|
22 | 22 |
|
23 | 23 | import * as React from 'react'; |
24 | 24 | import classnames from 'classnames'; |
| 25 | +import {MDCListFoundation} from '@material/list/foundation'; |
25 | 26 |
|
26 | 27 | export interface ListItemProps<T> extends React.HTMLProps<T> { |
27 | | - className?: string; |
28 | | - classNamesFromList?: string[]; |
29 | | - attributesFromList?: object; |
30 | | - childrenTabIndex?: number; |
31 | | - tabIndex?: number; |
32 | | - shouldFocus?: boolean; |
33 | | - shouldFollowHref?: boolean; |
34 | | - shouldToggleCheckbox?: boolean; |
| 28 | + checkboxList?: boolean; |
| 29 | + radioList?: boolean; |
| 30 | + onKeyDown?: React.KeyboardEventHandler<T>; |
| 31 | + onClick?: React.MouseEventHandler<T>; |
| 32 | + onFocus?: React.FocusEventHandler<T>; |
| 33 | + onBlur?: React.FocusEventHandler<T>; |
35 | 34 | tag?: string; |
36 | | - children?: React.ReactNode; |
| 35 | + activated?: boolean; |
| 36 | + selected?: boolean; |
37 | 37 | }; |
38 | 38 |
|
39 | | -function isAnchorElement(element: any): element is HTMLAnchorElement { |
40 | | - return !!element.href; |
41 | | -} |
42 | | - |
43 | | -function isFocusableElement(element: any): element is HTMLElement { |
44 | | - return typeof <HTMLElement>element.focus === 'function'; |
45 | | -} |
46 | | - |
47 | | -export default class ListItem<T extends {} = HTMLElement> extends React.Component< |
| 39 | +// TODO: convert to functional component |
| 40 | +// https://github.com/material-components/material-components-web-react/issues/729 |
| 41 | +export default class ListItem<T extends HTMLElement = HTMLElement> extends React.Component< |
48 | 42 | ListItemProps<T>, |
49 | 43 | {} |
50 | 44 | > { |
51 | | - listItemElement_: React.RefObject<T> = React.createRef(); |
| 45 | + private listItemElement = React.createRef<T>(); |
52 | 46 |
|
53 | 47 | static defaultProps: Partial<ListItemProps<HTMLElement>> = { |
| 48 | + checkboxList: false, |
| 49 | + radioList: false, |
54 | 50 | className: '', |
55 | | - classNamesFromList: [], |
56 | | - attributesFromList: {}, |
57 | | - childrenTabIndex: -1, |
58 | 51 | tabIndex: -1, |
59 | | - shouldFocus: false, |
60 | | - shouldFollowHref: false, |
61 | | - shouldToggleCheckbox: false, |
62 | 52 | onKeyDown: () => {}, |
63 | 53 | onClick: () => {}, |
64 | 54 | onFocus: () => {}, |
65 | 55 | onBlur: () => {}, |
66 | 56 | tag: 'li', |
67 | 57 | }; |
68 | 58 |
|
69 | | - componentDidUpdate(prevProps: ListItemProps<T>) { |
70 | | - const {shouldFocus, shouldFollowHref, shouldToggleCheckbox} = this.props; |
71 | | - if (shouldFocus && !prevProps.shouldFocus) { |
72 | | - this.focus(); |
73 | | - } |
74 | | - if (shouldFollowHref && !prevProps.shouldFollowHref) { |
75 | | - this.followHref(); |
76 | | - } |
77 | | - if (shouldToggleCheckbox && !prevProps.shouldToggleCheckbox) { |
78 | | - this.toggleCheckbox(); |
79 | | - } |
80 | | - } |
81 | | - |
82 | 59 | get classes() { |
83 | | - const {className, classNamesFromList} = this.props; |
84 | | - return classnames('mdc-list-item', className, classNamesFromList); |
| 60 | + const {className, activated, selected} = this.props; |
| 61 | + return classnames('mdc-list-item', className, { |
| 62 | + [MDCListFoundation.cssClasses.LIST_ITEM_ACTIVATED_CLASS]: activated, |
| 63 | + [MDCListFoundation.cssClasses.LIST_ITEM_SELECTED_CLASS]: selected, |
| 64 | + }); |
85 | 65 | } |
86 | 66 |
|
87 | | - focus() { |
88 | | - const element = this.listItemElement_.current; |
89 | | - if (isFocusableElement(element)) { |
90 | | - element.focus(); |
| 67 | + get role() { |
| 68 | + const {checkboxList, radioList, role} = this.props; |
| 69 | + if (role) { |
| 70 | + return role; |
| 71 | + } else if (checkboxList) { |
| 72 | + return 'checkbox'; |
| 73 | + } else if (radioList) { |
| 74 | + return 'radio'; |
91 | 75 | } |
92 | | - } |
93 | | - |
94 | | - followHref() { |
95 | | - const element = this.listItemElement_.current; |
96 | | - if (isAnchorElement(element)) { |
97 | | - element.click(); |
98 | | - } |
99 | | - } |
100 | | - |
101 | | - toggleCheckbox() { |
102 | | - // TODO(bonniez): implement |
103 | | - // https://github.com/material-components/material-components-web-react/issues/352 |
| 76 | + return null; |
104 | 77 | } |
105 | 78 |
|
106 | 79 | render() { |
107 | 80 | const { |
108 | | - /* eslint-disable */ |
| 81 | + /* eslint-disable no-unused-vars */ |
109 | 82 | className, |
110 | | - classNamesFromList, |
111 | | - childrenTabIndex, |
112 | | - shouldFocus, |
113 | | - shouldFollowHref, |
114 | | - shouldToggleCheckbox, |
115 | | - /* eslint-enable */ |
116 | | - attributesFromList, |
117 | 83 | children, |
| 84 | + role, |
| 85 | + checkboxList, |
| 86 | + radioList, |
| 87 | + /* eslint-enable no-unused-vars */ |
118 | 88 | tag: Tag, |
| 89 | + |
119 | 90 | ...otherProps |
120 | 91 | } = this.props; |
121 | 92 | return ( |
122 | 93 | // https://github.com/Microsoft/TypeScript/issues/28892 |
123 | 94 | // @ts-ignore |
124 | 95 | <Tag |
| 96 | + role={this.role} |
125 | 97 | className={this.classes} |
| 98 | + ref={this.listItemElement} |
126 | 99 | {...otherProps} |
127 | | - {...attributesFromList} // overrides attributes in otherProps |
128 | | - ref={this.listItemElement_} |
129 | 100 | > |
130 | | - {React.Children.map(children, this.renderChild)} |
| 101 | + {this.props.children} |
131 | 102 | </Tag> |
132 | 103 | ); |
133 | 104 | } |
134 | | - |
135 | | - renderChild = (child: React.ReactChild) => { |
136 | | - if (typeof child === 'string' || typeof child === 'number' || child === null) { |
137 | | - return child; |
138 | | - } |
139 | | - |
140 | | - const tabIndex = this.props.childrenTabIndex; |
141 | | - const props = {...child.props, tabIndex}; |
142 | | - return React.cloneElement(child, props); |
143 | | - }; |
144 | 105 | } |
0 commit comments