2323import React from 'react' ;
2424import classnames from 'classnames' ;
2525import { MDCListFoundation } from '@material/list/foundation' ;
26+ import { ListItemContext , ListItemContextShape } from './index' ;
27+ import { closest } from '@material/dom/ponyfill' ;
2628
27- export interface ListItemProps < T > extends React . HTMLProps < T > {
29+ export interface ListItemProps < T extends HTMLElement = HTMLElement > extends React . HTMLProps < T > , ListItemContextShape {
2830 checkboxList ?: boolean ;
2931 radioList ?: boolean ;
30- onKeyDown ?: React . KeyboardEventHandler < T > ;
31- onClick ?: React . MouseEventHandler < T > ;
32- onFocus ?: React . FocusEventHandler < T > ;
33- onBlur ?: React . FocusEventHandler < T > ;
3432 tag ?: string ;
3533 activated ?: boolean ;
3634 selected ?: boolean ;
37- onDestroy ?: ( ) => void ;
35+ ref ?: React . Ref < any > ;
36+ } ;
37+
38+ export interface ListItemState {
39+ tabIndex ?: number ;
3840}
3941
40- export default class ListItem < T extends HTMLElement = HTMLElement > extends React . Component <
41- ListItemProps < T > ,
42- { }
43- > {
42+ export class ListItemBase < T extends HTMLElement = HTMLElement > extends React . Component <
43+ ListItemProps < T > , ListItemState > {
4444 private listItemElement = React . createRef < T > ( ) ;
4545
4646 static defaultProps : Partial < ListItemProps < HTMLElement > > = {
@@ -54,15 +54,54 @@ export default class ListItem<T extends HTMLElement = HTMLElement> extends React
5454 onBlur : ( ) => { } ,
5555 onDestroy : ( ) => { } ,
5656 tag : 'li' ,
57+ handleClick : ( ) => { } ,
58+ handleKeyDown : ( ) => { } ,
59+ handleBlur : ( ) => { } ,
60+ handleFocus : ( ) => { } ,
61+ getListItemInitialTabIndex : ( ) => - 1 ,
62+ getClassNamesFromList : ( ) => ( { } ) ,
63+ } ;
64+
65+ state = {
66+ tabIndex : this . props . tabIndex ,
5767 } ;
5868
69+ get listElements ( ) : Element [ ] {
70+ if ( this . listItemElement . current ) {
71+ const listElement = closest ( this . listItemElement . current , `.${ MDCListFoundation . cssClasses . ROOT } ` ) ;
72+ if ( ! listElement ) return [ ] ;
73+ return [ ] . slice . call (
74+ listElement . querySelectorAll ( MDCListFoundation . strings . ENABLED_ITEMS_SELECTOR )
75+ ) ;
76+ }
77+ return [ ] ;
78+ }
79+
80+ componentDidMount ( ) {
81+ this . initializeTabIndex ( ) ;
82+ }
83+
84+ componentDidUpdate ( prevProps : ListItemProps ) {
85+ if ( prevProps . tabIndex !== this . props . tabIndex ) {
86+ this . setState ( { tabIndex : this . props . tabIndex } ) ;
87+ }
88+ }
89+
5990 componentWillUnmount ( ) {
60- this . props . onDestroy ! ( ) ;
91+ if ( this . listItemElement . current ) {
92+ const index = this . getIndex ( this . listItemElement . current ) ;
93+ this . props . onDestroy ! ( index ) ;
94+ }
6195 }
6296
6397 get classes ( ) {
64- const { className, activated, disabled, selected} = this . props ;
65- return classnames ( 'mdc-list-item' , className , {
98+ const { className, activated, disabled, selected, getClassNamesFromList} = this . props ;
99+ let classesFromList = [ '' ] ;
100+ if ( this . listItemElement . current ) {
101+ const index = this . getIndex ( this . listItemElement . current ) ;
102+ classesFromList = getClassNamesFromList ! ( ) [ index ] ;
103+ }
104+ return classnames ( 'mdc-list-item' , className , classesFromList , {
66105 [ MDCListFoundation . cssClasses . LIST_ITEM_ACTIVATED_CLASS ] : activated ,
67106 [ MDCListFoundation . cssClasses . LIST_ITEM_SELECTED_CLASS ] : selected ,
68107 'mdc-list-item--disabled' : disabled ,
@@ -81,6 +120,42 @@ export default class ListItem<T extends HTMLElement = HTMLElement> extends React
81120 return null ;
82121 }
83122
123+ private initializeTabIndex = ( ) => {
124+ if ( this . listItemElement . current ) {
125+ const index = this . getIndex ( this . listItemElement . current ) ;
126+ const tabIndex = this . props . getListItemInitialTabIndex ! ( index ) ;
127+ this . setState ( { tabIndex} ) ;
128+ }
129+ }
130+
131+ getIndex = ( listElement : Element ) => {
132+ return this . listElements . indexOf ( listElement ) ;
133+ }
134+
135+ handleClick = ( e : React . MouseEvent < any > ) => {
136+ const { onClick} = this . props ;
137+ onClick ! ( e ) ;
138+ this . props . handleClick ! ( e , this . getIndex ( e . currentTarget ) ) ;
139+ }
140+
141+ handleKeyDown = ( e : React . KeyboardEvent < any > ) => {
142+ const { onKeyDown} = this . props ;
143+ onKeyDown ! ( e ) ;
144+ this . props . handleKeyDown ! ( e , this . getIndex ( e . currentTarget ) ) ;
145+ }
146+
147+ handleFocus = ( e : React . FocusEvent < any > ) => {
148+ const { onFocus} = this . props ;
149+ onFocus ! ( e ) ;
150+ this . props . handleFocus ! ( e , this . getIndex ( e . currentTarget ) ) ;
151+ }
152+
153+ handleBlur = ( e : React . FocusEvent < any > ) => {
154+ const { onBlur} = this . props ;
155+ onBlur ! ( e ) ;
156+ this . props . handleBlur ! ( e , this . getIndex ( e . currentTarget ) ) ;
157+ }
158+
84159 render ( ) {
85160 const {
86161 /* eslint-disable no-unused-vars */
@@ -90,21 +165,51 @@ export default class ListItem<T extends HTMLElement = HTMLElement> extends React
90165 checkboxList,
91166 radioList,
92167 onDestroy,
168+ onClick,
169+ onKeyDown,
170+ onFocus,
171+ onBlur,
172+ handleClick,
173+ handleKeyDown,
174+ handleFocus,
175+ handleBlur,
176+ getListItemInitialTabIndex,
177+ getClassNamesFromList,
178+ tabIndex,
93179 /* eslint-enable no-unused-vars */
94180 tag : Tag ,
95181 ...otherProps
96182 } = this . props ;
183+
97184 return (
98185 // https://github.com/Microsoft/TypeScript/issues/28892
99186 // @ts -ignore
100187 < Tag
188+ { ...otherProps }
189+ { ...this . context }
101190 role = { this . role }
102191 className = { this . classes }
103192 ref = { this . listItemElement }
104- { ...otherProps }
193+ onClick = { this . handleClick }
194+ onKeyDown = { this . handleKeyDown }
195+ onFocus = { this . handleFocus }
196+ onBlur = { this . handleBlur }
197+ tabIndex = { this . state . tabIndex }
105198 >
106- { this . props . children }
199+ { children }
107200 </ Tag >
108201 ) ;
109202 }
110203}
204+
205+ const ListItem : React . FunctionComponent < ListItemProps > = ( props ) => {
206+ return (
207+ < ListItemContext . Consumer >
208+ { ( context ) => (
209+ < ListItemBase { ...context } { ...props } />
210+ ) }
211+ </ ListItemContext . Consumer >
212+ ) ;
213+ } ;
214+
215+ export default ListItem ;
0 commit comments