Created
December 10, 2017 11:34
-
-
Save aamirafridi/f263630c1efc5c8351385c718f15e50f to your computer and use it in GitHub Desktop.
React Accordion Component
This file contains hidden or 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
import "./index.css"; | |
import React, { Component } from "react"; | |
class Accordion extends Component { | |
static defaultProps = { | |
onChange: () => {}, | |
statusIconsComponents: { | |
opened: "▲", | |
closed: "▼" | |
}, | |
allowMultipleExpand: true | |
}; | |
state = { | |
activeIndexes: [] | |
}; | |
updateIndexes = (index, callback) => { | |
const { allowMultipleExpand, onChange } = this.props; | |
this.setState(prevState => { | |
let activeIndexes; | |
let isOpen = false; | |
if (prevState.activeIndexes.includes(index)) { | |
activeIndexes = allowMultipleExpand | |
? prevState.activeIndexes.filter( | |
currentIndex => currentIndex !== index | |
) | |
: []; | |
} else { | |
isOpen = true; | |
activeIndexes = allowMultipleExpand | |
? prevState.activeIndexes.concat(index) | |
: [index]; | |
} | |
callback(isOpen); | |
onChange(activeIndexes); | |
return { activeIndexes }; | |
}); | |
}; | |
render() { | |
const children = React.Children.map(this.props.children, (child, index) => { | |
const isActive = this.state.activeIndexes.includes(index); | |
return React.cloneElement(child, { | |
isActive, | |
statusIcon: this.props.statusIconsComponents[ | |
isActive ? "opened" : "closed" | |
], | |
onSelect: onSelectCallback => | |
this.updateIndexes(index, onSelectCallback) | |
}); | |
}); | |
return <div className="accordion">{children}</div>; | |
} | |
} | |
class AccordionItem extends Component { | |
static defaultProps = { | |
onChange: () => {}, | |
isOpen: false | |
}; | |
componentWillMount() { | |
const { isOpen, onSelect, onChange } = this.props; | |
if (isOpen) { | |
onSelect(onChange); | |
} | |
} | |
render() { | |
const { isActive, statusIcon, onSelect, onChange } = this.props; | |
const children = React.Children.map(this.props.children, child => { | |
return React.cloneElement(child, { | |
isActive, | |
statusIcon, | |
onSelect: () => { | |
onSelect(onChange); | |
} | |
}); | |
}); | |
return <div className="accordion__item">{children}</div>; | |
} | |
} | |
class AccordionHeader extends Component { | |
render() { | |
return ( | |
<div onClick={this.props.onSelect} className="accordion__header"> | |
{this.props.children} - {this.props.statusIcon} | |
</div> | |
); | |
} | |
} | |
class AccordionPanel extends Component { | |
render() { | |
return this.props.isActive ? ( | |
<div className="accordion__panel">{this.props.children}</div> | |
) : null; | |
} | |
} | |
class App extends Component { | |
render() { | |
return ( | |
<div> | |
<Accordion | |
onChange={console.log} | |
statusIconsComponents={{ | |
opened: "😊", | |
closed: "😞" | |
}} | |
allowMultipleExpand={true} | |
> | |
<AccordionItem | |
isOpen | |
onChange={isOpen => console.log("isOpen = ", isOpen)} | |
> | |
<AccordionHeader>Header 1</AccordionHeader> | |
<AccordionPanel>Panel 1</AccordionPanel> | |
</AccordionItem> | |
<AccordionItem> | |
<AccordionHeader>Header 2</AccordionHeader> | |
<AccordionPanel>Panel 2</AccordionPanel> | |
</AccordionItem> | |
<AccordionItem> | |
<AccordionHeader>Header 3</AccordionHeader> | |
<AccordionPanel>Panel 3</AccordionPanel> | |
</AccordionItem> | |
</Accordion> | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains hidden or 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
.accordion { | |
width: 50%; | |
margin: auto; | |
background: grey; | |
padding: 5px; | |
} | |
.accordion__item { | |
background: white; | |
margin-bottom: 5px; | |
} | |
.accordion__item:last-child { | |
margin-bottom: 0; | |
} | |
.accordion__header { | |
padding: 10px; | |
background: rgb(169, 169, 169); | |
line-height: 20px; | |
} | |
.accordion__panel { | |
padding: 10px; | |
background: white; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment