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(Accordion): added toggle alignment functionality #9877

Merged
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
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>
);
};
Loading