Skip to content

Commit

Permalink
Merge pull request #167 from primer/side_nav
Browse files Browse the repository at this point in the history
Adding FilterList and FilterListItem
  • Loading branch information
jonrohan committed Aug 3, 2018
2 parents bf93b39 + 884d63f commit 503f093
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 0 deletions.
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

0 comments on commit 503f093

Please sign in to comment.