Skip to content

Commit a0879c4

Browse files
committed
fix(dropdown): keyboard interactions and DAP issues
1 parent 1435f2c commit a0879c4

File tree

5 files changed

+36
-23
lines changed

5 files changed

+36
-23
lines changed

src/dropdown/dropdown.component.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,17 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
274274
* Adds keyboard functionality for navigation, selection and closing of the `Dropdown`.
275275
*/
276276
@HostListener("keydown", ["$event"])
277+
// "Esc", "Spacebar", "Down", and "up" are IE specific values
277278
onKeyDown(event: KeyboardEvent) {
278-
if (event.key === "Escape" && !this.menuIsClosed) {
279+
if (event.key === "Escape" || event.key === "Esc" && !this.menuIsClosed) {
279280
event.stopImmediatePropagation(); // don't unintentionally close other widgets that listen for Escape
280281
}
281-
if (event.key === "Escape" || (event.key === "ArrowUp" && event.altKey)) {
282+
if (event.key === "Escape" || event.key === "Esc") {
282283
event.preventDefault();
283284
this.closeMenu();
284285
this.dropdownButton.nativeElement.focus();
285-
} else if (event.key === "ArrowDown" && event.altKey) {
286+
} else if (this.menuIsClosed && event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp" ||
287+
event.key === "Spacebar" || event.key === "Down" || event.key === "Up") {
286288
event.preventDefault();
287289
this.openMenu();
288290
}
@@ -303,12 +305,13 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
303305
}
304306

305307
closedDropdownNavigation(event) {
306-
if (event.key === "ArrowDown") {
308+
// "Down", and "Up" are IE specific values
309+
if (event.key === "ArrowDown" || event.key === "Down") {
307310
event.preventDefault();
308311
this.view.getCurrentItem().selected = false;
309312
let item = this.view.getNextItem();
310313
if (item) { item.selected = true; }
311-
} else if (event.key === "ArrowUp") {
314+
} else if (event.key === "ArrowUp" || event.key === "Up") {
312315
event.preventDefault();
313316
this.view.getCurrentItem().selected = false;
314317
let item = this.view.getPrevItem();
@@ -362,10 +365,11 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
362365
* Handles keyboard events so users are controlling the `Dropdown` instead of unintentionally controlling outside elements.
363366
*/
364367
_keyboardNav(event: KeyboardEvent) {
365-
if (event.key === "Escape" && !this.menuIsClosed) {
368+
// "Esc" is an IE specific value
369+
if (event.key === "Escape" || event.key === "Esc" && !this.menuIsClosed) {
366370
event.stopImmediatePropagation(); // don't unintentionally close modal if inside of it
367371
}
368-
if (event.key === "Escape" || (event.key === "ArrowUp" && event.altKey)) {
372+
if (event.key === "Escape" || event.key === "Esc") {
369373
event.preventDefault();
370374
this.closeMenu();
371375
this.dropdownButton.nativeElement.focus();
@@ -456,7 +460,7 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
456460
document.body.firstElementChild.addEventListener("keydown", this.noop, true);
457461
document.addEventListener("click", this.outsideClick, true);
458462
document.addEventListener("keydown", this.outsideKey, true);
459-
// setTimeout(() => this.view.initFocus(), 0);
463+
setTimeout(() => this.view.initFocus(), 0);
460464
}
461465

462466
/**

src/dropdown/list/dropdown-list.component.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { StaticIconModule } from "./../../icon/static-icon.module";
66
import { DropdownList } from "./dropdown-list.component";
77
import { ListItem } from "./../list-item.interface";
88
import { ScrollableList } from "./../scrollable-list.directive";
9+
import { I18nModule } from "../../i18n/i18n.module";
910

1011
@Component({
1112
template: `<ibm-dropdown-list [items]="items" (select)="onSelect($event)"></ibm-dropdown-list>`
@@ -39,7 +40,7 @@ describe("Dropdown list", () => {
3940
ScrollableList
4041
],
4142
imports: [
42-
StaticIconModule
43+
StaticIconModule, I18nModule
4344
]
4445
});
4546
});
@@ -72,7 +73,7 @@ describe("Dropdown multi list", () => {
7273
ScrollableList
7374
],
7475
imports: [
75-
StaticIconModule
76+
StaticIconModule, I18nModule
7677
]
7778
});
7879
});

src/dropdown/list/dropdown-list.component.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ElementRef
1313
} from "@angular/core";
1414

15+
import { I18n } from "../../i18n/i18n.module";
1516
import { AbstractDropdownView } from "./../abstract-dropdown-view.class";
1617
import { ListItem } from "./../list-item.interface";
1718
import { watchFocusJump } from "./../dropdowntools";
@@ -49,12 +50,15 @@ import { ScrollableList } from "./../scrollable-list.directive";
4950
<ul
5051
#list
5152
role="listbox"
52-
class="bx--list-box__menu">
53-
<li tabindex="{{item.disabled? -1 : 0}}"
53+
class="bx--list-box__menu"
54+
[attr.aria-label]="dropdownListLabel">
55+
<li tabindex="-1"
5456
role="option"
55-
*ngFor="let item of displayItems"
57+
*ngFor="let item of displayItems; let i = index"
5658
(click)="doClick($event, item)"
5759
(keydown)="doKeyDown($event, item)"
60+
(focus)="listElementList[i].classList.add('bx--list-box__menu-item--highlighted'); listElementList[i].tabIndex = 0"
61+
(blur)="listElementList[i].classList.remove('bx--list-box__menu-item--highlighted'); listElementList[i].tabIndex = -1"
5862
class="bx--list-box__menu-item"
5963
[ngClass]="{
6064
selected: item.selected,
@@ -88,6 +92,7 @@ import { ScrollableList } from "./../scrollable-list.directive";
8892
]
8993
}) // conceptually this extends list-group, but we dont have to
9094
export class DropdownList implements AbstractDropdownView, AfterViewInit, OnChanges, OnDestroy {
95+
@Input() dropdownListLabel = this.i18n.get().DROPDOWN_LIST.LABEL;
9196
/**
9297
* The list items belonging to the `DropdownList`.
9398
*/
@@ -139,7 +144,7 @@ export class DropdownList implements AbstractDropdownView, AfterViewInit, OnChan
139144
/**
140145
* Creates an instance of `DropdownList`.
141146
*/
142-
constructor(public elementRef: ElementRef) {}
147+
constructor(public elementRef: ElementRef, protected i18n: I18n) {}
143148

144149
/**
145150
* Updates list when changes occur within the items belonging to the `DropdownList`.
@@ -353,24 +358,24 @@ export class DropdownList implements AbstractDropdownView, AfterViewInit, OnChan
353358
* Manages the keyboard accessiblity for navigation and selection within a `DropdownList`.
354359
*/
355360
doKeyDown(event: KeyboardEvent, item: ListItem) {
356-
if (event.key && (event.key === "Enter" || event.key === " ")) {
361+
// "Spacebar", "Down", and "Up" are IE specific values
362+
if (event.key && event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
357363
event.preventDefault();
358-
this.doClick(event, item);
359-
} else if (event.key === "ArrowDown" || event.key === "ArrowUp") {
364+
if (event.key === "Enter") {
365+
this.doClick(event, item);
366+
}
367+
} else if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Down" || event.key === "Up") {
360368
event.preventDefault();
361369
// this.checkScrollArrows();
362-
if (event.key === "ArrowDown" && this.hasNextElement()) {
370+
if (event.key === "ArrowDown" || event.key === "Down" && this.hasNextElement()) {
363371
this.getNextElement().focus();
364-
} else if (event.key === "ArrowUp") {
372+
} else if (event.key === "ArrowUp" || event.key === "Up") {
365373
if (this.hasPrevElement()) {
366374
this.getPrevElement().focus();
367375
} else if (this.getSelected()) {
368376
this.clearSelected.nativeElement.focus();
369377
}
370378
}
371-
if (event.shiftKey) {
372-
(event.target as HTMLElement).click();
373-
}
374379
}
375380
}
376381

src/i18n/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"RESET_SEARCH": "Reset search"
7272
}
7373
},
74+
"DROPDOWN_LIST": {
75+
"LABEL": "Listbox"
76+
},
7477
"LOADING": {
7578
"TITLE": "Loading"
7679
},

src/modal/modal-placeholder.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class ModalPlaceholder implements OnInit {
5454
* Initializes the component using `ModalService`.
5555
*/
5656
ngOnInit() {
57-
console.warn("`ibm-modal-placeholder` has been deprecated in favour of `ibm-placeholder`");
57+
console.warn("`ibm-dialog-placeholder` has been deprecated in favour of `ibm-placeholder`");
5858
this.placeholderService.registerViewContainerRef(this.viewContainerRef);
5959
}
6060
}

0 commit comments

Comments
 (0)