import React , { useEffect , useCallback } from 'react' ; import { MDCListFoundation , MDCListAdapter } from '@material/list' ; import { matches , FoundationElement } from '@rmwc/base' ; import { useFoundation } from '@rmwc/base' ; import { ListProps , ListApi } from './list' ; export const useListFoundation = ( props ) => { const listElements = useCallback ( ( el ) : HTMLLIElement [ ] => { if ( el ) { return [ ] . slice . call ( el . querySelectorAll ( `.${ MDCListFoundation . cssClasses . LIST_ITEM_CLASS }` ) ) ; } return [ ] ; } , [ ] ) ; const { foundation , ... elements } = useFoundation ( { props , api : ( { rootEl , foundation } ) : ListApi => { const adapter = ( foundation as any ) . adapter_ as MDCListAdapter ; return { listElements : ( ) => listElements ( rootEl . ref ) , focusRoot : ( ) => rootEl . ref && rootEl . ref . focus ( ) , getClasses : ( ) => MDCListFoundation . cssClasses . LIST_ITEM_CLASS , addClassToElementIndex : adapter . addClassForElementIndex , removeClassFromElementAtIndex : adapter . removeClassForElementIndex , setAttributeForElementIndex : adapter . setAttributeForElementIndex , getListItemCount : adapter . getListItemCount , focusItemAtIndex : adapter . focusItemAtIndex } ; } , elements : { rootEl : true } , foundation : ( { rootEl , emit } ) => { return new MDCListFoundation ( { getListItemCount : ( ) => listElements ( rootEl . ref ) . length , getFocusedElementIndex : ( ) => listElements ( rootEl . ref ) . indexOf ( document . activeElement as HTMLLIElement ) , listItemAtIndexHasClass : ( index , className ) => { const element = listElements ( rootEl . ref ) [ index ] ; return ! ! element ?. classList . contains ( className ) ; } , setAttributeForElementIndex : ( index , attr , value ) => { if ( attr === 'tabindex' ) { attr = 'tabIndex' ; } const element = listElements ( rootEl . ref ) [ index ] ; if ( element ) { element . setAttribute ( attr , String ( value ) ) ; } } , addClassForElementIndex : ( index , className ) => { const element = listElements ( rootEl . ref ) [ index ] ; if ( element ) { element . classList . add ( className ) ; } } , removeClassForElementIndex : ( index , className ) => { const element = listElements ( rootEl . ref ) [ index ] ; if ( element ) { element . classList . remove ( className ) ; } } , focusItemAtIndex : ( index ) => { const element = listElements ( rootEl . ref ) [ index ] ; if ( element ) { element . focus ( ) ; } } , setTabIndexForListItemChildren : ( listItemIndex , tabIndexValue ) => { const element = listElements ( rootEl . ref ) [ listItemIndex ] ; const listItemChildren = [ ] . slice . call ( element . querySelectorAll ( MDCListFoundation . strings . CHILD_ELEMENTS_TO_TOGGLE_TABINDEX ) ) ; listItemChildren . forEach ( ( ele ) => ele . setAttribute ( 'tabindex' , String ( tabIndexValue ) ) ) ; } , hasCheckboxAtIndex : ( index ) => { const listItem = listElements ( rootEl . ref ) [ index ] ; return ! ! listItem . querySelector ( MDCListFoundation . strings . CHECKBOX_SELECTOR ) ; } , hasRadioAtIndex : ( index ) => { const listItem = listElements ( rootEl . ref ) [ index ] ; return ! ! listItem . querySelector ( MDCListFoundation . strings . RADIO_SELECTOR ) ; } , isCheckboxCheckedAtIndex : ( index ) => { const listItem = listElements ( rootEl . ref ) [ index ] ; const toggleEl = listItem . querySelector ( MDCListFoundation . strings . CHECKBOX_SELECTOR ) as HTMLInputElement | null ; return toggleEl ? toggleEl . checked : false ; } , setCheckedCheckboxOrRadioAtIndex : ( index , isChecked ) => { const listItem = listElements ( rootEl . ref ) [ index ] ; const toggleEl = listItem . querySelector ( MDCListFoundation . strings . CHECKBOX_RADIO_SELECTOR ) as HTMLInputElement | null ; if ( toggleEl ) { toggleEl . checked = isChecked ; const event = document . createEvent ( 'Event' ) ; event . initEvent ( 'change' , true , true ) ; toggleEl . dispatchEvent ( event ) ; } } , notifyAction : ( index ) => { emit ( 'onAction' , { index } ) ; } , isFocusInsideList : ( ) => { return ! ! rootEl . ref ?. contains ( document . activeElement ) ; } , isRootFocused : ( ) => document . activeElement === rootEl . ref } ) ; } } ) ; const { rootEl } = elements ; /**
     * Used to figure out which list item this event is targetting. Or returns -1 if
     * there is no list item
     */ const getListItemIndex = useCallback ( ( evt ) => { let eventTarget = evt . target as HTMLElement | null ; let index = - 1 ; while ( eventTarget && ! eventTarget . classList . contains ( MDCListFoundation . cssClasses . LIST_ITEM_CLASS ) && ! eventTarget . classList . contains ( MDCListFoundation . cssClasses . ROOT ) ) { eventTarget = eventTarget . parentElement as HTMLLIElement ; } if ( eventTarget && eventTarget . classList . contains ( MDCListFoundation . cssClasses . LIST_ITEM_CLASS ) ) { index = listElements ( rootEl . ref ) . indexOf ( eventTarget as HTMLLIElement ) ; } return index ; } , [ listElements , rootEl . ref ] ) ; const handleClick = useCallback ( ( evt ) => { props . onClick ?. ( evt ) ; const index = getListItemIndex ( evt ) ; const toggleCheckbox = ! matches ( evt . target as HTMLElement , MDCListFoundation . strings . CHECKBOX_RADIO_SELECTOR ) ; foundation . handleClick ( index , toggleCheckbox ) ; } , [ getListItemIndex , foundation , props . onClick ] ) ; const handleKeydown = useCallback ( ( evt ) => { props . onKeyDown ?. ( evt ) ; const index = getListItemIndex ( evt ) ; if ( index >= 0 ) { foundation . handleKeydown ( evt , evt . target instanceof Element && evt . target . classList . contains ( MDCListFoundation . cssClasses . LIST_ITEM_CLASS ) , index ) ; } } , [ getListItemIndex , foundation , props . onKeyDown ] ) ; const handleFocusIn = useCallback ( ( evt ) => { props . onFocus ?. ( evt ) ; foundation . handleFocusIn ( evt , getListItemIndex ( evt ) ) ; } , [ getListItemIndex , foundation , props . onFocus ] ) ; const handleFocusOut = useCallback ( ( evt ) => { props . onBlur ?. ( evt ) ; foundation . handleFocusOut ( evt , getListItemIndex ( evt ) ) ; } , [ getListItemIndex , foundation , props . onBlur ] ) ; rootEl . setProp ( 'onClick' , handleClick , true ) ; rootEl . setProp ( 'onKeyDown' , handleKeydown , true ) ; rootEl . setProp ( 'onFocus' , handleFocusIn , true ) ; rootEl . setProp ( 'onBlur' , handleFocusOut , true ) ; useEffect ( ( ) => { foundation . layout ( ) ; } , [ foundation ] ) ; useEffect ( ( ) => { foundation . setWrapFocus ( props . wrapFocus || props . wrapFocus === undefined ) ; } , [ foundation , props . wrapFocus ] ) ; useEffect ( ( ) => { foundation . setVerticalOrientation ( props . vertical || props . vertical === undefined ) ; } , [ foundation , props . vertical ] ) ; return { ... elements } ; } ;