1- import { Component } from "@angular/core" ;
1+ import { Component , ViewChild , HostListener } from "@angular/core" ;
22import { Dialog } from "../dialog.component" ;
33import { position } from "../../utils/position" ;
4+ import { isFocusInLastItem , isFocusInFirstItem } from "./../../common/tab.service" ;
45
56/**
67 * Extend the `Dialog` component to create an overflow menu.
@@ -11,9 +12,10 @@ import { position } from "../../utils/position";
1112 selector : "ibm-overflow-menu-pane" ,
1213 template : `
1314 <ul
15+ role="menu"
16+ attr.aria-label="{{'OVERFLOW_MENU.OVERFLOW' | translate}}"
1417 #dialog
15- class="bx--overflow-menu-options bx--overflow-menu-options--open"
16- tabindex="-1">
18+ class="bx--overflow-menu-options bx--overflow-menu-options--open">
1719 <ng-template
1820 [ngTemplateOutlet]="dialogConfig.content"
1921 [ngTemplateOutletContext]="{overflowMenu: this}">
@@ -22,6 +24,8 @@ import { position } from "../../utils/position";
2224 `
2325} )
2426export class OverflowMenuPane extends Dialog {
27+ @ViewChild ( "dialog" ) dialog ;
28+
2529 onDialogInit ( ) {
2630 /**
2731 * -20 shifts the menu up to compensate for the
@@ -32,5 +36,53 @@ export class OverflowMenuPane extends Dialog {
3236 * so we need to add some compensation)
3337 */
3438 this . addGap [ "bottom" ] = pos => position . addOffset ( pos , - 20 , 60 ) ;
39+
40+ setTimeout ( ( ) => this . listItems ( ) [ 0 ] . focus ( ) ) ;
41+ }
42+
43+ @HostListener ( "keydown" , [ "$event" ] )
44+ hostkeys ( event : KeyboardEvent ) {
45+ this . escapeClose ( event ) ;
46+ const listItems = this . listItems ( ) ;
47+
48+ switch ( event . key ) {
49+ case "Down" : // IE specific value
50+ case "ArrowDown" :
51+ event . preventDefault ( ) ;
52+ if ( ! isFocusInLastItem ( event , listItems ) ) {
53+ const index = listItems . findIndex ( item => item === event . target ) ;
54+ listItems [ index + 1 ] . focus ( ) ;
55+ } else {
56+ listItems [ 0 ] . focus ( ) ;
57+ }
58+ break ;
59+
60+ case "Up" : // IE specific value
61+ case "ArrowUp" :
62+ event . preventDefault ( ) ;
63+ if ( ! isFocusInFirstItem ( event , listItems ) ) {
64+ const index = listItems . findIndex ( item => item === event . target ) ;
65+ listItems [ index - 1 ] . focus ( ) ;
66+ } else {
67+ listItems [ listItems . length - 1 ] . focus ( ) ;
68+ }
69+ break ;
70+
71+ case "Home" :
72+ event . preventDefault ( ) ;
73+ listItems [ 0 ] . focus ( ) ;
74+ break ;
75+
76+ case "End" :
77+ event . preventDefault ( ) ;
78+ listItems [ listItems . length - 1 ] . focus ( ) ;
79+ break ;
80+ }
81+ }
82+
83+ private listItems ( ) {
84+ const buttonClass = ".bx--overflow-menu-options__btn" ;
85+ const disabledClass = ".bx--overflow-menu-options__option--disabled" ;
86+ return Array . from < any > ( this . dialog . nativeElement . querySelectorAll ( `${ buttonClass } :not(${ disabledClass } )` ) ) ;
3587 }
3688}
0 commit comments