From 1f57be853f9b1ace7a78c821affddf6afde5b87c Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Tue, 12 Dec 2023 08:42:02 -0500 Subject: [PATCH 1/2] feat(Accordion): added toggle alignment functionality --- .../src/components/Accordion/Accordion.tsx | 7 +- .../components/Accordion/AccordionContext.ts | 1 + .../components/Accordion/AccordionToggle.tsx | 55 +++++---- .../Accordion/__tests__/Accordion.test.tsx | 12 ++ .../__tests__/AccordionToggle.test.tsx | 28 +++++ .../Accordion/examples/Accordion.md | 5 + .../examples/AccordionToggleIconAtStart.tsx | 107 ++++++++++++++++++ 7 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx diff --git a/packages/react-core/src/components/Accordion/Accordion.tsx b/packages/react-core/src/components/Accordion/Accordion.tsx index 386106770ed..c82e263fc5d 100644 --- a/packages/react-core/src/components/Accordion/Accordion.tsx +++ b/packages/react-core/src/components/Accordion/Accordion.tsx @@ -18,6 +18,8 @@ export interface AccordionProps extends React.HTMLProps { isBordered?: boolean; /** Display size variant. */ displaySize?: 'default' | 'lg'; + /** Alignment of the toggle icon. */ + toggleAlignment?: 'start' | 'end'; } export const Accordion: React.FunctionComponent = ({ @@ -28,6 +30,7 @@ export const Accordion: React.FunctionComponent = ({ asDefinitionList = true, isBordered = false, displaySize = 'default', + toggleAlignment = 'end', ...props }: AccordionProps) => { const AccordionList: any = asDefinitionList ? 'dl' : 'div'; @@ -36,6 +39,7 @@ export const Accordion: React.FunctionComponent = ({ className={css( styles.accordion, isBordered && styles.modifiers.bordered, + toggleAlignment === 'start' && styles.modifiers.toggleStart, displaySize === 'lg' && styles.modifiers.displayLg, className )} @@ -46,7 +50,8 @@ export const Accordion: React.FunctionComponent = ({ {children} diff --git a/packages/react-core/src/components/Accordion/AccordionContext.ts b/packages/react-core/src/components/Accordion/AccordionContext.ts index 8df38f401fa..dd3de4e5443 100644 --- a/packages/react-core/src/components/Accordion/AccordionContext.ts +++ b/packages/react-core/src/components/Accordion/AccordionContext.ts @@ -3,6 +3,7 @@ import * as React from 'react'; interface AccordionContextProps { ContentContainer: React.ElementType; ToggleContainer: React.ElementType; + toggleAlignment: 'start' | 'end'; } export const AccordionContext = React.createContext>({}); diff --git a/packages/react-core/src/components/Accordion/AccordionToggle.tsx b/packages/react-core/src/components/Accordion/AccordionToggle.tsx index a2ec5b28124..b21d8f57b8b 100644 --- a/packages/react-core/src/components/Accordion/AccordionToggle.tsx +++ b/packages/react-core/src/components/Accordion/AccordionToggle.tsx @@ -25,27 +25,36 @@ export const AccordionToggle: React.FunctionComponent = ({ children = null, component, ...props -}: AccordionToggleProps) => ( - - {({ ToggleContainer }) => { - const Container = component || ToggleContainer; - return ( - - - - ); - }} - -); +}: AccordionToggleProps) => { + const renderToggleIcon = () => ( + + + + ); + + return ( + + {({ ToggleContainer, toggleAlignment }) => { + const Container = component || ToggleContainer; + const isToggleStartAligned = toggleAlignment === 'start'; + + return ( + + + + ); + }} + + ); +}; AccordionToggle.displayName = 'AccordionToggle'; diff --git a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx index c5abf0c8c68..6770d1229d1 100644 --- a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx @@ -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(Test); + + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.toggleStart); +}); + +test(`Renders with class ${styles.modifiers.toggleStart} when toggleAlignment='start'`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.toggleStart); +}); + test('Matches the snapshot', () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx index dd39f0359ea..3cd077bf108 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx @@ -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( + + + Test + + + ); + + const toggle = screen.getByRole('button'); + + expect(toggle.firstChild).toHaveClass(styles.accordionToggleText); +}); + +test('Renders toggle icon before toggle text when toggleAlignment from context = "start"', () => { + render( + + + Test + + + ); + + const toggle = screen.getByRole('button'); + + expect(toggle.firstChild).toHaveClass(styles.accordionToggleIcon); +}); + test('Matches the snapshot', () => { const { asFragment } = render( diff --git a/packages/react-core/src/components/Accordion/examples/Accordion.md b/packages/react-core/src/components/Accordion/examples/Accordion.md index aea98f99b8e..cac3b5cc699 100644 --- a/packages/react-core/src/components/Accordion/examples/Accordion.md +++ b/packages/react-core/src/components/Accordion/examples/Accordion.md @@ -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" +``` \ No newline at end of file diff --git a/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx new file mode 100644 index 00000000000..2607bdd1793 --- /dev/null +++ b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx @@ -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 ( + + + { + onToggle('start-toggle-toggle1'); + }} + isExpanded={expanded === 'start-toggle-toggle1'} + id="start-toggle-toggle1" + > + Item one + + +

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. +

+
+
+ + + { + onToggle('start-toggle-toggle2'); + }} + isExpanded={expanded === 'start-toggle-toggle2'} + id="start-toggle-toggle2" + > + Item two + + +

+ Vivamus et tortor sed arcu congue vehicula eget et diam. Praesent nec dictum lorem. Aliquam id diam + ultrices, faucibus erat id, maximus nunc. +

+
+
+ + + { + onToggle('start-toggle-toggle3'); + }} + isExpanded={expanded === 'start-toggle-toggle3'} + id="start-toggle-toggle3" + > + Item three + + +

Morbi vitae urna quis nunc convallis hendrerit. Aliquam congue orci quis ultricies tempus.

+
+
+ + + { + onToggle('start-toggle-toggle4'); + }} + isExpanded={expanded === 'start-toggle-toggle4'} + id="start-toggle-toggle4" + > + Item four + + +

+ 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. +

+
+
+ + + { + onToggle('start-toggle-toggle5'); + }} + isExpanded={expanded === 'start-toggle-toggle5'} + id="start-toggle-toggle5" + > + Item five + + +

Vivamus finibus dictum ex id ultrices. Mauris dictum neque a iaculis blandit.

+
+
+
+ ); +}; From 552cf9baba72b7017308fc0f775796044b43d84a Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Tue, 12 Dec 2023 15:47:38 -0500 Subject: [PATCH 2/2] Updated prop name and description --- .../react-core/src/components/Accordion/Accordion.tsx | 10 +++++----- .../src/components/Accordion/AccordionContext.ts | 2 +- .../src/components/Accordion/AccordionToggle.tsx | 8 ++++---- .../components/Accordion/__tests__/Accordion.test.tsx | 4 ++-- .../Accordion/__tests__/AccordionToggle.test.tsx | 4 ++-- .../Accordion/examples/AccordionToggleIconAtStart.tsx | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/react-core/src/components/Accordion/Accordion.tsx b/packages/react-core/src/components/Accordion/Accordion.tsx index c82e263fc5d..fedc1e21ee0 100644 --- a/packages/react-core/src/components/Accordion/Accordion.tsx +++ b/packages/react-core/src/components/Accordion/Accordion.tsx @@ -18,8 +18,8 @@ export interface AccordionProps extends React.HTMLProps { isBordered?: boolean; /** Display size variant. */ displaySize?: 'default' | 'lg'; - /** Alignment of the toggle icon. */ - toggleAlignment?: 'start' | 'end'; + /** Sets the toggle icon position for all accordion toggles. */ + togglePosition?: 'start' | 'end'; } export const Accordion: React.FunctionComponent = ({ @@ -30,7 +30,7 @@ export const Accordion: React.FunctionComponent = ({ asDefinitionList = true, isBordered = false, displaySize = 'default', - toggleAlignment = 'end', + togglePosition = 'end', ...props }: AccordionProps) => { const AccordionList: any = asDefinitionList ? 'dl' : 'div'; @@ -39,7 +39,7 @@ export const Accordion: React.FunctionComponent = ({ className={css( styles.accordion, isBordered && styles.modifiers.bordered, - toggleAlignment === 'start' && styles.modifiers.toggleStart, + togglePosition === 'start' && styles.modifiers.toggleStart, displaySize === 'lg' && styles.modifiers.displayLg, className )} @@ -51,7 +51,7 @@ export const Accordion: React.FunctionComponent = ({ value={{ ContentContainer: asDefinitionList ? 'dd' : 'div', ToggleContainer: asDefinitionList ? 'dt' : headingLevel, - toggleAlignment + togglePosition }} > {children} diff --git a/packages/react-core/src/components/Accordion/AccordionContext.ts b/packages/react-core/src/components/Accordion/AccordionContext.ts index dd3de4e5443..99ba8a5b6c4 100644 --- a/packages/react-core/src/components/Accordion/AccordionContext.ts +++ b/packages/react-core/src/components/Accordion/AccordionContext.ts @@ -3,7 +3,7 @@ import * as React from 'react'; interface AccordionContextProps { ContentContainer: React.ElementType; ToggleContainer: React.ElementType; - toggleAlignment: 'start' | 'end'; + togglePosition: 'start' | 'end'; } export const AccordionContext = React.createContext>({}); diff --git a/packages/react-core/src/components/Accordion/AccordionToggle.tsx b/packages/react-core/src/components/Accordion/AccordionToggle.tsx index b21d8f57b8b..dd9438cb0a9 100644 --- a/packages/react-core/src/components/Accordion/AccordionToggle.tsx +++ b/packages/react-core/src/components/Accordion/AccordionToggle.tsx @@ -34,9 +34,9 @@ export const AccordionToggle: React.FunctionComponent = ({ return ( - {({ ToggleContainer, toggleAlignment }) => { + {({ ToggleContainer, togglePosition }) => { const Container = component || ToggleContainer; - const isToggleStartAligned = toggleAlignment === 'start'; + const isToggleStartPositioned = togglePosition === 'start'; return ( @@ -47,9 +47,9 @@ export const AccordionToggle: React.FunctionComponent = ({ type="button" {...props} > - {isToggleStartAligned && renderToggleIcon()} + {isToggleStartPositioned && renderToggleIcon()} {children} - {!isToggleStartAligned && renderToggleIcon()} + {!isToggleStartPositioned && renderToggleIcon()} ); diff --git a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx index 6770d1229d1..4d347f5d0eb 100644 --- a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx @@ -141,8 +141,8 @@ test(`Renders without class ${styles.modifiers.toggleStart} by default`, () => { expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.toggleStart); }); -test(`Renders with class ${styles.modifiers.toggleStart} when toggleAlignment='start'`, () => { - render(Test); +test(`Renders with class ${styles.modifiers.toggleStart} when togglePosition='start'`, () => { + render(Test); expect(screen.getByText('Test')).toHaveClass(styles.modifiers.toggleStart); }); diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx index 3cd077bf108..9610a0b5af3 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx @@ -169,9 +169,9 @@ test('Renders toggle text before toggle icon by default', () => { expect(toggle.firstChild).toHaveClass(styles.accordionToggleText); }); -test('Renders toggle icon before toggle text when toggleAlignment from context = "start"', () => { +test('Renders toggle icon before toggle text when togglePosition from context = "start"', () => { render( - + Test diff --git a/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx index 2607bdd1793..9815346c0bc 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx @@ -13,7 +13,7 @@ export const AccordionToggleIconAtStart: React.FunctionComponent = () => { }; return ( - + {