Skip to content

Commit 72cc507

Browse files
kwood15rbrtsmith
authored andcommitted
Add Progress Bar Component and Unit Tests (#57)
* Add Progress Bar Component and Unit Tests * PR Fixes * Add animation to progress bar * Add correct aria attributes
1 parent 83d0695 commit 72cc507

File tree

7 files changed

+185
-2
lines changed

7 files changed

+185
-2
lines changed

demo/src/App.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
Section,
66
Pill,
77
Table,
8+
LinkList,
9+
ProgressBar,
810
Form,
911
} from 'nebula-react'
1012

@@ -13,6 +15,15 @@ const App = () => (
1315
<Section size="md">
1416
<SiteWrap padding>
1517
<Section size="md">
18+
<SiteWrap padding>
19+
<h3>Link List with Divider</h3>
20+
<h3>Progress Bar</h3>
21+
<Section size="md">
22+
<ProgressBar.Wrapper>
23+
<ProgressBar.Indicator animated percent="50" />
24+
</ProgressBar.Wrapper>
25+
</Section>
26+
</SiteWrap>
1627
<Table.Wrapper>
1728
<Table.Container spacing="sm" sortedBy={{ index: 3, descending: false }} stackAt="max-sm" onChange={value => console.log(value)}>
1829
<Table.Header>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createElement as E } from 'react'
2+
import T from 'prop-types'
3+
4+
import { classNames } from '../../utils/'
5+
import { NAMESPACE, BLOCK_TAGS } from '../../constants'
6+
7+
const enhancePercentString = percent => `${percent && percent.endsWith('%') ? percent : `${percent}%`}`
8+
9+
const ProgressBarIndicator = ({ tag, animated, percent, className, ...rest }) =>
10+
E(
11+
tag || 'div',
12+
{
13+
style: { width: enhancePercentString(percent) },
14+
className: classNames(
15+
`${NAMESPACE}c-progress-bar__indicator`,
16+
{ [`${NAMESPACE}c-progress-bar__indicator--animated`]: animated },
17+
className
18+
),
19+
role: 'progressbar',
20+
'aria-valuenow': enhancePercentString(percent),
21+
'aria-valuemin': '0%',
22+
'aria-valuemax': '100%',
23+
...rest
24+
},
25+
)
26+
27+
ProgressBarIndicator.propTypes = {
28+
tag: T.oneOf(BLOCK_TAGS),
29+
className: T.string,
30+
percent: T.string,
31+
animated: T.bool
32+
}
33+
34+
export default ProgressBarIndicator
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { createElement as E } from 'react'
2+
import T from 'prop-types'
3+
4+
import { classNames } from '../../utils/'
5+
import { NAMESPACE, BLOCK_TAGS } from '../../constants'
6+
7+
const ProgressBarWrapper = ({ tag, className, children, ...rest }) =>
8+
E(
9+
tag || 'div',
10+
{
11+
className: classNames(`${NAMESPACE}c-progress-bar`, className),
12+
...rest
13+
},
14+
children
15+
)
16+
17+
ProgressBarWrapper.propTypes = {
18+
tag: T.oneOf(BLOCK_TAGS),
19+
className: T.string,
20+
children: T.node.isRequired
21+
}
22+
23+
export default ProgressBarWrapper
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
4+
import { NAMESPACE } from '../../../constants'
5+
import { ProgressBar } from '../'
6+
7+
describe('<ProgressBar.Indicator />', () => {
8+
it('takes a className that gets appended', () => {
9+
const $ = shallow(<ProgressBar.Indicator className="test" />)
10+
expect($.hasClass(`${NAMESPACE}c-progress-bar__indicator`)).toBe(true)
11+
expect($.hasClass(`${NAMESPACE}c-progress-bar__indicator--animated`)).toBe(false)
12+
expect($.hasClass('test')).toBe(true)
13+
})
14+
15+
it('renders with an animated gradient', () => {
16+
const $ = shallow(<ProgressBar.Indicator animated />)
17+
expect($.hasClass(`${NAMESPACE}c-progress-bar__indicator`)).toBe(true)
18+
expect($.hasClass(`${NAMESPACE}c-progress-bar__indicator--animated`)).toBe(true)
19+
})
20+
21+
it('renders a defined tag type', () => {
22+
const $ = shallow(<ProgressBar.Indicator tag="article" />)
23+
expect($.type()).toBe('article')
24+
})
25+
26+
it('renders a div by default', () => {
27+
const $ = shallow(<ProgressBar.Indicator />)
28+
expect($.type()).toBe('div')
29+
})
30+
31+
it('renders with attributes', () => {
32+
const $ = shallow(
33+
<ProgressBar.Indicator style={{ position: 'relative' }} ariaHidden />
34+
)
35+
expect($.prop('style')).toEqual({
36+
position: 'relative'
37+
})
38+
expect($.prop('ariaHidden')).toBe(true)
39+
})
40+
41+
it('renders with the correct aria values', () => {
42+
const $ = shallow(<ProgressBar.Indicator percent="50" />)
43+
expect($.prop('role')).toBe('progressbar')
44+
expect($.prop('aria-valuemin')).toBe('0%')
45+
expect($.prop('aria-valuemax')).toBe('100%')
46+
expect($.prop('aria-valuenow')).toBe('50%')
47+
})
48+
49+
describe('percent prop', () => {
50+
it('renders an inline style width as a percentage', () => {
51+
const $ = shallow(<ProgressBar.Indicator percent="50" />)
52+
expect($.prop('style')).toEqual({
53+
width: '50%'
54+
})
55+
})
56+
57+
it('only appends the percentage unit if not passed', () => {
58+
const $ = shallow(<ProgressBar.Indicator percent="50%" />)
59+
expect($.prop('style')).toEqual({
60+
width: '50%'
61+
})
62+
})
63+
})
64+
})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
4+
import { NAMESPACE } from '../../../constants'
5+
import { ProgressBar } from '../'
6+
7+
describe('<ProgressBar.Wrapper />', () => {
8+
it('takes a className that gets appended', () => {
9+
const $ = shallow(<ProgressBar.Wrapper className="test">_</ProgressBar.Wrapper>)
10+
expect($.hasClass(`${NAMESPACE}c-progress-bar`)).toBe(true)
11+
expect($.hasClass('test')).toBe(true)
12+
})
13+
14+
it('renders a defined tag type', () => {
15+
const $ = shallow(<ProgressBar.Wrapper tag="article">_</ProgressBar.Wrapper>)
16+
expect($.type()).toBe('article')
17+
})
18+
19+
it('renders a div by default', () => {
20+
const $ = shallow(<ProgressBar.Wrapper>_</ProgressBar.Wrapper>)
21+
expect($.type()).toBe('div')
22+
})
23+
24+
it('renders with attributes', () => {
25+
const $ = shallow(
26+
<ProgressBar.Wrapper style={{ position: 'relative' }} ariaHidden>
27+
_
28+
</ProgressBar.Wrapper>
29+
)
30+
expect($.prop('style')).toEqual({
31+
position: 'relative'
32+
})
33+
expect($.prop('ariaHidden')).toBe(true)
34+
})
35+
36+
it('renders children', () => {
37+
const $ = shallow(<ProgressBar.Wrapper>test child</ProgressBar.Wrapper>)
38+
expect($.contains('test child')).toBe(true)
39+
})
40+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Wrapper from './Wrapper'
2+
import Indicator from './Indicator'
3+
4+
const ProgressBar = {
5+
Wrapper,
6+
Indicator
7+
}
8+
9+
export { ProgressBar }

src/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import { Icon } from './components/Icon/'
1818
import { LinkList } from './components/LinkList/'
1919
import { LoadingIcon } from './components/LoadingIcon/'
2020
import { Modal } from './components/Modal/'
21-
import { Pagination } from './components/Pagination/'
2221
import { Navbar } from './components/Navbar/'
22+
import { Pagination } from './components/Pagination/'
2323
import { Pill } from './components/Pill/'
24+
import { ProgressBar } from './components/ProgressBar/'
2425
import { StatusCard } from './components/StatusCard/'
2526
import { Table } from './components/Table/'
2627
import { Tabs } from './components/Tabs/'
@@ -46,8 +47,9 @@ export {
4647
MatrixList,
4748
Modal,
4849
Navbar,
49-
Pill,
5050
Pagination,
51+
Pill,
52+
ProgressBar,
5153
Section,
5254
SiteWrap,
5355
StatusCard,

0 commit comments

Comments
 (0)