Skip to content
This repository was archived by the owner on Jul 29, 2025. It is now read-only.

Commit 3b6c501

Browse files
author
Matt Goo
committed
feat(list): typescript (#501)
1 parent 056adb5 commit 3b6c501

20 files changed

+610
-560
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
"@types/mocha": "^5.2.5",
9292
"@types/prop-types": "^15.5.6",
9393
"@types/puppeteer": "^1.11.1",
94-
"@types/react": "^16.7.7",
94+
"@types/react": "^16.4.4",
9595
"@types/react-dom": "^16.0.11",
9696
"@types/react-router-dom": "^4.3.1",
9797
"@types/uuid": "^3.4.4",

packages/list/ListDivider.js renamed to packages/list/ListDivider.tsx

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,27 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23-
import React from 'react';
24-
import PropTypes from 'prop-types';
25-
import classnames from 'classnames';
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
2625

27-
const ListDivider = (props) => {
28-
const {
29-
tag: Tag,
30-
className,
31-
...otherProps
32-
} = props;
26+
export interface ListDividerProps extends React.HTMLProps<HTMLElement>{
27+
className?: string,
28+
tag?: string,
29+
role?: string
30+
};
3331

32+
const ListDivider: React.FunctionComponent<ListDividerProps> = ({
33+
tag: Tag = 'li', className = '', role = 'separator', ...otherProps // eslint-disable-line react/prop-types
34+
}) => {
3435
return (
36+
// https://github.com/Microsoft/TypeScript/issues/28892
37+
// @ts-ignore
3538
<Tag
3639
className={classnames('mdc-list-divider', className)}
40+
role={role}
3741
{...otherProps}
3842
/>
3943
);
4044
};
4145

42-
ListDivider.propTypes = {
43-
className: PropTypes.string,
44-
tag: PropTypes.string,
45-
role: PropTypes.string,
46-
};
47-
48-
ListDivider.defaultProps = {
49-
className: '',
50-
tag: 'li',
51-
role: 'separator',
52-
};
53-
5446
export default ListDivider;

packages/list/ListGroup.js renamed to packages/list/ListGroup.tsx

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,24 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23-
import React from 'react';
24-
import PropTypes from 'prop-types';
25-
import classnames from 'classnames';
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
2625

27-
const ListGroup = (props) => {
28-
const {
29-
tag: Tag,
30-
className,
31-
children,
32-
...otherProps
33-
} = props;
26+
export interface ListGroupProps extends React.HTMLProps<HTMLElement>{
27+
className?: string,
28+
tag?: string
29+
};
3430

31+
const ListGroup:React.FunctionComponent<ListGroupProps> = ({
32+
tag: Tag = 'div', className = '', children, ...otherProps // eslint-disable-line react/prop-types
33+
}) => {
3534
return (
35+
// https://github.com/Microsoft/TypeScript/issues/28892
36+
// @ts-ignore
3637
<Tag className={classnames('mdc-list-group', className)} {...otherProps}>
3738
{children}
3839
</Tag>
3940
);
4041
};
4142

42-
ListGroup.propTypes = {
43-
className: PropTypes.string,
44-
children: PropTypes.node,
45-
tag: PropTypes.string,
46-
};
47-
48-
ListGroup.defaultProps = {
49-
className: '',
50-
children: null,
51-
tag: 'div',
52-
};
53-
5443
export default ListGroup;

packages/list/ListGroupSubheader.js renamed to packages/list/ListGroupSubheader.tsx

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,26 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23-
import React from 'react';
24-
import PropTypes from 'prop-types';
25-
import classnames from 'classnames';
26-
27-
const ListGroupSubheader = (props) => {
28-
const {
29-
tag: Tag,
30-
className,
31-
children,
32-
...otherProps
33-
} = props;
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
25+
export interface ListGroupSubheaderProps extends React.HTMLProps<HTMLElement> {
26+
className?: string,
27+
tag?: string
28+
};
3429

30+
const ListGroupSubheader:React.FunctionComponent<ListGroupSubheaderProps> = ({
31+
tag: Tag = 'h3', className = '', children, ...otherProps // eslint-disable-line react/prop-types
32+
}) => {
3533
return (
36-
<Tag className={classnames('mdc-list-group__subheader', className)} {...otherProps}>
34+
// https://github.com/Microsoft/TypeScript/issues/28892
35+
// @ts-ignore
36+
<Tag
37+
className={classnames('mdc-list-group__subheader', className)}
38+
{...otherProps}
39+
>
3740
{children}
3841
</Tag>
3942
);
4043
};
4144

42-
ListGroupSubheader.propTypes = {
43-
className: PropTypes.string,
44-
children: PropTypes.oneOfType([
45-
PropTypes.string,
46-
PropTypes.element,
47-
]),
48-
tag: PropTypes.string,
49-
};
50-
51-
ListGroupSubheader.defaultProps = {
52-
className: '',
53-
children: '',
54-
tag: 'h3',
55-
};
56-
5745
export default ListGroupSubheader;

packages/list/ListItem.js renamed to packages/list/ListItem.tsx

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,65 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23-
import React, {Component} from 'react';
24-
import PropTypes from 'prop-types';
25-
import classnames from 'classnames';
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
2625

27-
export default class ListItem extends Component {
28-
listItemElement_ = React.createRef();
26+
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;
35+
onKeyDown: React.KeyboardEventHandler<T>;
36+
onClick: React.MouseEventHandler<T>;
37+
onFocus: React.FocusEventHandler<T>;
38+
onBlur: React.FocusEventHandler<T>;
39+
tag: string;
40+
children: React.ReactNode;
41+
};
2942

30-
componentDidUpdate(prevProps) {
31-
const {
32-
shouldFocus,
33-
shouldFollowHref,
34-
shouldToggleCheckbox,
35-
} = this.props;
36-
if (shouldFocus !== prevProps.shouldFocus && shouldFocus) {
43+
function isAnchorElement(element: any): element is HTMLAnchorElement {
44+
return !!element.href;
45+
}
46+
47+
function isFocusableElement(element: any): element is HTMLElement {
48+
return typeof <HTMLElement>element.focus === 'function';
49+
}
50+
51+
export default class ListItem<T extends {} = HTMLElement> extends React.Component<
52+
ListItemProps<T>,
53+
{}
54+
> {
55+
listItemElement_: React.RefObject<T> = React.createRef();
56+
57+
static defaultProps: Partial<ListItemProps<HTMLElement>> = {
58+
className: '',
59+
classNamesFromList: [],
60+
attributesFromList: {},
61+
childrenTabIndex: -1,
62+
tabIndex: -1,
63+
shouldFocus: false,
64+
shouldFollowHref: false,
65+
shouldToggleCheckbox: false,
66+
onKeyDown: () => {},
67+
onClick: () => {},
68+
onFocus: () => {},
69+
onBlur: () => {},
70+
tag: 'li',
71+
};
72+
73+
componentDidUpdate(prevProps: ListItemProps<T>) {
74+
const {shouldFocus, shouldFollowHref, shouldToggleCheckbox} = this.props;
75+
if (shouldFocus && !prevProps.shouldFocus) {
3776
this.focus();
3877
}
39-
if (shouldFollowHref !== prevProps.shouldFollowHref && shouldFollowHref) {
78+
if (shouldFollowHref && !prevProps.shouldFollowHref) {
4079
this.followHref();
4180
}
42-
if (shouldToggleCheckbox !== prevProps.shouldToggleCheckbox && shouldToggleCheckbox) {
81+
if (shouldToggleCheckbox && !prevProps.shouldToggleCheckbox) {
4382
this.toggleCheckbox();
4483
}
4584
}
@@ -51,14 +90,14 @@ export default class ListItem extends Component {
5190

5291
focus() {
5392
const element = this.listItemElement_.current;
54-
if (element) {
93+
if (isFocusableElement(element)) {
5594
element.focus();
5695
}
5796
}
5897

5998
followHref() {
6099
const element = this.listItemElement_.current;
61-
if (element && element.href) {
100+
if (isAnchorElement(element)) {
62101
element.click();
63102
}
64103
}
@@ -83,8 +122,9 @@ export default class ListItem extends Component {
83122
tag: Tag,
84123
...otherProps
85124
} = this.props;
86-
87125
return (
126+
// https://github.com/Microsoft/TypeScript/issues/28892
127+
// @ts-ignore
88128
<Tag
89129
className={this.classes}
90130
{...otherProps}
@@ -96,44 +136,13 @@ export default class ListItem extends Component {
96136
);
97137
}
98138

99-
renderChild = (child) => {
100-
const props = Object.assign({},
101-
child.props,
102-
{tabIndex: this.props.childrenTabIndex}
103-
);
139+
renderChild = (child: React.ReactChild) => {
140+
if (typeof child === 'string' || typeof child === 'number') {
141+
return child;
142+
}
143+
144+
const tabIndex = this.props.childrenTabIndex;
145+
const props = {...child.props, tabIndex};
104146
return React.cloneElement(child, props);
105-
}
147+
};
106148
}
107-
108-
ListItem.propTypes = {
109-
children: PropTypes.node,
110-
className: PropTypes.string,
111-
classNamesFromList: PropTypes.array,
112-
attributesFromList: PropTypes.object,
113-
childrenTabIndex: PropTypes.number,
114-
tabIndex: PropTypes.number,
115-
shouldFocus: PropTypes.bool,
116-
shouldFollowHref: PropTypes.bool,
117-
shouldToggleCheckbox: PropTypes.bool,
118-
onKeyDown: PropTypes.func,
119-
onClick: PropTypes.func,
120-
onFocus: PropTypes.func,
121-
onBlur: PropTypes.func,
122-
tag: PropTypes.string,
123-
};
124-
125-
ListItem.defaultProps = {
126-
className: '',
127-
classNamesFromList: [],
128-
attributesFromList: {},
129-
childrenTabIndex: -1,
130-
tabIndex: -1,
131-
shouldFocus: false,
132-
shouldFollowHref: false,
133-
shouldToggleCheckbox: false,
134-
onKeyDown: () => {},
135-
onClick: () => {},
136-
onFocus: () => {},
137-
onBlur: () => {},
138-
tag: 'li',
139-
};

packages/list/ListItemGraphic.js renamed to packages/list/ListItemGraphic.tsx

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,40 +20,30 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23-
import React from 'react';
24-
import PropTypes from 'prop-types';
25-
import classnames from 'classnames';
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
2625

27-
const ListItemGraphic = (props) => {
28-
const {
29-
tabIndex, // eslint-disable-line no-unused-vars
30-
graphic,
31-
tabbableOnListItemFocus,
32-
className,
33-
...otherProps
34-
} = props;
26+
export interface ListItemGraphicProps {
27+
tabbableOnListItemFocus?: boolean;
28+
className?: string;
29+
tabIndex?: number;
30+
graphic: React.ReactElement<any>;
31+
childrenTabIndex?: number;
32+
};
3533

34+
const ListItemGraphic:React.FunctionComponent<ListItemGraphicProps> = ({
35+
tabIndex = -1, // eslint-disable-line no-unused-vars
36+
graphic,
37+
tabbableOnListItemFocus = false,
38+
className = '',
39+
...otherProps
40+
}) => {
3641
const graphicProps = {
3742
className: classnames('mdc-list-item__graphic', className),
38-
tabIndex: tabbableOnListItemFocus ? props.tabIndex : -1,
43+
tabIndex: tabbableOnListItemFocus ? tabIndex : -1,
3944
...otherProps,
4045
};
41-
4246
return React.cloneElement(graphic, graphicProps);
4347
};
4448

45-
ListItemGraphic.propTypes = {
46-
tabbableOnListItemFocus: PropTypes.bool,
47-
className: PropTypes.string,
48-
tabIndex: PropTypes.number,
49-
graphic: PropTypes.element,
50-
};
51-
52-
ListItemGraphic.defaultProps = {
53-
tabbableOnListItemFocus: false,
54-
className: '',
55-
tabIndex: -1,
56-
graphic: {},
57-
};
58-
5949
export default ListItemGraphic;

0 commit comments

Comments
 (0)