Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding FilterList and FilterListItem #167

Merged
merged 11 commits into from Aug 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions examples/component-examples/FilterList.js
@@ -0,0 +1,33 @@
import React from 'react'
import {LiveEditor} from '@compositor/kit'
import {Block, FilterList, FilterListItem} from '../../src'

const filterListCode = `<FilterList>
<FilterListItem selected count='32' href='#foo'>First Filter</FilterListItem>
<FilterListItem count='2' href='#bar'>Second Filter</FilterListItem>
<FilterListItem href='#baz'>Third Filter</FilterListItem>
</FilterList>
`

const filterListSmallCode = `<FilterList small>
<FilterListItem selected count='32' href='#foo'>First Filter</FilterListItem>
<FilterListItem href='#bar'>Second Filter</FilterListItem>
<FilterListItem href='#baz'>Third Filter</FilterListItem>
</FilterList>
`

const FilterListExample = {
name: 'Filter List',
element: (
<div>
<Block mb={3}>
<LiveEditor code={filterListCode} scope={{FilterList, FilterListItem}} />
</Block>
<Block mb={3}>
<LiveEditor code={filterListSmallCode} scope={{FilterList, FilterListItem}} />
</Block>
</div>
)
}

export default FilterListExample
1 change: 1 addition & 0 deletions examples/component-examples/index.js
Expand Up @@ -12,6 +12,7 @@ export {default as CounterLabel} from './CounterLabel'
export {default as Details} from './Details'
export {default as DonutChart} from './DonutChart'
export {default as Dropdown} from './Dropdown'
export {default as FilterList} from './FilterList'
export {default as Flash} from './Flash'
export {default as Flex} from './Flex'
export {default as FontSizes} from './FontSizes'
Expand Down
31 changes: 31 additions & 0 deletions src/FilterList.js
@@ -0,0 +1,31 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import {withSystemProps, COMMON} from './system-props'

export const ITEM_CLASS = 'filter-item'
export const SELECTED_CLASS = 'selected'

function FilterList({children, className, small}) {
const classes = classnames(className, 'filter-list', small && 'small')

const items = React.Children.map(children, child => {
return <li>{child}</li>
})

return <ul className={classes}>{items}</ul>
}

Object.assign(FilterList, {ITEM_CLASS, SELECTED_CLASS})

FilterList.defaultProps = {
m: 0,
p: 0
}

FilterList.propTypes = {
children: PropTypes.node,
small: PropTypes.bool
}

export default withSystemProps(FilterList, COMMON)
42 changes: 42 additions & 0 deletions src/FilterListItem.js
@@ -0,0 +1,42 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import {ITEM_CLASS, SELECTED_CLASS} from './FilterList'
import {withSystemProps, COMMON} from './system-props'

function getCountComponent(count) {
return (
<span className="count" title="results">
{count}
</span>
)
}

function FilterListItem({children, className, count, selected, is: Tag, ...rest}) {
const classes = classnames(ITEM_CLASS, selected && SELECTED_CLASS, className)

if (typeof rest.to === 'string') {
rest.activeClassName = SELECTED_CLASS
}

return (
<Tag className={classes} {...rest}>
{count && getCountComponent(count)}
{children}
</Tag>
)
}

FilterListItem.defaultProps = {
is: 'a'
}

FilterListItem.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
count: PropTypes.string,
is: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
selected: PropTypes.bool
}

export default withSystemProps(FilterListItem, COMMON)
26 changes: 26 additions & 0 deletions src/__tests__/FilterList.js
@@ -0,0 +1,26 @@
import React from 'react'
import FilterList from '../FilterList'
import {render, rendersClass} from '../utils/testing'
import {COMMON} from '../system-props'

describe('FilterList', () => {
it('implements common system props', () => {
expect(FilterList).toImplementSystemProps(COMMON)
})

it('renders a <ul>', () => {
expect(render(<FilterList />).type).toEqual('ul')
})

it('wraps children in <li>', () => {
expect(render(<FilterList>Hello</FilterList>).children.pop().type).toEqual('li')
})

it('adds the filter-list class', () => {
expect(rendersClass(<FilterList />, 'filter-list')).toEqual(true)
})

it('respects the "small" prop', () => {
expect(rendersClass(<FilterList small />, 'small')).toEqual(true)
})
})
35 changes: 35 additions & 0 deletions src/__tests__/FilterListItem.js
@@ -0,0 +1,35 @@
/* eslint-disable jsx-a11y/anchor-has-content, jsx-a11y/anchor-is-valid */
import React from 'react'
import FilterListItem from '../FilterListItem'
import {render} from '../utils/testing'
import {COMMON} from '../system-props'

describe('FilterListItem', () => {
it('implements common system props', () => {
expect(FilterListItem).toImplementSystemProps(COMMON)
})

it('renders an <a> by default', () => {
expect(render(<FilterListItem />).type).toEqual('a')
})

it('renders the given "tag" prop', () => {
const Type = props => <b {...props} />
expect(render(<FilterListItem tag={Type} />)).toMatchSnapshot()
})

it('respects the "selected" prop', () => {
expect(render(<FilterListItem selected />)).toMatchSnapshot()
})

it('adds activeClassName={SELECTED_CLASS} when it gets a "to" prop', () => {
const Mock = jest.fn(() => <div />)
expect(render(<FilterListItem tag={Mock} to="#" />)).toMatchSnapshot()
})

it('respects "count" prop', () => {
const CountMock = render(<FilterListItem count="400" />).children.pop()
expect(CountMock.type).toEqual('span')
expect(CountMock.props.className).toEqual('count')
})
})
23 changes: 23 additions & 0 deletions src/__tests__/__snapshots__/FilterListItem.js.snap
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`FilterListItem adds activeClassName={SELECTED_CLASS} when it gets a "to" prop 1`] = `
<a
activeClassName="selected"
className="filter-item emotion-0"
tag={[MockFunction]}
to="#"
/>
`;

exports[`FilterListItem renders the given "tag" prop 1`] = `
<a
className="filter-item emotion-0"
tag={[Function]}
/>
`;

exports[`FilterListItem respects the "selected" prop 1`] = `
<a
className="filter-item selected emotion-0"
/>
`;
2 changes: 2 additions & 0 deletions src/index.js
Expand Up @@ -24,6 +24,8 @@ export {default as Dropdown} from './Dropdown'

export {default as DonutChart} from './DonutChart'
export {default as DonutSlice} from './DonutSlice'
export {default as FilterList} from './FilterList'
export {default as FilterListItem} from './FilterListItem'
export {default as FlexContainer} from './FlexContainer'
export {default as FlexItem} from './FlexItem'

Expand Down