diff --git a/src/components/Accordion/Accordion.module.css b/src/components/Accordion/Accordion.module.css index e2361f51e..cad5877f9 100644 --- a/src/components/Accordion/Accordion.module.css +++ b/src/components/Accordion/Accordion.module.css @@ -29,6 +29,10 @@ height: 3.375rem; } +.accordion-button--empty { + pointer-events: none; +} + /** * Small variant. */ @@ -105,6 +109,10 @@ color: var(--eds-theme-color-text-neutral-strong); } +.accordion-panel--hidden { + padding: 0; +} + /** * Small variant. */ diff --git a/src/components/Accordion/Accordion.stories.tsx b/src/components/Accordion/Accordion.stories.tsx index 5940ca5da..b50c0b3d3 100644 --- a/src/components/Accordion/Accordion.stories.tsx +++ b/src/components/Accordion/Accordion.stories.tsx @@ -149,6 +149,51 @@ export const DefaultOpen: StoryObj = { }, }; +export const EmptyStackedOpen: StoryObj = { + args: { + children: ( + <> + + Massa quam egestas massa. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, + massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At + tristique et ullamcorper rhoncus amet pharetra aliquet tortor. + Suscipit dui, nunc sit dui tellus massa laoreet tellus. + + + + Massa quam egestas massa. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, + massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At + tristique et ullamcorper rhoncus amet pharetra aliquet tortor. + Suscipit dui, nunc sit dui tellus massa laoreet tellus. + + + + Massa quam egestas massa. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, + massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At + tristique et ullamcorper rhoncus amet pharetra aliquet tortor. + Suscipit dui, nunc sit dui tellus massa laoreet tellus. + + + + Massa quam egestas massa. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, + massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At + tristique et ullamcorper rhoncus amet pharetra aliquet tortor. + Suscipit dui, nunc sit dui tellus massa laoreet tellus. + + + + ), + }, +}; + export const SmallOpen: StoryObj = { args: { ...DefaultOpen.args, diff --git a/src/components/Accordion/Accordion.test.tsx b/src/components/Accordion/Accordion.test.tsx index c603f3267..b93148f75 100644 --- a/src/components/Accordion/Accordion.test.tsx +++ b/src/components/Accordion/Accordion.test.tsx @@ -95,7 +95,7 @@ describe('', () => { , ); - const accordionButton = screen.getByTestId('accordion-button'); + const accordionButton = screen.getByRole('button'); await act(async () => { await user.click(accordionButton); @@ -103,4 +103,31 @@ describe('', () => { expect(onOpen).toHaveBeenCalledTimes(1); expect(onClose).not.toHaveBeenCalled(); }); + + it('should not call onOpen callback when accordion opens on an empty row', async () => { + const user = userEvent.setup(); + const onClose = jest.fn(); + const onOpen = jest.fn(); + render( + + + + Accordion Button + + Accordion Panel + + , + ); + const accordionButton = screen.getByRole('button'); + + await act(async () => { + await user.click(accordionButton); + }); + expect(onOpen).not.toHaveBeenCalled(); + expect(onClose).not.toHaveBeenCalled(); + }); }); diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index 491b39184..f5b05f80f 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -85,6 +85,10 @@ type AccordionRowProps = { * Whether panel is expanded by default. */ defaultOpen?: boolean; + /** + * Whether the row can show expandable content + */ + isExpandable?: boolean; }; const AccordionContext = createContext<{ @@ -95,6 +99,10 @@ const AccordionContext = createContext<{ headingAs: 'h2', }); +const AccordionRowContext = createContext<{ isExpandable?: boolean }>({ + isExpandable: true, +}); + /** * `import {Accordion} from "@chanzuckerberg/eds;` * @@ -140,10 +148,13 @@ const AccordionButton = ({ size, } = useContext(AccordionContext); + const { isExpandable } = useContext(AccordionRowContext); + const componentClassName = clsx( styles['accordion-button'], size === 'sm' && styles['accordion-button--sm'], hasOutline && styles['accordion-button--outline'], + !isExpandable && styles['accordion-button--empty'], className, ); @@ -159,19 +170,19 @@ const AccordionButton = ({ className={componentClassName} fullWidth onClick={() => { - if (open && onClose) { + if (open && isExpandable && onClose) { onClose(); } - if (!open && onOpen) { + if (!open && isExpandable && onOpen) { onOpen(); } }} onKeyDown={(e) => { if (e.key === SPACEBAR_KEYCODE || e.key === ENTER_KEYCODE) { - if (open && onClose) { + if (open && isExpandable && onClose) { onClose(); } - if (!open && onOpen) { + if (!open && isExpandable && onOpen) { onOpen(); } } @@ -186,16 +197,18 @@ const AccordionButton = ({ > {children} - + {isExpandable && ( + + )} )} @@ -208,17 +221,19 @@ const AccordionPanel = ({ ...other }: AccordionPanelProps) => { const { hasOutline, size } = useContext(AccordionContext); + const { isExpandable } = useContext(AccordionRowContext); const componentClassName = clsx( styles['accordion-panel'], size === 'sm' && styles['accordion-panel--sm'], hasOutline && styles['accordion-panel--outline'], + !isExpandable && styles['accordion-panel--hidden'], className, ); return ( - {children} + {isExpandable && children} ); }; @@ -227,6 +242,7 @@ const AccordionRow = ({ className, defaultOpen, children, + isExpandable = true, ...other }: AccordionRowProps) => { const { hasOutline } = useContext(AccordionContext); @@ -236,13 +252,15 @@ const AccordionRow = ({ className, ); return ( - - {({ open }) => ( -
- {typeof children === 'function' ? children({ open }) : children} -
- )} -
+ + + {({ open }) => ( +
+ {typeof children === 'function' ? children({ open }) : children} +
+ )} +
+
); }; diff --git a/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap b/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap index 46dc804b7..e343b556e 100644 --- a/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap +++ b/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap @@ -101,6 +101,166 @@ exports[` DefaultOpen story renders snapshot 1`] = ` `; +exports[` EmptyStackedOpen story renders snapshot 1`] = ` +
+
+
+ +
+
+
+ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At tristique et ullamcorper rhoncus amet pharetra aliquet tortor. Suscipit dui, nunc sit dui tellus massa laoreet tellus. +
+
+
+ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At tristique et ullamcorper rhoncus amet pharetra aliquet tortor. Suscipit dui, nunc sit dui tellus massa laoreet tellus. +
+
+
+ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla amet, massa ultricies iaculis. Quam lacus maecenas nibh malesuada. At tristique et ullamcorper rhoncus amet pharetra aliquet tortor. Suscipit dui, nunc sit dui tellus massa laoreet tellus. +
+
+
+
+`; + exports[` Small story renders snapshot 1`] = `
SmallOpen story renders snapshot 1`] = ` class="accordion-row" >
@@ -373,11 +533,11 @@ exports[` StackedOpen story renders snapshot 1`] = ` class="accordion-row" >