1- import { CSSResult , html , nothing , TemplateResult } from 'lit' ;
1+ import { CSSResult , html , nothing , PropertyValues , TemplateResult } from 'lit' ;
22import { property } from 'lit/decorators.js' ;
33
44import icons from './assets/img/icons' ;
@@ -9,6 +9,7 @@ import { IATopNavConfig, IATopNavLink } from './models';
99import dropdownMenuCSS from './styles/dropdown-menu' ;
1010import TrackedElement from './tracked-element' ;
1111import { ifDefined } from 'lit/directives/if-defined.js' ;
12+ import KeyboardNavigation from './lib/keyboard-navigation' ;
1213
1314export default class DropdownMenu extends TrackedElement {
1415 @property ( { type : String } ) baseHost = '' ;
@@ -18,10 +19,33 @@ export default class DropdownMenu extends TrackedElement {
1819 @property ( { type : Boolean } ) animated = false ;
1920 @property ( { type : Boolean } ) open = false ;
2021
22+ private previousKeydownListener ?: // eslint-disable-next-line @typescript-eslint/no-explicit-any
23+ ( this : HTMLElement , ev : KeyboardEvent ) => any ;
24+
2125 static get styles ( ) : CSSResult [ ] {
2226 return [ dropdownMenuCSS ] ;
2327 }
2428
29+ updated ( props : PropertyValues ) {
30+ if ( props . has ( 'open' ) && this . open ) {
31+ const container = this . shadowRoot ?. querySelector (
32+ '.nav-container' ,
33+ ) as HTMLElement ;
34+
35+ if ( container ) {
36+ const keyboardNavigation = new KeyboardNavigation (
37+ container ,
38+ 'usermenu' ,
39+ ) ;
40+ this . addEventListener ( 'keydown' , keyboardNavigation . handleKeyDown ) ;
41+ if ( this . previousKeydownListener ) {
42+ this . removeEventListener ( 'keydown' , this . previousKeydownListener ) ;
43+ }
44+ this . previousKeydownListener = keyboardNavigation . handleKeyDown ;
45+ }
46+ }
47+ }
48+
2549 get dropdownItems ( ) {
2650 if ( ! this . menuItems ) return nothing ;
2751
@@ -56,17 +80,19 @@ export default class DropdownMenu extends TrackedElement {
5680
5781 dropdownLink ( link : IATopNavLink ) : TemplateResult {
5882 const calloutText = this . config ?. callouts ?. [ link . title ] ;
83+ const isMobileUpload = link . class === 'mobile-upload' ;
84+ const isTabbable = this . open && ! isMobileUpload ;
85+
5986 return html `< a
6087 href ="${ formatUrl ( link . url , this . baseHost ) } "
6188 class =${ ifDefined ( link . class ) }
62- tabindex ="${ this . open ? '' : '-1' } "
89+ tabindex ="${ isTabbable ? '' : '-1' } "
6390 @click=${ this . trackClick }
6491 data-event-click-tracking="${ this . config
6592 ?. eventCategory } |Nav${ link . analyticsEvent } "
6693 aria-label=${ calloutText ? `New feature: ${ link . title } ` : nothing }
6794 >
68- ${ link . class === 'mobile-upload' ? icons . uploadUnpadded : nothing }
69- ${ link . title }
95+ ${ isMobileUpload ? icons . uploadUnpadded : nothing } ${ link . title }
7096 ${ calloutText
7197 ? html `< span class ="callout " aria-hidden ="true "> ${ calloutText } </ span > `
7298 : nothing }
0 commit comments