62
app/components/Accordion/Accordion.js
Executable file
62
app/components/Accordion/Accordion.js
Executable file
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Card from './../Card';
|
||||
|
||||
import { Provider } from './context';
|
||||
|
||||
export class Accordion extends React.Component {
|
||||
static propTypes = {
|
||||
initialOpen: PropTypes.bool,
|
||||
onToggle: PropTypes.func,
|
||||
open: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isOpen: props.initialOpen
|
||||
}
|
||||
|
||||
if (props.open !== 'undefined' && props.onToggle === 'undefined') {
|
||||
throw "Accordion: props.open has to be used combined with props.onToggle " +
|
||||
"use props.initialOpen to create an uncontrolled Accordion."
|
||||
}
|
||||
}
|
||||
|
||||
toggleHandler() {
|
||||
const { onToggle } = this.props;
|
||||
|
||||
if (!onToggle) {
|
||||
this.setState({ isOpen: !this.state.isOpen });
|
||||
} else {
|
||||
this.onToggle(!this.props.open);
|
||||
}
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
return !this.props.onToggle ?
|
||||
this.state.isOpen : this.props.open;
|
||||
}
|
||||
|
||||
render() {
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const { className, children, initialOpen, ...otherProps } = this.props;
|
||||
|
||||
return (
|
||||
<Provider
|
||||
value={{
|
||||
onToggle: this.toggleHandler.bind(this),
|
||||
isOpen: this.isOpen()
|
||||
}}
|
||||
>
|
||||
<Card className={ className } { ...otherProps }>
|
||||
{ children }
|
||||
</Card>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
24
app/components/Accordion/AccordionBody.js
Executable file
24
app/components/Accordion/AccordionBody.js
Executable file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Collapse, CardBody } from 'reactstrap';
|
||||
|
||||
import { Consumer } from './context';
|
||||
|
||||
export const AccordionBody = (props) => (
|
||||
<Consumer>
|
||||
{
|
||||
({ isOpen }) => (
|
||||
<Collapse isOpen={ isOpen }>
|
||||
<CardBody className={ classNames(props.className, 'pt-0') }>
|
||||
{ props.children }
|
||||
</CardBody>
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
</Consumer>
|
||||
);
|
||||
AccordionBody.propTypes = {
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string
|
||||
};
|
33
app/components/Accordion/AccordionHeader.js
Executable file
33
app/components/Accordion/AccordionHeader.js
Executable file
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import CardHeader from './../CardHeader';
|
||||
|
||||
import { Consumer } from './context';
|
||||
import classes from './AccordionHeader.scss';
|
||||
|
||||
export const AccordionHeader = (props) => (
|
||||
<Consumer>
|
||||
{
|
||||
({ onToggle }) => (
|
||||
<CardHeader
|
||||
className={
|
||||
classNames(
|
||||
props.className,
|
||||
classes.header
|
||||
)
|
||||
}
|
||||
onClick={ onToggle}
|
||||
>
|
||||
{ props.children }
|
||||
</CardHeader>
|
||||
)
|
||||
}
|
||||
</Consumer>
|
||||
);
|
||||
AccordionHeader.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
className: PropTypes.string
|
||||
};
|
14
app/components/Accordion/AccordionHeader.scss
Executable file
14
app/components/Accordion/AccordionHeader.scss
Executable file
@@ -0,0 +1,14 @@
|
||||
@import '../../styles/variables';
|
||||
|
||||
div.header {
|
||||
background: none;
|
||||
border-bottom: none;
|
||||
cursor: pointer;
|
||||
color: $link-color;
|
||||
text-decoration: $link-decoration;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover-color;
|
||||
text-decoration: $link-hover-decoration;
|
||||
}
|
||||
}
|
27
app/components/Accordion/AccordionIndicator.js
Executable file
27
app/components/Accordion/AccordionIndicator.js
Executable file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Consumer } from './context';
|
||||
|
||||
export const AccordionIndicator = (props) => (
|
||||
<Consumer>
|
||||
{
|
||||
({ isOpen }) => isOpen ?
|
||||
React.cloneElement(props.open, {
|
||||
className: classNames(props.className, props.open.props.className)
|
||||
}) : React.cloneElement(props.closed, {
|
||||
className: classNames(props.className, props.closed.props.className)
|
||||
})
|
||||
}
|
||||
</Consumer>
|
||||
);
|
||||
AccordionIndicator.propTypes = {
|
||||
open: PropTypes.node,
|
||||
closed: PropTypes.node,
|
||||
className: PropTypes.string
|
||||
}
|
||||
AccordionIndicator.defaultProps = {
|
||||
open: <i className="fa fa-fw fa-minus"></i>,
|
||||
closed: <i className="fa fa-fw fa-plus"></i>
|
||||
}
|
8
app/components/Accordion/context.js
Executable file
8
app/components/Accordion/context.js
Executable file
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
const { Provider, Consumer } = React.createContext();
|
||||
|
||||
export {
|
||||
Provider,
|
||||
Consumer
|
||||
};
|
10
app/components/Accordion/index.js
Executable file
10
app/components/Accordion/index.js
Executable file
@@ -0,0 +1,10 @@
|
||||
import { Accordion } from './Accordion';
|
||||
import { AccordionBody } from './AccordionBody';
|
||||
import { AccordionHeader } from './AccordionHeader';
|
||||
import { AccordionIndicator } from './AccordionIndicator';
|
||||
|
||||
Accordion.Body = AccordionBody;
|
||||
Accordion.Header = AccordionHeader;
|
||||
Accordion.Indicator = AccordionIndicator;
|
||||
|
||||
export default Accordion;
|
Reference in New Issue
Block a user