packageDocumentation module import { isArrowKey , SpecialKey } from "@itwin/appui-abstract" ; import { Orientation } from "../enums/Orientation" ; internal export type CrossAxisArrowKeyFunc = ( forward : boolean ) => void ; internal export class ItemKeyboardNavigator { private _direction : Map < string , number > ; private _itemCount = 0 ; private _orientation = Orientation . Horizontal ; private _allowWrap = true ; private _crossAxisArrowKeyHandler ? : CrossAxisArrowKeyFunc ; constructor ( public onFocusItem , public onActivateItem ) { this . _direction = new Map < string , number > ( [ [ SpecialKey . ArrowLeft , - 1 ] , [ SpecialKey . ArrowUp , - 1 ] , [ SpecialKey . ArrowRight , 1 ] , [ SpecialKey . ArrowDown , 1 ] , ] ) ; } /** The item count */ public get itemCount ( ) : number { return this . _itemCount ; } public set itemCount ( count ) { this . _itemCount = count ; } /** The primary orientation */ public get orientation ( ) : Orientation { return this . _orientation ; } public set orientation ( orientation ) { this . _orientation = orientation ; } /** The allow wrap property controls whether the movement will stop at the first and last items or wrap  */ public get allowWrap ( ) : boolean { return this . _allowWrap ; } public set allowWrap ( v ) { this . _allowWrap = v ; } /** Called when the arrow keys that run perpendicular to the primary orientation are pressed */ public get crossAxisArrowKeyHandler ( ) : CrossAxisArrowKeyFunc | undefined { return this . _crossAxisArrowKeyHandler ; } public set crossAxisArrowKeyHandler ( v ) { this . _crossAxisArrowKeyHandler = v ; } /** Handle KeyDown on items */ public handleKeyDownEvent ( event , index ) { const key = event . key ; switch ( key ) { case SpecialKey . Home : event . preventDefault ( ) ; this . focusFirstItem ( ) ; break ; case SpecialKey . End : event . preventDefault ( ) ; this . focusLastItem ( ) ; break ; case SpecialKey . ArrowUp : case SpecialKey . ArrowDown : this . determineOrientation ( event , index ) ; break ; case SpecialKey . Enter : case SpecialKey . Space : this . activateItem ( index ) ; break ; } } /** Handle KeyUp on items */ public handleKeyUpEvent ( event , index ) { const key = event . key ; switch ( key ) { case SpecialKey . ArrowLeft : case SpecialKey . ArrowRight : this . determineOrientation ( event , index ) ; break ; } } private focusFirstItem ( ) { this . onFocusItem ( 0 ) ; } private focusLastItem ( ) { const index = this . _itemCount - 1 ; this . onFocusItem ( index ) ; } /** When an item list's orientation is set to vertical,
     * only up and down arrow should function.
     * In all other cases only left and right arrow function.
     */ private determineOrientation ( event , index ) { const key = event . key ; const vertical = this . _orientation === Orientation . Vertical ; let proceed = false ; if ( vertical ) { if ( key === SpecialKey . ArrowUp || key === SpecialKey . ArrowDown ) { event . preventDefault ( ) ; proceed = true ; } else if ( this . crossAxisArrowKeyHandler && ( key === SpecialKey . ArrowLeft || key === SpecialKey . ArrowRight ) ) { this . crossAxisArrowKeyHandler ( key === SpecialKey . ArrowRight ) ; } } else { if ( key === SpecialKey . ArrowLeft || key === SpecialKey . ArrowRight ) { proceed = true ; } else if ( this . crossAxisArrowKeyHandler && ( key === SpecialKey . ArrowUp || key === SpecialKey . ArrowDown ) ) { this . crossAxisArrowKeyHandler ( key === SpecialKey . ArrowDown ) ; } } if ( proceed ) { this . switchItemOnArrowPress ( event , index ) ; } } /** Either focus the next, previous, first, or last item depending on key pressed
     */ private switchItemOnArrowPress ( event , index ) { const pressed = event . key ; const targetDirection = this . _direction . get ( pressed ) ; if ( targetDirection ) { const newIndex = index + targetDirection ; if ( 0 <= newIndex && newIndex < this . _itemCount ) { this . onFocusItem ( newIndex ) ; } else { if ( this . _allowWrap ) { if ( pressed === SpecialKey . ArrowLeft || pressed === SpecialKey . ArrowUp ) { this . focusLastItem ( ) ; } else { this . focusFirstItem ( ) ; } } } } } private activateItem ( index ) { this . onActivateItem ( index ) ; } } internal export function isNavigationKey ( key ) { return ( isArrowKey ( key ) || key === SpecialKey . Home || key === SpecialKey . End || key === SpecialKey . Space || key === SpecialKey . Enter ) ; }