import React from 'react' ; import classnames from 'classnames' ; import { closest } from '@material/dom/ponyfill' ; import { withRipple , InjectedProps , RippledComponentProps , } from '@material/react-ripple' ; import { MDCListFoundation } from '@material/list/foundation' ; import { ListItemContext , ListItemContextShape } from './index' ; export interface ListItemProps < T extends HTMLElement = HTMLElement > extends React . HTMLProps < T > , ListItemContextShape , InjectedProps < T > { checkboxList ? : boolean ; radioList ? : boolean ; tag ? : string ; activated ? : boolean ; selected ? : boolean ; ref ? : React . Ref < any > ; initRipple ? : ( surface : T ) => void ; } export interface ListItemState { tabIndex ? : number ; } export class ListItemBase < T extends HTMLElement = HTMLElement > extends React . Component < ListItemProps < T > , ListItemState > { private listItemElement = React . createRef < T > ( ) ; static defaultProps : Partial < ListItemProps < HTMLElement > > = { checkboxList : false , radioList : false , className : '' , tabIndex : - 1 , onKeyDown : ( ) => { } , onClick : ( ) => { } , onFocus : ( ) => { } , onBlur : ( ) => { } , onDestroy : ( ) => { } , tag : 'li' , handleClick : ( ) => { } , handleKeyDown : ( ) => { } , handleBlur : ( ) => { } , handleFocus : ( ) => { } , getListItemInitialTabIndex : ( ) => - 1 , getClassNamesFromList : ( ) => ( { } ) , } ; state = { tabIndex : this . props . tabIndex , } ; get listElements ( ) : Element [ ] { if ( this . listItemElement . current ) { const listElement = closest ( this . listItemElement . current , `.${ MDCListFoundation . cssClasses . ROOT }` ) ; if ( ! listElement ) return [ ] ; return [ ] . slice . call ( listElement . querySelectorAll ( MDCListFoundation . strings . ENABLED_ITEMS_SELECTOR ) ) ; } return [ ] ; } componentDidMount ( ) { this . initializeTabIndex ( ) ; if ( this . props . initRipple ) { this . props . initRipple ( this . listItemElement . current as T ) ; } } componentDidUpdate ( prevProps ) { if ( prevProps . tabIndex !== this . props . tabIndex ) { this . setState ( { tabIndex : this . props . tabIndex } ) ; } } componentWillUnmount ( ) { if ( this . listItemElement . current ) { const index = this . getIndex ( this . listItemElement . current ) ; this . props . onDestroy ! ( index ) ; } } get classes ( ) { const { className , activated , disabled , selected , getClassNamesFromList , } = this . props ; let classesFromList = [ '' ] ; if ( this . listItemElement . current ) { const index = this . getIndex ( this . listItemElement . current ) ; classesFromList = getClassNamesFromList ! ( ) [ index ] ; } return classnames ( 'mdc-list-item' , className , classesFromList , { [ MDCListFoundation . cssClasses . LIST_ITEM_ACTIVATED_CLASS ] : activated , [ MDCListFoundation . cssClasses . LIST_ITEM_SELECTED_CLASS ] : selected , 'mdc-list-item--disabled' : disabled , } ) ; } get role ( ) { const { checkboxList , radioList , role } = this . props ; if ( role ) { return role ; } else if ( checkboxList ) { return 'checkbox' ; } else if ( radioList ) { return 'radio' ; } return null ; } private initializeTabIndex = ( ) => { if ( this . listItemElement . current ) { const index = this . getIndex ( this . listItemElement . current ) ; const tabIndex = this . props . getListItemInitialTabIndex ! ( index ) ; this . setState ( { tabIndex } ) ; } } ; getIndex = ( listElement ) => { return this . listElements . indexOf ( listElement ) ; } ; handleClick = ( e ) => { const { onClick } = this . props ; onClick ! ( e ) ; this . props . handleClick ! ( e , this . getIndex ( e . currentTarget ) ) ; } ; handleKeyDown = ( e ) => { const { onKeyDown } = this . props ; onKeyDown ! ( e ) ; this . props . handleKeyDown ! ( e , this . getIndex ( e . currentTarget ) ) ; } ; handleFocus = ( e ) => { const { onFocus } = this . props ; onFocus ! ( e ) ; this . props . handleFocus ! ( e , this . getIndex ( e . currentTarget ) ) ; } ; handleBlur = ( e ) => { const { onBlur } = this . props ; onBlur ! ( e ) ; this . props . handleBlur ! ( e , this . getIndex ( e . currentTarget ) ) ; } ; render ( ) { const { className , children , role , initRipple , checkboxList , radioList , selected , activated , onDestroy , onClick , onKeyDown , onFocus , onBlur , handleClick , handleKeyDown , handleFocus , handleBlur , getListItemInitialTabIndex , getClassNamesFromList , tabIndex , tag : Tag , ... otherProps } = this . props ; return ( < Tag { ... otherProps } { ... this . context } role = { this . role } className = { this . classes } ref = { this . listItemElement } onClick = { this . handleClick } onKeyDown = { this . handleKeyDown } onFocus = { this . handleFocus } onBlur = { this . handleBlur } tabIndex = { this . state . tabIndex } > { children } < /Tag>); } } const ListItem = ( props ) => { return ( < ListItemContext . Consumer > { ( context ) => < ListItemBase { ... context } { ... props } />} < /ListItemContext.Consumer>); } ; export default withRipple < ListItemProps , HTMLElement > ( ListItem ) ;