Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { FunctionComponent, HTMLProps } from 'react';
import { Omit } from '../../typeUtils';

export interface AccordionProps extends Omit<HTMLProps<HTMLUListElement>, 'aria-label'> {
'aria-label': string;
}

declare const Accordion: FunctionComponent<AccordionProps>;

export default Accordion;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly/components/Accordion/accordion.css';

const Accordion = ({ children, className, 'aria-label': ariaLabel, ...props }) => (
<dl className={css(styles.accordion, className)} aria-label={ariaLabel} {...props}>
{children}
</dl>
);

Accordion.propTypes = {
/** Content rendered inside the Accordion */
children: PropTypes.node,
/** Additional classes added to the Accordion */
className: PropTypes.string,
/** Adds accessible text to the Accordion */
'aria-label': PropTypes.string.isRequired,
/** Additional props are spread to the container <dl> */
'': PropTypes.any
};

Accordion.defaultProps = {
children: null,
className: ''
};

export default Accordion;
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
---
title: 'Accordion'
cssPrefix: 'pf-c-accordion'
---

import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core';

## Simple Accordion
```js
import React from 'react';
import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core';

class SimpleAccordion extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: ['ex-toggle2']
};
}
render() {
const toggle = id => {
const expanded = this.state.expanded;
const index = expanded.indexOf(id);
const newExpanded =
index >= 0 ? [...expanded.slice(0, index), ...expanded.slice(index + 1, expanded.length)] : [...expanded, id];
this.setState(() => ({ expanded: newExpanded }));
};

return (
<Accordion aria-label="Accordion example">
<AccordionItem aria-labelledby="ex-item1">
<AccordionToggle
onClick={() => toggle('ex-toggle1')}
isExpanded={this.state.expanded.includes('ex-toggle1')}
id="ex-toggle1"
aria-controls="ex-expand1"
>
Item One
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand1"
isHidden={!this.state.expanded.includes('ex-toggle1')}
>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item2">
<AccordionToggle
onClick={() => toggle('ex-toggle2')}
isExpanded={this.state.expanded.includes('ex-toggle2')}
id="ex-toggle2"
aria-controls="ex-expand2"
>
Item Two
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand2"
isHidden={!this.state.expanded.includes('ex-toggle2')}
>
<p>
Vivamus et tortor sed arcu congue vehicula eget et diam. Praesent nec dictum lorem. Aliquam id diam
ultrices, faucibus erat id, maximus nunc.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item3">
<AccordionToggle
onClick={() => toggle('ex-toggle3')}
isExpanded={this.state.expanded.includes('ex-toggle3')}
id="ex-toggle3"
aria-controls="ex-expand3"
>
Item Three
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand3"
isHidden={!this.state.expanded.includes('ex-toggle3')}
>
<p>Morbi vitae urna quis nunc convallis hendrerit. Aliquam congue orci quis ultricies tempus.</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item4">
<AccordionToggle
onClick={() => toggle('ex-toggle4')}
isExpanded={this.state.expanded.includes('ex-toggle4')}
id="ex-toggle4"
aria-controls="ex-expand4"
>
Item Four
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand4"
isHidden={!this.state.expanded.includes('ex-toggle4')}
>
<p>
Donec vel posuere orci. Phasellus quis tortor a ex hendrerit efficitur. Aliquam lacinia ligula pharetra,
sagittis ex ut, pellentesque diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae; Vestibulum ultricies nulla nibh. Etiam vel dui fermentum ligula ullamcorper
eleifend non quis tortor. Morbi tempus ornare tempus. Orci varius natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Mauris et velit neque. Donec ultricies condimentum mauris,
pellentesque imperdiet libero convallis convallis. Aliquam erat volutpat. Donec rutrum semper tempus.
Proin dictum imperdiet nibh, quis dapibus nulla. Integer sed tincidunt lectus, sit amet auctor eros.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item5">
<AccordionToggle
onClick={() => toggle('ex-toggle5')}
isExpanded={this.state.expanded.includes('ex-toggle5')}
id="ex-toggle5"
aria-controls="ex-expand5"
>
Item Five
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand5"
isHidden={!this.state.expanded.includes('ex-toggle5')}
>
<p>Vivamus finibus dictum ex id ultrices. Mauris dictum neque a iaculis blandit.</p>
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
}
```

## Fixed Accordion
```js
import React from 'react';
import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core';

class FixedAccordion extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: ['ex-toggle4']
};
}

render() {
const toggle = id => {
const expanded = this.state.expanded;
const index = expanded.indexOf(id);
const newExpanded =
index >= 0 ? [...expanded.slice(0, index), ...expanded.slice(index + 1, expanded.length)] : [...expanded, id];
this.setState(() => ({ expanded: newExpanded }));
};

return (
<Accordion aria-label="Accordion example">
<AccordionItem aria-labelledby="ex-item1">
<AccordionToggle
onClick={() => toggle('ex-toggle1')}
isExpanded={this.state.expanded.includes('ex-toggle1')}
id="ex-toggle1"
aria-controls="ex-expand1"
>
Item One
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand1"
isHidden={!this.state.expanded.includes('ex-toggle1')}
isFixed
>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item2">
<AccordionToggle
onClick={() => toggle('ex-toggle2')}
isExpanded={this.state.expanded.includes('ex-toggle2')}
id="ex-toggle2"
aria-controls="ex-expand2"
>
Item Two
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand2"
isHidden={!this.state.expanded.includes('ex-toggle2')}
isFixed
>
<p>
Vivamus et tortor sed arcu congue vehicula eget et diam. Praesent nec dictum lorem. Aliquam id diam
ultrices, faucibus erat id, maximus nunc.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item3">
<AccordionToggle
onClick={() => toggle('ex-toggle3')}
isExpanded={this.state.expanded.includes('ex-toggle3')}
id="ex-toggle3"
aria-controls="ex-expand3"
>
Item Three
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand3"
isHidden={!this.state.expanded.includes('ex-toggle3')}
isFixed
>
<p>Morbi vitae urna quis nunc convallis hendrerit. Aliquam congue orci quis ultricies tempus.</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item4">
<AccordionToggle
onClick={() => toggle('ex-toggle4')}
isExpanded={this.state.expanded.includes('ex-toggle4')}
id="ex-toggle4"
aria-controls="ex-expand4"
>
Item Four
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand4"
isHidden={!this.state.expanded.includes('ex-toggle4')}
isFixed
>
<p>
Donec vel posuere orci. Phasellus quis tortor a ex hendrerit efficitur. Aliquam lacinia ligula pharetra,
sagittis ex ut, pellentesque diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
posuere cubilia Curae; Vestibulum ultricies nulla nibh. Etiam vel dui fermentum ligula ullamcorper
eleifend non quis tortor. Morbi tempus ornare tempus. Orci varius natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Mauris et velit neque. Donec ultricies condimentum mauris,
pellentesque imperdiet libero convallis convallis. Aliquam erat volutpat. Donec rutrum semper tempus.
Proin dictum imperdiet nibh, quis dapibus nulla. Integer sed tincidunt lectus, sit amet auctor eros.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem aria-labelledby="ex-item5">
<AccordionToggle
onClick={() => toggle('ex-toggle5')}
isExpanded={this.state.expanded.includes('ex-toggle5')}
id="ex-toggle5"
aria-controls="ex-expand5"
>
Item Five
</AccordionToggle>
<AccordionContent
aria-label="Primary Content Details"
id="ex-expand5"
isHidden={!this.state.expanded.includes('ex-toggle5')}
isFixed
>
<p>Vivamus finibus dictum ex id ultrices. Mauris dictum neque a iaculis blandit.</p>
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import Accordion from './Accordion';
import AccordionToggle from './AccordionToggle';
import { Button } from '@patternfly/react-core';

describe('Accordion', () => {
test('Accordion default', () => {
const view = shallow(<Accordion aria-label="this is a simple accordion" />);
expect(view).toMatchSnapshot();
});

test('Toggle default with aria label', () => {
const view = mount(
<AccordionToggle aria-label="Toggle details for" aria-labelledby="ex-toggle2 ex-item2" id="ex-toggle2" />
);

expect(view.find(Button).props()['aria-label']).toBe('Toggle details for');
expect(view.find(Button).props()['aria-labelledby']).toBe(null);
expect(view.find(Button).props()['aria-expanded']).toBe(false);
expect(view.find(Button).props().id).toBe('ex-toggle2');
expect(view.find(Button).props().id).toBe('ex-toggle2');
});

test('Toggle expanded', () => {
const view = mount(<AccordionToggle aria-label="Toggle details for" id="ex-toggle2" isExpanded />);
expect(view.find(Button).props()['aria-expanded']).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FunctionComponent, HTMLProps } from 'react';
import { Omit } from '../../typeUtils';

export interface AccordionContentProps extends Omit<HTMLProps<HTMLElement>, 'aria-label'> {
isHidden: boolean;
isFixed: boolean;
'aria-label': string;
}

declare const AccordionContent: FunctionComponent<AccordionContentProps>;

export default AccordionContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/patternfly/components/Accordion/accordion.css';

const AccordionContent = ({ className, children, id, isHidden, isFixed, 'aria-label': ariaLabel, ...props }) => (
<dd
id={id}
className={css(styles.accordionExpandedContent, isFixed && styles.modifiers.fixed, className)}
hidden={isHidden}
aria-label={ariaLabel}
{...props}
>
<div className={css(styles.accordionExpandedContentBody)}>
{children}
</div>
</dd>
);

AccordionContent.propTypes = {
/** Content rendered inside the Accordion */
children: PropTypes.node,
/** Additional classes added to the Accordion content */
className: PropTypes.string,
/** Identify the AccordionContent item */
id: PropTypes.string,
/** Flag to show if the expanded content of the Accordion item is visible */
isHidden: PropTypes.bool,
/** Flag to indicate Accordion content is fixed */
isFixed: PropTypes.bool,
/** Adds accessible text to the Accordion content */
'aria-label': PropTypes.string.isRequired,
/** Additional props are spread to the container <dd> */
'': PropTypes.any
};

AccordionContent.defaultProps = {
className: '',
id: '',
isHidden: false,
isFixed: false
};

export default AccordionContent;
Loading