Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(bs5) accordion #2105

Merged
merged 6 commits into from Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
149 changes: 149 additions & 0 deletions docs/lib/Components/AccordionPage.js
@@ -0,0 +1,149 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
import React from 'react';
import { PrismCode } from 'react-prism';
import PageTitle from '../UI/PageTitle';
import SectionTitle from '../UI/SectionTitle';

import AccordionExample from '../examples/Accordion';
const AccordionExampleSource = require('!!raw-loader!../examples/Accordion');

import UncontrolledAccordionExample from '../examples/UncontrolledAccordion';
const UncontrolledAccordionExampleSource = require('!!raw-loader!../examples/UncontrolledAccordion');

export default class AccordionPage extends React.Component {
render() {
return (
<div>
<PageTitle title="Accordion" />
<div className="docs-example">
<AccordionExample />
</div>
<pre>
<PrismCode className="language-jsx">
{ AccordionExampleSource}
</PrismCode>
</pre>
<SectionTitle>Properties</SectionTitle>
<pre>
<PrismCode className="language-jsx">
{`Accordion.propTypes = {
openId: Proptypes.string.isRequired,
toggle: Proptypes.func.isRequired,
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
};

AccordionBody.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
accordionId: PropTypes.string.isRequired,
};

AccordionHeader.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
targetId: PropTypes.string.isRequired,
};

AccordionItem.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
};
`}
</PrismCode>
</pre>
<div className="docs-example">
<UncontrolledAccordionExample />
</div>
<pre>
<PrismCode className="language-jsx">
{ UncontrolledAccordionExampleSource }
</PrismCode>
</pre>
<SectionTitle>Properties</SectionTitle>
<pre>
<PrismCode className="language-jsx">
{`UncontrolledAccordion.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
};

AccordionBody.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
accordionId: PropTypes.string.isRequired,
};

AccordionHeader.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
targetId: PropTypes.string.isRequired,
};

AccordionItem.propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
};
`}
</PrismCode>
</pre>
</div>
);
}
}
4 changes: 4 additions & 0 deletions docs/lib/Components/index.js
Expand Up @@ -2,6 +2,10 @@ import React from 'react';
import Content from '../UI/Content';

const items = [
{
name: 'Accordion',
to: '/components/accordion/'
},
{
name: 'Alerts',
to: '/components/alerts/'
Expand Down
45 changes: 45 additions & 0 deletions docs/lib/examples/Accordion.js
@@ -0,0 +1,45 @@
import React, { useState } from 'react';
import { Accordion, AccordionBody, AccordionHeader, AccordionItem } from 'reactstrap';

const Example = (props) => {
const [openId, setOpenId] = useState();
const toggle = (id) => {
openId === id ? setOpenId(undefined) : setOpenId(id);
};

return (
<div>
<Accordion openId={openId} toggle={toggle}>
<AccordionItem>
<AccordionHeader targetId="1">
Accordion Item 1
</AccordionHeader>
<AccordionBody accordionId="1">
<strong>This is the first item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
<AccordionItem>
<AccordionHeader targetId="2">
Accordion Item 2
</AccordionHeader>
<AccordionBody accordionId="2">
<strong>This is the second item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
<AccordionItem>
<AccordionHeader targetId="3">
Accordion Item 3
</AccordionHeader>
<AccordionBody accordionId="3">
<strong>This is the third item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
</Accordion>
</div>
);
};

export default Example;
40 changes: 40 additions & 0 deletions docs/lib/examples/UncontrolledAccordion.js
@@ -0,0 +1,40 @@
import React from 'react';
import { UncontrolledAccordion, AccordionBody, AccordionHeader, AccordionItem } from 'reactstrap';

const Example = (props) => {
return (
<div>
<UncontrolledAccordion>
<AccordionItem>
<AccordionHeader targetId="1">
Accordion Item 1
</AccordionHeader>
<AccordionBody accordionId="1">
<strong>This is the first item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
<AccordionItem>
<AccordionHeader targetId="2">
Accordion Item 2
</AccordionHeader>
<AccordionBody accordionId="2">
<strong>This is the second item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
<AccordionItem>
<AccordionHeader targetId="3">
Accordion Item 3
</AccordionHeader>
<AccordionBody accordionId="3">
<strong>This is the third item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem>
</UncontrolledAccordion>
</div>
);
};

export default Example;
4 changes: 3 additions & 1 deletion docs/lib/routes.js
Expand Up @@ -17,6 +17,7 @@ import PopoversPage from './Components/PopoversPage';
import ProgressPage from './Components/ProgressPage';
import TooltipsPage from './Components/TooltipsPage';
import BadgePage from './Components/BadgePage';
import AccordionPage from './Components/AccordionPage';
import MediaPage from './Components/MediaPage';
import ModalsPage from './Components/ModalsPage';
import CardPage from './Components/CardPage';
Expand All @@ -41,7 +42,8 @@ const routes = (
<Route path="/" component={UI.Layout}>
<IndexRoute component={Home} />
<Route path="/components/" component={Components}>
<IndexRedirect to="alerts/" />
kyletsang marked this conversation as resolved.
Show resolved Hide resolved
<IndexRedirect to="accordion/" />
<Route path="accordion/" component={AccordionPage} />
<Route path="breadcrumbs/" component={BreadcrumbsPage} />
<Route path="buttons/" component={ButtonsPage} />
<Route path="button-group/" component={ButtonGroupPage} />
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -266,7 +266,7 @@
"react-transition-group": "^2.3.1"
},
"peerDependencies": {
"react": ">=16.3.0",
"react": ">=16.8.0",
"react-dom": ">=16.3.0"
},
"devDependencies": {
Expand Down Expand Up @@ -306,7 +306,7 @@
"mini-css-extract-plugin": "^0.9.0",
"ncp": "^2.0.0",
"raw-loader": "^1.0.0",
"react": "^16.3.2",
"react": "^16.8.0",
"react-app-rewired": "^1.6.2",
"react-dom": "^16.3.2",
"react-helmet": "^5.0.3",
Expand Down
55 changes: 55 additions & 0 deletions src/Accordion.js
@@ -0,0 +1,55 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';
import { AccordionContext } from './AccordionContext';

const propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
openId: PropTypes.string.isRequired,
toggle: PropTypes.func.isRequired,
};

const defaultProps = {
tag: 'div'
};

const Accordion = (props) => {
const {
openId,
toggle,
className,
cssModule,
tag: Tag,
innerRef,
...attributes
} = props;
const classes = mapToCssModules(classNames(
className,
'accordion',
), cssModule);

const accordionContext = useMemo(() => ({
openId,
toggle,
}));

return (
<AccordionContext.Provider value={accordionContext}>
<Tag {...attributes} className={classes} ref={innerRef} />
</AccordionContext.Provider>
);
};

Accordion.propTypes = propTypes;
Accordion.defaultProps = defaultProps;

export default Accordion;
53 changes: 53 additions & 0 deletions src/AccordionBody.js
@@ -0,0 +1,53 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';
import Collapse from './Collapse';
import { AccordionContext } from './AccordionContext';

const propTypes = {
tag: tagPropType,
className: PropTypes.string,
cssModule: PropTypes.object,
innerRef: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.func,
]),
children: PropTypes.node,
accordionId: PropTypes.string.isRequired,
};

const defaultProps = {
tag: 'div'
};

const AccordionItem = (props) => {
const {
className,
cssModule,
tag: Tag,
innerRef,
children,
accordionId,
...attributes
} = props;

const { openId } = useContext(AccordionContext);

const classes = mapToCssModules(classNames(
className,
'accordion-collapse',
), cssModule);

return (
phwebi marked this conversation as resolved.
Show resolved Hide resolved
<Collapse {...attributes} className={classes} ref={innerRef} isOpen={openId === accordionId}>
<Tag className="accordion-body">{children}</Tag>
</Collapse>
);
};

AccordionItem.propTypes = propTypes;
AccordionItem.defaultProps = defaultProps;

export default AccordionItem;