diff --git a/src/components/Accordion/Accordion.stories.tsx b/src/components/Accordion/Accordion.stories.tsx index d371bc9ee..93c5ab4cc 100644 --- a/src/components/Accordion/Accordion.stories.tsx +++ b/src/components/Accordion/Accordion.stories.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import { Meta, Story } from '@storybook/react/types-6-0'; +import { includes } from 'ramda'; import { Inline, Stack } from '../layout'; import { HexGrade } from '../HexGrade'; @@ -72,7 +73,7 @@ CustomTitleElement.args = { }; export const AcordionWithExternalManagement: Story = () => { - const [openItems, setOpenItems] = useState([]); + const [openItems, setOpenItems] = useState<(string | number)[]>([]); const handleOnClick = (id: string) => { if (!openItems.includes(id)) { const newItems = [id]; @@ -91,16 +92,23 @@ export const AcordionWithExternalManagement: Story = () => { - + { + setOpenItems(ids); + }} + /> ); }; diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index 5241e5de8..eb24037c5 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -30,29 +30,37 @@ function filterState( if (isCollapsedOnOpen) { return [item]; } + return [...state, item]; } const Accordion = React.forwardRef( ( - { isCollapsedOnOpen = true, items, openItems, className, ...props }, + { + isCollapsedOnOpen = true, + items, + openItems, + className, + onChange, + ...props + }, ref, ) => { const [openIds, setOpenIds] = useState(pickOpen(items)); - useEffect( - () => - openItems?.forEach((item: AccordionItemId) => - setOpenIds((state) => filterState(state, item, isCollapsedOnOpen)), - ), - [openItems, isCollapsedOnOpen], - ); + useEffect(() => { + if (openItems !== undefined) { + setOpenIds(isCollapsedOnOpen ? [openItems[0]] : openItems); + } + }, [openItems, isCollapsedOnOpen]); const handleClick = useCallback( (id: AccordionItemId) => { - setOpenIds((state) => filterState(state, id, isCollapsedOnOpen)); + const nextState = filterState(openIds, id, isCollapsedOnOpen); + setOpenIds(nextState); + onChange?.(nextState); }, - [setOpenIds, isCollapsedOnOpen], + [openIds, setOpenIds, onChange, isCollapsedOnOpen], ); return ( @@ -78,6 +86,7 @@ Accordion.propTypes = { isCollapsedOnOpen: PropTypes.bool, className: PropTypes.string, openItems: PropTypes.arrayOf(AccordionItemIdPropType), + onChange: PropTypes.func, }; export default Accordion; diff --git a/src/components/Accordion/Accordion.types.ts b/src/components/Accordion/Accordion.types.ts index 75a15f814..6748d4704 100644 --- a/src/components/Accordion/Accordion.types.ts +++ b/src/components/Accordion/Accordion.types.ts @@ -22,7 +22,8 @@ export interface AccordionProps { isCollapsedOnOpen?: boolean; items: AccordionItem[]; className?: string; - openItems: AccordionItemId[]; + openItems?: AccordionItemId[]; + onChange?: (openIds: AccordionItemId[]) => void; } export const AccordionItemIdPropType = PropTypes.oneOfType([