Skip to content

Commit 680e083

Browse files
committed
feat(list,listitem): convert to TypeScript and export types
1 parent d5887d4 commit 680e083

File tree

8 files changed

+89
-114
lines changed

8 files changed

+89
-114
lines changed

src/List/List.js

-47
This file was deleted.

src/List/List.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ name: List
33
menu: Components
44
---
55

6-
import List from './List';
7-
import ListItem from '../ListItem/ListItem';
6+
import { List } from './List';
7+
import { ListItem } from '../ListItem/ListItem';
88

99
# List
1010

src/List/List.spec.js renamed to src/List/List.spec.tsx

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import React from 'react';
2-
31
import { renderWithTheme } from '../../test/utils';
42

5-
import List from './List';
3+
import { List } from './List';
64

75
describe('<List />', () => {
86
it('renders List', () => {
97
const { container } = renderWithTheme(<List />);
10-
const list = container.firstChild;
8+
const list = container.firstElementChild;
119

1210
expect(list).toBeInTheDocument();
1311
});
1412
it('is an ul', () => {
1513
const { container } = renderWithTheme(<List />);
16-
const list = container.firstChild;
14+
const list = container.firstElementChild;
1715

18-
expect(list.tagName).toBe('UL');
16+
expect(list?.tagName).toBe('UL');
1917
});
2018
it('renders children', () => {
2119
const textContent = 'Hi there!';
@@ -30,7 +28,7 @@ describe('<List />', () => {
3028
describe('prop: inline', () => {
3129
it('renders inline', () => {
3230
const { container } = renderWithTheme(<List inline />);
33-
const list = container.firstChild;
31+
const list = container.firstElementChild;
3432

3533
expect(list).toHaveStyleRule('display', 'inline-flex');
3634
expect(list).toHaveStyleRule('align-items', 'center');
@@ -39,7 +37,7 @@ describe('<List />', () => {
3937
describe('prop: fullWidth', () => {
4038
it('has 100% width', () => {
4139
const { container } = renderWithTheme(<List fullWidth />);
42-
const list = container.firstChild;
40+
const list = container.firstElementChild;
4341

4442
expect(list).toHaveStyleRule('width', '100%');
4543
});

src/List/List.stories.js renamed to src/List/List.stories.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import { ComponentMeta } from '@storybook/react';
22
import styled from 'styled-components';
33

44
import { List, ListItem, Bar, Divider } from 'react95';
@@ -18,7 +18,7 @@ export default {
1818
component: List,
1919
subcomponents: { ListItem },
2020
decorators: [story => <Wrapper>{story()}</Wrapper>]
21-
};
21+
} as ComponentMeta<typeof List>;
2222

2323
export function Default() {
2424
return (

src/List/List.tsx

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react';
2+
3+
import styled from 'styled-components';
4+
import { createBorderStyles, createBoxStyles } from '../common';
5+
import { CommonStyledProps } from '../types';
6+
7+
type ListProps = React.HTMLAttributes<HTMLUListElement> & {
8+
fullWidth?: boolean;
9+
shadow?: boolean;
10+
inline?: boolean;
11+
} & CommonStyledProps;
12+
13+
// TODO keyboard controls
14+
const List = styled.ul.attrs(() => ({
15+
role: 'menu'
16+
}))<ListProps>`
17+
box-sizing: border-box;
18+
width: ${props => (props.fullWidth ? '100%' : 'auto')};
19+
padding: 4px;
20+
${createBorderStyles({ windowBorders: true })}
21+
${createBoxStyles()}
22+
${props =>
23+
props.inline &&
24+
`
25+
display: inline-flex;
26+
align-items: center;
27+
`}
28+
list-style: none;
29+
position: relative;
30+
`;
31+
32+
export { List, ListProps };

src/ListItem/ListItem.spec.js renamed to src/ListItem/ListItem.spec.tsx

+16-19
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
import React from 'react';
2-
31
import { renderWithTheme, theme } from '../../test/utils';
42
import { blockSizes } from '../common/system';
5-
import ListItem from './ListItem';
3+
import { ListItem } from './ListItem';
64

75
const defaultSize = 'lg';
86
describe('<ListItem />', () => {
97
it('renders ListItem', () => {
10-
const { container } = renderWithTheme(<ListItem />);
11-
const listItem = container.firstChild;
8+
const { getByRole } = renderWithTheme(<ListItem />);
9+
const listItem = getByRole('menuitem');
1210
expect(listItem).toBeInTheDocument();
13-
expect(listItem).toHaveAttribute('aria-disabled', 'false');
14-
expect(ListItem.defaultProps.size).toBe(defaultSize);
11+
expect(listItem).not.toHaveAttribute('aria-disabled');
1512
});
1613
it('renders children', () => {
1714
const textContent = 'Hi there!';
@@ -23,36 +20,36 @@ describe('<ListItem />', () => {
2320
expect(getByText(textContent)).toBeInTheDocument();
2421
});
2522
it('should have a default role of menuitem', () => {
26-
const { container } = renderWithTheme(<ListItem />);
27-
const listItem = container.firstChild;
23+
const { getByRole } = renderWithTheme(<ListItem />);
24+
const listItem = getByRole('menuitem');
2825
expect(listItem).toHaveAttribute('role', 'menuitem');
2926
});
3027

3128
it('should render with custom role', () => {
32-
const { container } = renderWithTheme(<ListItem role='option' />);
33-
const listItem = container.firstChild;
29+
const { getByRole } = renderWithTheme(<ListItem role='option' />);
30+
const listItem = getByRole('option');
3431
expect(listItem).toHaveAttribute('role', 'option');
3532
});
3633

3734
// it('should have a tabIndex of -1 by default', () => {
38-
// const { container } = renderWithTheme(<ListItem role='option' />);
39-
// const listItem = container.firstChild;
35+
// const { getByRole } = renderWithTheme(<ListItem role='option' />);
36+
// const listItem = getByRole('menuitem');
4037
// expect(listItem).toHaveAttribute('tabIndex', '-1');
4138
// });
4239
describe('prop: disabled', () => {
4340
it('should not trigger onClick callback', () => {
4441
const clickHandler = jest.fn();
45-
const { container } = renderWithTheme(
42+
const { getByRole } = renderWithTheme(
4643
<ListItem disabled onClick={clickHandler} />
4744
);
48-
const listItem = container.firstChild;
45+
const listItem = getByRole('menuitem') as HTMLElement;
4946
listItem.click();
5047
expect(clickHandler).not.toBeCalled();
5148
expect(listItem).toHaveAttribute('aria-disabled', 'true');
5249
});
5350
it('renders with disabled styles ', () => {
54-
const { container } = renderWithTheme(<ListItem disabled />);
55-
const listItem = container.firstChild;
51+
const { getByRole } = renderWithTheme(<ListItem disabled />);
52+
const listItem = getByRole('menuitem');
5653
expect(listItem).toHaveStyleRule('pointer-events', 'none');
5754
expect(listItem).toHaveStyleRule('color', theme.materialTextDisabled);
5855
expect(listItem).toHaveStyleRule(
@@ -64,10 +61,10 @@ describe('<ListItem />', () => {
6461
describe('prop: onClick', () => {
6562
it('should be called when clicked', () => {
6663
const clickHandler = jest.fn();
67-
const { container } = renderWithTheme(
64+
const { getByRole } = renderWithTheme(
6865
<ListItem onClick={clickHandler} />
6966
);
70-
const listItem = container.firstChild;
67+
const listItem = getByRole('menuitem') as HTMLElement;
7168
listItem.click();
7269
expect(clickHandler).toHaveBeenCalledTimes(1);
7370
});
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
import React from 'react';
2-
import propTypes from 'prop-types';
1+
import React, { forwardRef } from 'react';
32

43
import styled from 'styled-components';
54
import { createDisabledTextStyles } from '../common';
65
import { blockSizes } from '../common/system';
6+
import { CommonStyledProps, Sizes } from '../types';
77

8-
export const StyledListItem = styled.li`
8+
type ListItemProps = {
9+
disabled?: boolean;
10+
square?: boolean;
11+
primary?: boolean;
12+
size?: Sizes;
13+
} & React.HTMLAttributes<HTMLLIElement> &
14+
CommonStyledProps;
15+
16+
export const StyledListItem = styled.li<{
17+
disabled?: boolean;
18+
square?: boolean;
19+
primary?: boolean;
20+
size: Sizes;
21+
}>`
922
box-sizing: border-box;
1023
1124
display: flex;
@@ -21,32 +34,34 @@ export const StyledListItem = styled.li`
2134
text-align: center;
2235
line-height: ${props => blockSizes[props.size]};
2336
color: ${({ theme }) => theme.materialText};
24-
pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')};
37+
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'auto')};
2538
font-weight: ${({ primary }) => (primary ? 'bold' : 'normal')};
2639
&:hover {
27-
${({ theme, isDisabled }) =>
28-
!isDisabled &&
40+
${({ theme, disabled }) =>
41+
!disabled &&
2942
`
3043
color: ${theme.materialTextInvert};
3144
background: ${theme.hoverBackground};
3245
`}
3346
3447
cursor: default;
3548
}
36-
${props => props.isDisabled && createDisabledTextStyles()}
49+
${props => props.disabled && createDisabledTextStyles()}
3750
`;
3851

39-
const ListItem = React.forwardRef(function ListItem(props, ref) {
40-
const {
41-
size,
52+
const ListItem = forwardRef<HTMLLIElement, ListItemProps>(function ListItem(
53+
{
54+
size = 'lg',
4255
disabled,
4356
// tabIndex: tabIndexProp,
4457
square,
4558
children,
4659
onClick,
4760
primary,
4861
...otherProps
49-
} = props;
62+
},
63+
ref
64+
) {
5065
// let tabIndex;
5166
// if (!disabled) {
5267
// tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1;
@@ -55,39 +70,19 @@ const ListItem = React.forwardRef(function ListItem(props, ref) {
5570
return (
5671
<StyledListItem
5772
size={size}
58-
isDisabled={disabled}
73+
disabled={disabled}
5974
square={square}
6075
onClick={disabled ? undefined : onClick}
6176
primary={primary}
6277
// tabIndex={tabIndex}
6378
role='menuitem'
6479
ref={ref}
65-
aria-disabled={disabled.toString()}
80+
aria-disabled={disabled}
6681
{...otherProps}
6782
>
6883
{children}
6984
</StyledListItem>
7085
);
7186
});
7287

73-
ListItem.defaultProps = {
74-
disabled: false,
75-
size: 'lg',
76-
square: false,
77-
onClick: null,
78-
children: null,
79-
primary: false
80-
// tabIndex: undefined
81-
};
82-
83-
ListItem.propTypes = {
84-
size: propTypes.oneOf(['sm', 'md', 'lg']),
85-
disabled: propTypes.bool,
86-
square: propTypes.bool,
87-
children: propTypes.node,
88-
onClick: propTypes.func,
89-
primary: propTypes.bool
90-
// tabIndex: propTypes.number
91-
};
92-
93-
export default ListItem;
88+
export { ListItem, ListItemProps };

src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export * from './Desktop/Desktop';
1616
export * from './Divider/Divider';
1717
export { default as Fieldset } from './Fieldset/Fieldset';
1818
export * from './Hourglass/Hourglass';
19-
export { default as List } from './List/List';
20-
export { default as ListItem } from './ListItem/ListItem';
19+
export * from './List/List';
20+
export * from './ListItem/ListItem';
2121
export * from './LoadingIndicator/LoadingIndicator';
2222
export { default as NumberField } from './NumberField/NumberField';
2323
export * from './Panel/Panel';

0 commit comments

Comments
 (0)