license import { MDCFoundation } from '@material/base/foundation' ; import { cssClasses as listCssClasses } from '@material/list/constants' ; import { MDCMenuSurfaceFoundation } from '@material/menu-surface/foundation' ; import { MDCMenuAdapter } from './adapter' ; import { cssClasses , DefaultFocusState , numbers , strings } from './constants' ; export class MDCMenuFoundation extends MDCFoundation < MDCMenuAdapter > { static override get cssClasses ( ) { return cssClasses ; } static override get strings ( ) { return strings ; } static override get numbers ( ) { return numbers ; } private closeAnimationEndTimerId = 0 ; private defaultFocusState = DefaultFocusState . LIST_ROOT ; private selectedIndex = - 1 ; see MDCMenuAdapter for typing information on parameters and return types.
      static override get defaultAdapter ( ) : MDCMenuAdapter { return { addClassToElementAtIndex : ( ) => undefined , removeClassFromElementAtIndex : ( ) => undefined , addAttributeToElementAtIndex : ( ) => undefined , removeAttributeFromElementAtIndex : ( ) => undefined , getAttributeFromElementAtIndex : ( ) => null , elementContainsClass : ( ) => false , closeSurface : ( ) => undefined , getElementIndex : ( ) => - 1 , notifySelected : ( ) => undefined , getMenuItemCount : ( ) => 0 , focusItemAtIndex : ( ) => undefined , focusListRoot : ( ) => undefined , getSelectedSiblingOfItemAtIndex : ( ) => - 1 , isSelectableItemAtIndex : ( ) => false , } ; } constructor ( adapter ? ) { super ( { ... MDCMenuFoundation . defaultAdapter , ... adapter } ) ; } override destroy ( ) { if ( this . closeAnimationEndTimerId ) { clearTimeout ( this . closeAnimationEndTimerId ) ; } this . adapter . closeSurface ( ) ; } handleKeydown ( evt ) { const { key , keyCode } = evt ; const isTab = key === 'Tab' || keyCode === 9 ; if ( isTab ) { this . adapter . closeSurface ( true ) ; } } handleItemAction ( listItem ) { const index = this . adapter . getElementIndex ( listItem ) ; if ( index < 0 ) { return ; } this . adapter . notifySelected ( { index } ) ; const skipRestoreFocus = this . adapter . getAttributeFromElementAtIndex ( index , strings . SKIP_RESTORE_FOCUS ) === 'true' ; this . adapter . closeSurface ( skipRestoreFocus ) ; this . closeAnimationEndTimerId = setTimeout ( ( ) => { const recomputedIndex = this . adapter . getElementIndex ( listItem ) ; if ( recomputedIndex >= 0 && this . adapter . isSelectableItemAtIndex ( recomputedIndex ) ) { this . setSelectedIndex ( recomputedIndex ) ; } } , MDCMenuSurfaceFoundation . numbers . TRANSITION_CLOSE_DURATION ) ; } handleMenuSurfaceOpened ( ) { switch ( this . defaultFocusState ) { case DefaultFocusState . FIRST_ITEM : this . adapter . focusItemAtIndex ( 0 ) ; break ; case DefaultFocusState . LAST_ITEM : this . adapter . focusItemAtIndex ( this . adapter . getMenuItemCount ( ) - 1 ) ; break ; case DefaultFocusState . NONE : break ; default : this . adapter . focusListRoot ( ) ; break ; } } /**
     * Sets default focus state where the menu should focus every time when menu
     * is opened. Focuses the list root (`DefaultFocusState.LIST_ROOT`) element by
     * default.
     */ setDefaultFocusState ( focusState ) { this . defaultFocusState = focusState ; } return getSelectedIndex ( ) { return this . selectedIndex ; } param index setSelectedIndex ( index ) { this . validatedIndex ( index ) ; if ( ! this . adapter . isSelectableItemAtIndex ( index ) ) { throw new Error ( 'MDCMenuFoundation: No selection group at specified index.' ) ; } const prevSelectedIndex = this . adapter . getSelectedSiblingOfItemAtIndex ( index ) ; if ( prevSelectedIndex >= 0 ) { this . adapter . removeAttributeFromElementAtIndex ( prevSelectedIndex , strings . ARIA_CHECKED_ATTR ) ; this . adapter . removeClassFromElementAtIndex ( prevSelectedIndex , cssClasses . MENU_SELECTED_LIST_ITEM ) ; } this . adapter . addClassToElementAtIndex ( index , cssClasses . MENU_SELECTED_LIST_ITEM ) ; this . adapter . addAttributeToElementAtIndex ( index , strings . ARIA_CHECKED_ATTR , 'true' ) ; this . selectedIndex = index ; } param index param isEnabled setEnabled ( index , isEnabled ) { this . validatedIndex ( index ) ; if ( isEnabled ) { this . adapter . removeClassFromElementAtIndex ( index , listCssClasses . LIST_ITEM_DISABLED_CLASS ) ; this . adapter . addAttributeToElementAtIndex ( index , strings . ARIA_DISABLED_ATTR , 'false' ) ; } else { this . adapter . addClassToElementAtIndex ( index , listCssClasses . LIST_ITEM_DISABLED_CLASS ) ; this . adapter . addAttributeToElementAtIndex ( index , strings . ARIA_DISABLED_ATTR , 'true' ) ; } } private validatedIndex ( index ) { const menuSize = this . adapter . getMenuItemCount ( ) ; const isIndexInRange = index >= 0 && index < menuSize ; if ( ! isIndexInRange ) { throw new Error ( 'MDCMenuFoundation: No list item at specified index.' ) ; } } } export default MDCMenuFoundation ;