Skip to content

Commit

Permalink
feature(Accordion): add UncontrolledAccordion
Browse files Browse the repository at this point in the history
  • Loading branch information
Phoebe Gao committed Feb 23, 2021
1 parent b5fc217 commit 12b6906
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 13 deletions.
68 changes: 68 additions & 0 deletions docs/lib/Components/AccordionPage.js
Expand Up @@ -7,6 +7,9 @@ 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 (
Expand All @@ -24,6 +27,71 @@ export default class AccordionPage extends React.Component {
<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,
Expand Down
15 changes: 10 additions & 5 deletions docs/lib/examples/Accordion.js
@@ -1,15 +1,20 @@
import React from 'react';
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>
<Accordion openId={openId} toggle={toggle}>
<AccordionItem>
<AccordionHeader targetId="1">
Accordion Item 1
</AccordionHeader>
<AccordionBody id="1">
<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>
Expand All @@ -18,7 +23,7 @@ const Example = (props) => {
<AccordionHeader targetId="2">
Accordion Item 2
</AccordionHeader>
<AccordionBody id="2">
<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>
Expand All @@ -27,7 +32,7 @@ const Example = (props) => {
<AccordionHeader targetId="3">
Accordion Item 3
</AccordionHeader>
<AccordionBody id="3">
<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>
Expand Down
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;
11 changes: 6 additions & 5 deletions src/Accordion.js
@@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { mapToCssModules, tagPropType } from './utils';
Expand All @@ -14,6 +14,8 @@ const propTypes = {
PropTypes.func,
]),
children: PropTypes.node,
openId: PropTypes.string.isRequired,
toggle: PropTypes.func.isRequired,
};

const defaultProps = {
Expand All @@ -22,6 +24,8 @@ const defaultProps = {

const Accordion = (props) => {
const {
openId,
toggle,
className,
cssModule,
tag: Tag,
Expand All @@ -33,12 +37,9 @@ const Accordion = (props) => {
'accordion',
), cssModule);

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

return (
Expand Down
34 changes: 34 additions & 0 deletions src/UncontrolledAccordion.js
@@ -0,0 +1,34 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { tagPropType } from './utils';
import Accordion from './Accordion';

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

const defaultProps = {
tag: 'div'
};

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

return <Accordion {...props} openId={openId} toggle={toggle} />;
};

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

export default UncntrolledAccordion;
6 changes: 3 additions & 3 deletions src/__tests__/Accordion.spec.js
Expand Up @@ -4,19 +4,19 @@ import { Accordion } from '../';

describe('Accordion', () => {
it('should render with "accordion" class', () => {
const wrapper = mount(<Accordion />);
const wrapper = mount(<Accordion openId="this accordion" togggle={() => {}} />);

expect(wrapper.find('.accordion').length).toBe(1);
});

it('should render additional classes', () => {
const wrapper = mount(<Accordion className="other" />);
const wrapper = mount(<Accordion className="other" openId="this accordion" togggle={() => {}} />);

expect(wrapper.find('.accordion').hasClass('other')).toBe(true);
});

it('should render custom tag', () => {
const wrapper = mount(<Accordion tag="main" />);
const wrapper = mount(<Accordion tag="main" openId="this accordion" togggle={() => {}} />);

expect(wrapper.find('main.accordion').length).toBe(1);
});
Expand Down
23 changes: 23 additions & 0 deletions src/__tests__/UncontrolledAccordion.spec.js
@@ -0,0 +1,23 @@
import React from 'react';
import { mount } from 'enzyme';
import { UncontrolledAccordion } from '../';

describe('Accordion', () => {
it('should render with "accordion" class', () => {
const wrapper = mount(<UncontrolledAccordion />);

expect(wrapper.find('.accordion').length).toBe(1);
});

it('should render additional classes', () => {
const wrapper = mount(<UncontrolledAccordion className="other" />);

expect(wrapper.find('.accordion').hasClass('other')).toBe(true);
});

it('should render custom tag', () => {
const wrapper = mount(<UncontrolledAccordion tag="main" />);

expect(wrapper.find('main.accordion').length).toBe(1);
});
});
1 change: 1 addition & 0 deletions src/index.js
Expand Up @@ -22,6 +22,7 @@ export DropdownToggle from './DropdownToggle';
export { DropdownContext } from './DropdownContext';
export Fade from './Fade';
export Accordion from './Accordion';
export UncontrolledAccordion from './UncontrolledAccordion';
export AccordionHeader from './AccordionHeader';
export AccordionItem from './AccordionItem';
export AccordionBody from './AccordionBody';
Expand Down

0 comments on commit 12b6906

Please sign in to comment.