-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* init collapse * add collapse animation * add margin between toggle button and collapse * disable lint on force refresh DOM line. * add test to Collapse * remove height after shown * Revert "remove height after shown" This reverts commit eff9353. * remove height after shown. * add more test * use setState() to set inline height style * remove custom tag in doc * add inline style test * remove comment * set height to null when isOpen is true * add initial state test
- Loading branch information
1 parent
0ad0f98
commit ddbf0dd
Showing
8 changed files
with
323 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */ | ||
import React from 'react'; | ||
import { PrismCode } from 'react-prism'; | ||
import { Alert } from 'reactstrap'; | ||
import Helmet from 'react-helmet'; | ||
|
||
import CollapseExample from '../examples/Collapse'; | ||
const CollapseExampleSource = require('!!raw!../examples/Collapse'); | ||
|
||
export default class AlertsPage extends React.Component { | ||
render() { | ||
return ( | ||
<div> | ||
<Helmet title="Collapse" /> | ||
|
||
<h3>Collapse</h3> | ||
<div className="docs-example"> | ||
<CollapseExample /> | ||
</div> | ||
<pre> | ||
<PrismCode className="language-jsx"> | ||
{CollapseExampleSource} | ||
</PrismCode> | ||
</pre> | ||
|
||
<h3>Properties</h3> | ||
<pre> | ||
<PrismCode className="language-jsx"> | ||
{`Collapse.propTypes = { | ||
isOpen: PropTypes.bool, | ||
className: PropTypes.node | ||
}`} | ||
</PrismCode> | ||
</pre> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import React, { Component } from 'react'; | ||
import { Collapse, Button, CardBlock, Card } from 'reactstrap'; | ||
|
||
class Example extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.toggle = this.toggle.bind(this); | ||
this.state = { collapse: false }; | ||
} | ||
|
||
toggle() { | ||
this.setState({ collapse: !this.state.collapse }); | ||
} | ||
|
||
render() { | ||
return ( | ||
<div> | ||
<Button color="primary" onClick={this.toggle} style={{ marginBottom: '1rem' }}>Toggle</Button> | ||
<Collapse isOpen={this.state.collapse}> | ||
<Card> | ||
<CardBlock> | ||
Anim pariatur cliche reprehenderit, | ||
enim eiusmod high life accusamus terry richardson ad squid. Nihil | ||
anim keffiyeh helvetica, craft beer labore wes anderson cred | ||
nesciunt sapiente ea proident. | ||
</CardBlock> | ||
</Card> | ||
</Collapse> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export default Example; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import React, { Component, PropTypes } from 'react'; | ||
import classNames from 'classnames'; | ||
import omit from 'lodash.omit'; | ||
|
||
const SHOW = 'SHOW'; | ||
const SHOWN = 'SHOWN'; | ||
const HIDE = 'HIDE'; | ||
const HIDDEN = 'HIDDEN'; | ||
|
||
const propTypes = { | ||
isOpen: PropTypes.bool, | ||
className: PropTypes.node, | ||
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), | ||
}; | ||
|
||
const defaultProps = { | ||
isOpen: false, | ||
tag: 'div' | ||
}; | ||
|
||
class Collapse extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
collapse: props.isOpen ? SHOWN : HIDDEN, | ||
height: props.isOpen ? null : 0 | ||
}; | ||
this.element = null; | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
const willOpen = nextProps.isOpen; | ||
const collapse = this.state.collapse; | ||
|
||
if (willOpen && collapse === HIDDEN) { | ||
// will open | ||
this.setState({ collapse: SHOW }, () => { | ||
// the height transition will work after class "collapsing" applied | ||
this.setState({ height: this.getHeight() }); | ||
this.transitionTag = setTimeout(() => { | ||
this.setState({ | ||
collapse: SHOWN, | ||
height: null | ||
}); | ||
}, 350); | ||
}); | ||
} else if (!willOpen && collapse === SHOWN) { | ||
// will hide | ||
this.setState({ height: this.getHeight() }, () => { | ||
this.setState({ | ||
collapse: HIDE, | ||
height: this.getHeight() | ||
}, () => { | ||
this.setState({ height: 0 }); | ||
}); | ||
}); | ||
|
||
this.transitionTag = setTimeout(() => { | ||
this.setState({ | ||
collapse: HIDDEN, | ||
height: null | ||
}); | ||
}, 350); | ||
} | ||
// else: do nothing. | ||
} | ||
|
||
componentWillUnmount() { | ||
clearTimeout(this.transitionTag); | ||
} | ||
|
||
getHeight() { | ||
return this.element.scrollHeight; | ||
} | ||
|
||
render() { | ||
const { | ||
className, | ||
tag: Tag, | ||
...attributes | ||
} = omit(this.props, ['isOpen']); | ||
const { collapse, height } = this.state; | ||
let collapseClass; | ||
switch (collapse) { | ||
case SHOW: | ||
collapseClass = 'collapsing'; | ||
break; | ||
case SHOWN: | ||
collapseClass = 'collapse in'; | ||
break; | ||
case HIDE: | ||
collapseClass = 'collapsing'; | ||
break; | ||
case HIDDEN: | ||
collapseClass = 'collapse'; | ||
break; | ||
default: | ||
// HIDDEN | ||
collapseClass = 'collapse'; | ||
} | ||
|
||
const classes = classNames( | ||
className, | ||
collapseClass | ||
); | ||
const style = height === null ? null : { height }; | ||
return ( | ||
<Tag | ||
{...attributes} | ||
style={{ ...attributes.style, ...style }} | ||
className={classes} | ||
ref={(c) => { this.element = c; }} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
Collapse.propTypes = propTypes; | ||
Collapse.defaultProps = defaultProps; | ||
export default Collapse; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import React from 'react'; | ||
import { shallow, mount } from 'enzyme'; | ||
import Collapse from '../Collapse'; | ||
|
||
describe('Collapse', () => { | ||
let isOpen; | ||
let toggle; | ||
|
||
beforeEach(() => { | ||
isOpen = false; | ||
toggle = () => { isOpen = !isOpen; }; | ||
jasmine.clock().install(); | ||
}); | ||
|
||
afterEach(() => { | ||
// fast forward time for collapse to fade out | ||
jasmine.clock().tick(400); | ||
jasmine.clock().uninstall(); | ||
}); | ||
|
||
it('should render children', () => { | ||
const wrapper = shallow(<Collapse><p>hello</p></Collapse>).find('p'); | ||
expect(wrapper.text()).toBe('hello'); | ||
}); | ||
|
||
it('should have default isOpen value', () => { | ||
const wrapper = shallow(<Collapse />); | ||
expect(wrapper.instance().props.isOpen).toEqual(false); | ||
}); | ||
|
||
it('should render with class "collapse"', () => { | ||
const wrapper = shallow(<Collapse />); | ||
expect(wrapper.hasClass('collapse')).toEqual(true); | ||
}); | ||
|
||
it('should render with class "in" when isOpen is true', () => { | ||
const wrapper = shallow(<Collapse isOpen />); | ||
expect(wrapper.hasClass('in')).toEqual(true); | ||
}); | ||
|
||
it('should set height to null when isOpen is true', () => { | ||
isOpen = true; | ||
const wrapper = shallow(<Collapse isOpen={isOpen} />); | ||
expect(wrapper.state('height')).toBe(null); | ||
}); | ||
|
||
it('should set height to 0 when isOpen is false', () => { | ||
const wrapper = shallow(<Collapse isOpen={isOpen} />); | ||
expect(wrapper.state('height')).toBe(0); | ||
}); | ||
|
||
it('should render with class "collapse" with default collapse state', () => { | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
wrapper.setState({ collapse: null }); | ||
jasmine.clock().tick(360); | ||
wrapper.update(); | ||
expect(wrapper.find('.collapse').length).toBe(1); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should change state with { collapse: ${State} } when isOpen change to true before transition', () => { | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
expect(wrapper.state('collapse')).toEqual('SHOW'); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should change state with { collapse: ${State} } when isOpen change to true after transition', () => { | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
jasmine.clock().tick(350); | ||
expect(wrapper.state('collapse')).toEqual('SHOWN'); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should change state with { collapse: ${State} } when isOpen change to false before transition', () => { | ||
isOpen = true; | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
expect(wrapper.state('collapse')).toEqual('HIDE'); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should change state with { collapse: ${State} } when isOpen change to false after transition', () => { | ||
isOpen = true; | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
jasmine.clock().tick(360); | ||
expect(wrapper.state('collapse')).toEqual('HIDDEN'); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should set inline style to 0 when isOpen change to false', () => { | ||
isOpen = true; | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
expect(wrapper.state('height')).toBe(0); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should remove inline style when isOpen change to true after transition', () => { | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
toggle(); | ||
wrapper.setProps({ isOpen: isOpen }); | ||
jasmine.clock().tick(380); | ||
expect(wrapper.state('height')).toBe(null); | ||
wrapper.unmount(); | ||
}); | ||
|
||
it('should remove timeout tag after unmount', () => { | ||
spyOn(Collapse.prototype, 'componentWillUnmount').and.callThrough(); | ||
const wrapper = mount(<Collapse isOpen={isOpen} />); | ||
wrapper.unmount(); | ||
expect(Collapse.prototype.componentWillUnmount).toHaveBeenCalled(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters