Skip to content

Commit

Permalink
feat: add List and ListInlineItem components (reactstrap#2033)
Browse files Browse the repository at this point in the history
* Add ListInline

* Add ListInlineItem

* Add tests

* Update docs

* Rename ListInline to List

* Update List

* Update ListInlineItem

* Update tests

* Add ListUnstyled example

* Update docs

* Update indentation

* Update to use forwardRef

* Update docs
  • Loading branch information
johnathanmiller committed Dec 14, 2020
1 parent 0aa6211 commit a97a834
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 0 deletions.
62 changes: 62 additions & 0 deletions docs/lib/Components/ListPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { PrismCode } from 'react-prism';
import PageTitle from '../UI/PageTitle';
import ListInlineExample from '../examples/ListInline';
import ListUnstyledExample from '../examples/ListUnstyled';

const ListInlineExampleSource = require('!!raw-loader!../examples/ListInline');
const ListUnstyledExampleSource = require('!!raw-loader!../examples/ListUnstyled');

export default class ListPage extends React.Component {
render() {
return (
<div>
<PageTitle title="List" />
<div className="docs-example">
<ListUnstyledExample />
</div>
<pre>
<PrismCode className="language-jsx">
{ListUnstyledExampleSource}
</PrismCode>
</pre>

<legend>Inline</legend>
<div className="docs-example">
<ListInlineExample />
</div>
<pre>
<PrismCode className="language-jsx">
{ListInlineExampleSource}
</PrismCode>
</pre>

<h4>List Properties</h4>
<pre>
<PrismCode className="language-jsx">
{
`List.propTypes = {
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
className: PropTypes.string,
cssModule: PropTypes.object,
type: PropTypes.string
};`
}
</PrismCode>
</pre>
<h4>ListInlineItem Properties</h4>
<pre>
<PrismCode className="language-jsx">
{
`ListInlineItem.propTypes = {
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
className: PropTypes.string,
cssModule: PropTypes.object
};`
}
</PrismCode>
</pre>
</div>
);
}
}
4 changes: 4 additions & 0 deletions docs/lib/Components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ const items = [
name: 'Layout',
to: '/components/layout/'
},
{
name: 'List',
to: '/components/list/'
},
{
name: 'List Group',
to: '/components/listgroup/'
Expand Down
14 changes: 14 additions & 0 deletions docs/lib/examples/ListInline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { List, ListInlineItem } from 'reactstrap';

const Example = (props) => {
return (
<List type="inline">
<ListInlineItem>Lorem ipsum</ListInlineItem>
<ListInlineItem>Phasellus iaculis</ListInlineItem>
<ListInlineItem>Nulla volutpat</ListInlineItem>
</List>
);
}

export default Example;
26 changes: 26 additions & 0 deletions docs/lib/examples/ListUnstyled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { List } from 'reactstrap';

const Example = (props) => {
return (
<List type="unstyled">
<li>Lorem ipsum dolor sit amet</li>
<li>Consectetur adipiscing elit</li>
<li>Integer molestie lorem at massa</li>
<li>Facilisis in pretium nisl aliquet</li>
<li>Nulla volutpat aliquam velit
<ul>
<li>Phasellus iaculis neque</li>
<li>Purus sodales ultricies</li>
<li>Vestibulum laoreet porttitor sem</li>
<li>Ac tristique libero volutpat at</li>
</ul>
</li>
<li>Faucibus porta lacus fringilla vel</li>
<li>Aenean sit amet erat nunc</li>
<li>Eget porttitor lorem</li>
</List>
);
}

export default Example;
2 changes: 2 additions & 0 deletions docs/lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import ToastsPage from './Components/ToastsPage';
import CollapsePage from './Components/CollapsePage';
import CarouselPage from './Components/CarouselPage';
import ListGroupPage from './Components/ListGroupPage';
import ListPage from './Components/ListPage';
import SpinnersPage from './Components/SpinnersPage';
import ClearfixPage from './Utilities/ClearfixPage';
import ColorsPage from './Utilities/ColorsPage';
Expand Down Expand Up @@ -68,6 +69,7 @@ const routes = (
<Route path="jumbotron/" component={JumbotronPage} />
<Route path="collapse/" component={CollapsePage} />
<Route path="carousel/" component={CarouselPage} />
<Route path="list/" component={ListPage} />
<Route path="listgroup/" component={ListGroupPage} />
<Route path="spinners/" component={SpinnersPage} />
</Route>
Expand Down
38 changes: 38 additions & 0 deletions src/List.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';

const propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
type: PropTypes.string
};

const defaultProps ={
tag: 'ul'
};

const List = forwardRef((props, ref) => {
const {
className,
cssModule,
tag: Tag,
type,
...attributes
} = props;
const classes = mapToCssModules(classNames(
className,
type ? `list-${type}` : false
), cssModule);

return (
<Tag {...attributes} className={classes} ref={ref} />
);
});

List.propTypes = propTypes;
List.defaultProps = defaultProps;

export default List;
36 changes: 36 additions & 0 deletions src/ListInlineItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';

const propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object
};

const defaultProps ={
tag: 'li'
};

const ListInlineItem = forwardRef((props, ref) => {
const {
className,
cssModule,
tag: Tag,
...attributes
} = props;
const classes = mapToCssModules(classNames(
className,
'list-inline-item'
), cssModule);

return (
<Tag {...attributes} className={classes} ref={ref} />
);
});

ListInlineItem.propTypes = propTypes;
ListInlineItem.defaultProps = defaultProps;

export default ListInlineItem;
39 changes: 39 additions & 0 deletions src/__tests__/List.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { shallow } from 'enzyme';
import { List } from '../';

describe('List', () => {
it('should render with "ul" tag', () => {
const wrapper = shallow(<List>Yo!</List>);

expect(wrapper.type()).toBe('ul');
})

it('should render with "list-inline" class when type is "inline"', () => {
const wrapper = shallow(<List type="inline">Yo!</List>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('list-inline')).toBe(true);
});

it('should render with "list-unstyled" class when type is "unstyled"', () => {
const wrapper = shallow(<List type="unstyled">Yo!</List>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('list-unstyled')).toBe(true);
});

it('should render additional classes', () => {
const wrapper = shallow(<List className="other">Yo!</List>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('other')).toBe(true);
});

it('should render custom tag', () => {
const wrapper = shallow(<List tag="main">Yo!</List>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.find('main').length).toBe(1);
});
});
33 changes: 33 additions & 0 deletions src/__tests__/ListInlineItem.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { shallow } from 'enzyme';
import { ListInlineItem } from '../';

describe('ListInlineItem', () => {
it('should render children', () => {
const listInlineItem = shallow(<ListInlineItem>Yo!</ListInlineItem>).find('li');
expect(listInlineItem.text()).toBe('Yo!');
});

it('should render with "list-inline-item" class', () => {
const wrapper = shallow(<ListInlineItem>Yo!</ListInlineItem>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('list-inline-item')).toBe(true);
});

it('should render additional classes', () => {
const wrapper = shallow(<ListInlineItem className="other">Yo!</ListInlineItem>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('other')).toBe(true);
expect(wrapper.hasClass('list-inline-item')).toBe(true);
});

it('should render custom tag', () => {
const wrapper = shallow(<ListInlineItem tag="span">Yo!</ListInlineItem>);

expect(wrapper.text()).toBe('Yo!');
expect(wrapper.hasClass('list-inline-item')).toBe(true);
expect(wrapper.find('span').length).toBe(1);
});
});
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export Collapse from './Collapse';
export ListGroupItem from './ListGroupItem';
export ListGroupItemHeading from './ListGroupItemHeading';
export ListGroupItemText from './ListGroupItemText';
export List from './List';
export ListInlineItem from './ListInlineItem';
export UncontrolledAlert from './UncontrolledAlert';
export UncontrolledButtonDropdown from './UncontrolledButtonDropdown';
export UncontrolledCollapse from './UncontrolledCollapse';
Expand Down
4 changes: 4 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ export { default as ListGroupItemHeading } from './lib/ListGroupItemHeading';
export { ListGroupItemHeadingProps } from './lib/ListGroupItemHeading';
export { default as ListGroupItemText } from './lib/ListGroupItemText';
export { ListGroupItemTextProps } from './lib/ListGroupItemText';
export { default as List } from './lib/List';
export { ListProps } from './lib/List';
export { default as ListInlineItem } from './lib/ListInlineItem';
export { ListInlineItemProps } from './lib/ListInlineItem';
export { default as Media } from './lib/Media';
export { MediaProps } from './lib/Media';
export { default as Modal } from './lib/Modal';
Expand Down
12 changes: 12 additions & 0 deletions types/lib/List.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { CSSModule } from './index';

export interface ListProps extends React.HTMLAttributes<HTMLElement> {
[key: string]: any;
tag?: React.ElementType;
cssModule?: CSSModule;
type?: string;
}

declare class List extends React.Component<ListProps> {}
export default List;
11 changes: 11 additions & 0 deletions types/lib/ListInlineItem.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react';
import { CSSModule } from './index';

export interface ListInlineItemProps extends React.HTMLAttributes<HTMLElement> {
[key: string]: any;
tag?: React.ElementType;
cssModule?: CSSModule;
}

declare class ListInlineItem extends React.Component<ListInlineItemProps> {}
export default ListInlineItem;
2 changes: 2 additions & 0 deletions types/reactstrap-tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ import {
ListGroupItem,
ListGroupItemHeading,
ListGroupItemText,
List,
ListInlineItem,
ModalFooter,
Modal,
ModalBody,
Expand Down

0 comments on commit a97a834

Please sign in to comment.