Skip to content

Commit

Permalink
feat(Accordion): added toggle alignment functionality (#9877)
Browse files Browse the repository at this point in the history
* feat(Accordion): added toggle alignment functionality

* Updated prop name and description
  • Loading branch information
thatblindgeye authored Dec 20, 2023
1 parent 2ae9642 commit 58e0071
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 24 deletions.
7 changes: 6 additions & 1 deletion packages/react-core/src/components/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface AccordionProps extends React.HTMLProps<HTMLDListElement> {
isBordered?: boolean;
/** Display size variant. */
displaySize?: 'default' | 'lg';
/** Sets the toggle icon position for all accordion toggles. */
togglePosition?: 'start' | 'end';
}

export const Accordion: React.FunctionComponent<AccordionProps> = ({
Expand All @@ -28,6 +30,7 @@ export const Accordion: React.FunctionComponent<AccordionProps> = ({
asDefinitionList = true,
isBordered = false,
displaySize = 'default',
togglePosition = 'end',
...props
}: AccordionProps) => {
const AccordionList: any = asDefinitionList ? 'dl' : 'div';
Expand All @@ -36,6 +39,7 @@ export const Accordion: React.FunctionComponent<AccordionProps> = ({
className={css(
styles.accordion,
isBordered && styles.modifiers.bordered,
togglePosition === 'start' && styles.modifiers.toggleStart,
displaySize === 'lg' && styles.modifiers.displayLg,
className
)}
Expand All @@ -46,7 +50,8 @@ export const Accordion: React.FunctionComponent<AccordionProps> = ({
<AccordionContext.Provider
value={{
ContentContainer: asDefinitionList ? 'dd' : 'div',
ToggleContainer: asDefinitionList ? 'dt' : headingLevel
ToggleContainer: asDefinitionList ? 'dt' : headingLevel,
togglePosition
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react';
interface AccordionContextProps {
ContentContainer: React.ElementType;
ToggleContainer: React.ElementType;
togglePosition: 'start' | 'end';
}

export const AccordionContext = React.createContext<Partial<AccordionContextProps>>({});
55 changes: 32 additions & 23 deletions packages/react-core/src/components/Accordion/AccordionToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,36 @@ export const AccordionToggle: React.FunctionComponent<AccordionToggleProps> = ({
children = null,
component,
...props
}: AccordionToggleProps) => (
<AccordionContext.Consumer>
{({ ToggleContainer }) => {
const Container = component || ToggleContainer;
return (
<Container>
<button
id={id}
className={css(styles.accordionToggle, isExpanded && styles.modifiers.expanded, className)}
aria-expanded={isExpanded}
type="button"
{...props}
>
<span className={css(styles.accordionToggleText)}>{children}</span>
<span className={css(styles.accordionToggleIcon)}>
<AngleRightIcon />
</span>
</button>
</Container>
);
}}
</AccordionContext.Consumer>
);
}: AccordionToggleProps) => {
const renderToggleIcon = () => (
<span className={css(styles.accordionToggleIcon)}>
<AngleRightIcon />
</span>
);

return (
<AccordionContext.Consumer>
{({ ToggleContainer, togglePosition }) => {
const Container = component || ToggleContainer;
const isToggleStartPositioned = togglePosition === 'start';

return (
<Container>
<button
id={id}
className={css(styles.accordionToggle, isExpanded && styles.modifiers.expanded, className)}
aria-expanded={isExpanded}
type="button"
{...props}
>
{isToggleStartPositioned && renderToggleIcon()}
<span className={css(styles.accordionToggleText)}>{children}</span>
{!isToggleStartPositioned && renderToggleIcon()}
</button>
</Container>
);
}}
</AccordionContext.Consumer>
);
};
AccordionToggle.displayName = 'AccordionToggle';
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ test('Renders with pf-m-display-lg when displaySize="lg"', () => {
expect(screen.getByText('Test')).toHaveClass('pf-m-display-lg');
});

test(`Renders without class ${styles.modifiers.toggleStart} by default`, () => {
render(<Accordion>Test</Accordion>);

expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.toggleStart);
});

test(`Renders with class ${styles.modifiers.toggleStart} when togglePosition='start'`, () => {
render(<Accordion togglePosition="start">Test</Accordion>);

expect(screen.getByText('Test')).toHaveClass(styles.modifiers.toggleStart);
});

test('Matches the snapshot', () => {
const { asFragment } = render(<Accordion aria-label="this is a simple accordion" />);
expect(asFragment()).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,34 @@ test('Renders the toggle with pf-m-expanded and aria-expanded=true when isExpand
expect(toggle).toHaveAttribute('aria-expanded', 'true');
});

test('Renders toggle text before toggle icon by default', () => {
render(
<AccordionContext.Provider value={{ ToggleContainer: 'h3' }}>
<AccordionToggle id="accordion-toggle" isExpanded>
Test
</AccordionToggle>
</AccordionContext.Provider>
);

const toggle = screen.getByRole('button');

expect(toggle.firstChild).toHaveClass(styles.accordionToggleText);
});

test('Renders toggle icon before toggle text when togglePosition from context = "start"', () => {
render(
<AccordionContext.Provider value={{ ToggleContainer: 'h3', togglePosition: 'start' }}>
<AccordionToggle id="accordion-toggle" isExpanded>
Test
</AccordionToggle>
</AccordionContext.Provider>
);

const toggle = screen.getByRole('button');

expect(toggle.firstChild).toHaveClass(styles.accordionToggleIcon);
});

test('Matches the snapshot', () => {
const { asFragment } = render(
<AccordionContext.Provider value={{ ToggleContainer: 'h3' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-i

```ts file="./AccordionBordered.tsx"
```

### Toggle icon at start

```ts file="./AccordionToggleIconAtStart.tsx"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react';
import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core';

export const AccordionToggleIconAtStart: React.FunctionComponent = () => {
const [expanded, setExpanded] = React.useState('start-toggle-toggle2');

const onToggle = (id: string) => {
if (id === expanded) {
setExpanded('');
} else {
setExpanded(id);
}
};

return (
<Accordion togglePosition="start">
<AccordionItem>
<AccordionToggle
onClick={() => {
onToggle('start-toggle-toggle1');
}}
isExpanded={expanded === 'start-toggle-toggle1'}
id="start-toggle-toggle1"
>
Item one
</AccordionToggle>
<AccordionContent id="start-toggle-expand1" isHidden={expanded !== 'start-toggle-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>
<AccordionToggle
onClick={() => {
onToggle('start-toggle-toggle2');
}}
isExpanded={expanded === 'start-toggle-toggle2'}
id="start-toggle-toggle2"
>
Item two
</AccordionToggle>
<AccordionContent id="start-toggle-expand2" isHidden={expanded !== 'start-toggle-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>
<AccordionToggle
onClick={() => {
onToggle('start-toggle-toggle3');
}}
isExpanded={expanded === 'start-toggle-toggle3'}
id="start-toggle-toggle3"
>
Item three
</AccordionToggle>
<AccordionContent id="start-toggle-expand3" isHidden={expanded !== 'start-toggle-toggle3'}>
<p>Morbi vitae urna quis nunc convallis hendrerit. Aliquam congue orci quis ultricies tempus.</p>
</AccordionContent>
</AccordionItem>

<AccordionItem>
<AccordionToggle
onClick={() => {
onToggle('start-toggle-toggle4');
}}
isExpanded={expanded === 'start-toggle-toggle4'}
id="start-toggle-toggle4"
>
Item four
</AccordionToggle>
<AccordionContent id="start-toggle-expand4" isHidden={expanded !== 'start-toggle-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>
<AccordionToggle
onClick={() => {
onToggle('start-toggle-toggle5');
}}
isExpanded={expanded === 'start-toggle-toggle5'}
id="start-toggle-toggle5"
>
Item five
</AccordionToggle>
<AccordionContent id="start-toggle-expand5" isHidden={expanded !== 'start-toggle-toggle5'}>
<p>Vivamus finibus dictum ex id ultrices. Mauris dictum neque a iaculis blandit.</p>
</AccordionContent>
</AccordionItem>
</Accordion>
);
};

0 comments on commit 58e0071

Please sign in to comment.