7 changed files with 372 additions and 356 deletions
@ -0,0 +1,86 @@ |
|||||
|
import React from 'react'; |
||||
|
import className from 'classnames'; |
||||
|
import * as Utils from './settings.panelUtils'; |
||||
|
|
||||
|
class Panel extends React.Component { |
||||
|
|
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
this.toggleSection = this.toggleSection.bind(this); |
||||
|
this.state = { |
||||
|
singleOpen: this.props.singleOpen, |
||||
|
openByDefault: this.props.openByDefault, |
||||
|
activeSections: [], |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
componentWillMount() { |
||||
|
const { |
||||
|
singleOpen, |
||||
|
openByDefault, |
||||
|
uniqId, |
||||
|
children } = this.props; |
||||
|
|
||||
|
const settings = { |
||||
|
singleOpen, |
||||
|
openByDefault, |
||||
|
uniqId, |
||||
|
kids: children |
||||
|
}; |
||||
|
|
||||
|
const initialStateSections = Utils.setupAccordion(settings).activeSections; |
||||
|
this.setState({ activeSections: initialStateSections }); |
||||
|
} |
||||
|
|
||||
|
getChildrenWithProps() { |
||||
|
const { |
||||
|
children, |
||||
|
} = this.props; |
||||
|
|
||||
|
|
||||
|
const kids = React.Children.map(children, (child, i) => { |
||||
|
if(child) { |
||||
|
const unqId = `panel-sec-${i}`; |
||||
|
return React.cloneElement(child, { |
||||
|
toggle: (acId) => this.toggleSection(acId), |
||||
|
key: unqId, |
||||
|
unq: unqId, |
||||
|
active: (this.state.activeSections && this.state.activeSections.lastIndexOf(unqId) !== -1) |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
return kids; |
||||
|
} |
||||
|
|
||||
|
toggleSection(sectionId) { |
||||
|
const newActive = Utils.toggleSection( |
||||
|
sectionId, |
||||
|
this.state.activeSections, |
||||
|
this.state.singleOpen); |
||||
|
|
||||
|
this.setState({ |
||||
|
activeSections: newActive |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { |
||||
|
className: propClasses, |
||||
|
uniqId: propId |
||||
|
} = this.props; |
||||
|
|
||||
|
const childrenWithProps = this.getChildrenWithProps(); |
||||
|
const accordionClasses = className('panel-group', propClasses); |
||||
|
const uniqId = propId || ''; |
||||
|
|
||||
|
return( |
||||
|
<div className={accordionClasses} id={uniqId}> |
||||
|
{childrenWithProps} |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default Panel; |
@ -0,0 +1,85 @@ |
|||||
|
import React from 'react'; |
||||
|
import className from 'classnames'; |
||||
|
|
||||
|
class PanelSection extends React.Component { |
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
this.state = { |
||||
|
sectionHeight: 0, |
||||
|
} |
||||
|
this.toggleSection = this.toggleSection.bind(this); |
||||
|
} |
||||
|
|
||||
|
componentDidMount() { |
||||
|
const { active } = this.props; |
||||
|
if (active) this.setState({sectionHeight: this.accordionContent.scrollHeight}); |
||||
|
} |
||||
|
|
||||
|
componentWillReceiveProps(nextProps) { |
||||
|
if(this.props.active) { |
||||
|
this.setState({ |
||||
|
sectionHeight: 'auto', |
||||
|
}); |
||||
|
} |
||||
|
if (nextProps.active !== this.props.active) { |
||||
|
this.toggleOpen(nextProps.active); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
getHeight() { |
||||
|
const { active } = this.props; |
||||
|
return (active) ? this.accordionContent.scrollHeight : 0; |
||||
|
} |
||||
|
|
||||
|
toggleSection() { |
||||
|
const { |
||||
|
unq, |
||||
|
toggle |
||||
|
} = this.props; |
||||
|
toggle(unq); |
||||
|
} |
||||
|
|
||||
|
toggleOpen(active) { |
||||
|
const height = (active) ? `${this.accordionContent.scrollHeight}px` : 0; |
||||
|
this.setState({ |
||||
|
sectionHeight: height, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { |
||||
|
title, |
||||
|
icon, |
||||
|
children, |
||||
|
active, |
||||
|
className: propClasses |
||||
|
} = this.props; |
||||
|
|
||||
|
const contentStyles = { |
||||
|
height: this.state.sectionHeight, |
||||
|
overflow: 'hidden', |
||||
|
transition: 'height .25s ease', |
||||
|
}; |
||||
|
|
||||
|
const contentClasses = className('panel-collapse', { |
||||
|
active |
||||
|
}); |
||||
|
|
||||
|
return( |
||||
|
<div className="panel" onClick={() => this.toggleSection()}> |
||||
|
<div className="panel-heading"> |
||||
|
<a className='panel-title'> |
||||
|
<i className={icon}></i> {title} |
||||
|
</a> |
||||
|
</div> |
||||
|
<div className={contentClasses} style={contentStyles} ref={(ref) => this.accordionContent = ref}> |
||||
|
<div className="panel-body"> |
||||
|
{children} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default PanelSection; |
@ -0,0 +1,48 @@ |
|||||
|
export function checkUndef(item) { |
||||
|
return (typeof item !== 'undefined'); |
||||
|
} |
||||
|
|
||||
|
export function toggleSection(sectionId, activeSections, singleOpen) { |
||||
|
let present = null; |
||||
|
let newActiveSections = activeSections; |
||||
|
|
||||
|
newActiveSections.map((section) => { |
||||
|
if (section === sectionId) present = true; |
||||
|
return true; |
||||
|
}); |
||||
|
|
||||
|
if (!singleOpen) { |
||||
|
if (present) { |
||||
|
const pos = newActiveSections.indexOf(sectionId); |
||||
|
newActiveSections.splice(pos, 1); |
||||
|
} else { |
||||
|
newActiveSections.push(sectionId); |
||||
|
} |
||||
|
} else { |
||||
|
newActiveSections = [sectionId]; |
||||
|
} |
||||
|
|
||||
|
return newActiveSections; |
||||
|
} |
||||
|
|
||||
|
export function setupAccordion(info) { |
||||
|
const singleOpen = (checkUndef(info.singleOpen)) ? info.singleOpen : false; |
||||
|
const activeSections = []; |
||||
|
const singleChild = typeof info.kids.length === 'undefined'; |
||||
|
|
||||
|
if (!singleChild) { |
||||
|
info.kids.forEach((child, i) => { |
||||
|
const { openByDefault } = child ? child.props : false; |
||||
|
if (singleOpen && activeSections.length === 0 && openByDefault) { |
||||
|
activeSections.push(`panel-sec-${i}`); |
||||
|
} |
||||
|
if (!singleOpen && openByDefault) { |
||||
|
activeSections.push(`panel-sec-${i}`); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
activeSections, |
||||
|
}; |
||||
|
} |
Loading…
Reference in new issue