UNPKG

@spaced-out/ui-design-system

Version:
117 lines (102 loc) 2.9 kB
// @flow strict import * as React from 'react'; import classify from '../../utils/classify'; import {Button} from '../Button'; import {Toggle} from '../Toggle'; import css from './Accordion.module.css'; export type AccordionClassNames = $ReadOnly<{ wrapper?: string, headerWrapper?: string, header?: string, content?: string, }>; export type AccordionPropsType = { id: string, header: React.Node, children: React.Node, classNames?: AccordionClassNames, isOpen?: boolean, disabled?: boolean, showToggle?: boolean, onChange?: ?(id?: string, isOpen: boolean) => mixed, onToggle?: ?(id?: string, checked?: boolean) => mixed, }; export const Accordion: React$AbstractComponent< AccordionPropsType, HTMLDivElement, > = React.forwardRef<AccordionPropsType, HTMLDivElement>( ( { id, header, onChange, onToggle, disabled = false, classNames, isOpen = false, showToggle = false, children, }: AccordionPropsType, ref, ) => { const [accordionIsOpen, setAccordionIsOpen] = React.useState(isOpen); const [checked, setChecked] = React.useState<boolean>(false); const handleToggle = () => { setChecked(!checked); onToggle?.(id, !checked); }; const handleAccordionClick = () => { if (!disabled) { onChange?.(id, !accordionIsOpen); setAccordionIsOpen((prev) => !prev); } }; React.useEffect(() => { setAccordionIsOpen(isOpen); }, [isOpen]); return ( <div ref={ref} data-testid="Accordion" className={classify(css.wrapper, classNames?.wrapper)} > <div className={classify(css.headerWrapper, classNames?.headerWrapper)} onClick={handleAccordionClick} > <div className={classify(css.header, classNames?.header)}> {showToggle && ( <div onClick={(e) => { e.stopPropagation(); // prevent toggle click from triggering accordion toggle }} > <Toggle checked={checked} onChange={handleToggle} ariaLabel={'toggle'} /> </div> )} {header} </div> <Button iconLeftName={accordionIsOpen ? 'chevron-up' : 'chevron-down'} disabled={disabled} size="small" type="ghost" className={css.icon} ariaLabel={'Collapse button'} // we are not defining onClick here as we are using onClick of the parent here. /> </div> {accordionIsOpen && ( <div className={classify(css.content, classNames?.content)}> {children} </div> )} </div> ); }, ); Accordion.displayName = 'Accordion';