Add the accordion component + tests (fixes #170)
This commit is contained in:
Родитель
55ff8d379c
Коммит
ce92cf7169
|
@ -0,0 +1,101 @@
|
|||
'use strict';
|
||||
|
||||
/*eslint react/no-multi-comp: 0 */
|
||||
|
||||
var React = require('react');
|
||||
var cx = require('classnames');
|
||||
|
||||
|
||||
var Accordion = React.createClass({
|
||||
|
||||
displayName: 'Accordion',
|
||||
|
||||
propTypes: {
|
||||
children: React.PropTypes.array,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var sections = [];
|
||||
React.Children.forEach(this.props.children, function() {
|
||||
sections.push({isActive: false});
|
||||
});
|
||||
sections[0].isActive = true;
|
||||
return {
|
||||
sections: sections,
|
||||
};
|
||||
},
|
||||
|
||||
activate: function(sectionIdx, e) {
|
||||
if (e.target.getAttribute('data-activate') !== null) {
|
||||
e.preventDefault();
|
||||
var sections = this.state.sections;
|
||||
sections.forEach(function(section, idx) {
|
||||
section.isActive = (sectionIdx === idx);
|
||||
});
|
||||
this.setState({sections: sections});
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var that = this;
|
||||
var children = React.Children.map(this.props.children, function(child, idx){
|
||||
return React.cloneElement(child, {
|
||||
activate: that.activate.bind(that, idx),
|
||||
isActive: that.state.sections[idx].isActive,
|
||||
});
|
||||
});
|
||||
return (
|
||||
<div className="accordion" ref="accordion">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var AccordionSection = React.createClass({
|
||||
|
||||
displayName: 'AccordionSection',
|
||||
|
||||
propTypes: {
|
||||
activate: React.PropTypes.function,
|
||||
children: React.PropTypes.array,
|
||||
isActive: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var classes = cx(
|
||||
'ac-section', {'active': this.props.isActive});
|
||||
|
||||
return (
|
||||
<section onClick={this.props.activate}
|
||||
className={classes}>
|
||||
{this.props.children}
|
||||
</section>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
var AccordionContent = React.createClass({
|
||||
|
||||
displayName: 'AccordionContent',
|
||||
|
||||
propTypes: {
|
||||
children: React.PropTypes.array,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="ac-content">
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
Accordion: Accordion,
|
||||
AccordionContent: AccordionContent,
|
||||
AccordionSection: AccordionSection,
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var TestUtils = require('react/lib/ReactTestUtils');
|
||||
var helpers = require('./helpers');
|
||||
|
||||
var {Accordion,
|
||||
AccordionContent,
|
||||
AccordionSection} = require('components/accordion');
|
||||
|
||||
|
||||
describe('Accordion', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.Accordion = TestUtils.renderIntoDocument(
|
||||
<Accordion>
|
||||
<AccordionSection>
|
||||
<h2>Section 1</h2>
|
||||
<button className="button1" data-activate>Click this</button>
|
||||
<AccordionContent>
|
||||
<p>Section 1 content</p>
|
||||
</AccordionContent>
|
||||
</AccordionSection>
|
||||
|
||||
<AccordionSection>
|
||||
<h2>Section 2</h2>
|
||||
<button className="button2" data-activate>Click this</button>
|
||||
<AccordionContent>
|
||||
<p>Section 2 content</p>
|
||||
</AccordionContent>
|
||||
</AccordionSection>
|
||||
|
||||
<AccordionSection>
|
||||
<h2>Section 3</h2>
|
||||
<button className="button3">Click this</button>
|
||||
<p>Section 3 content</p>
|
||||
</AccordionSection>
|
||||
</Accordion>
|
||||
);
|
||||
});
|
||||
|
||||
it('should initialize with first section visible', function() {
|
||||
var sections = helpers.findAllByClass(this.Accordion, 'ac-section');
|
||||
assert.include(sections[0].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.notInclude(sections[1].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.notInclude(sections[2].getDOMNode().getAttribute('class'), 'active');
|
||||
});
|
||||
|
||||
it('should show section 2 on click', function() {
|
||||
var button2 = helpers.findByClass(this.Accordion, 'button2');
|
||||
TestUtils.Simulate.click(button2.getDOMNode());
|
||||
var sections = helpers.findAllByClass(this.Accordion, 'ac-section');
|
||||
assert.notInclude(sections[0].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.include(sections[1].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.notInclude(sections[2].getDOMNode().getAttribute('class'), 'active');
|
||||
});
|
||||
|
||||
it('clicking button in section3 should be a noop', function() {
|
||||
var button3 = helpers.findByClass(this.Accordion, 'button3');
|
||||
TestUtils.Simulate.click(button3.getDOMNode());
|
||||
var sections = helpers.findAllByClass(this.Accordion, 'ac-section');
|
||||
assert.include(sections[0].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.notInclude(sections[1].getDOMNode().getAttribute('class'), 'active');
|
||||
assert.notInclude(sections[2].getDOMNode().getAttribute('class'), 'active');
|
||||
});
|
||||
|
||||
});
|
Загрузка…
Ссылка в новой задаче