All files / src/components accordion.tsx

100% Statements 7/7
90.9% Branches 10/11
100% Functions 3/3
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66                    9x                                     9x                 13x   13x 2x       13x                                        
import { useState, type FC, type ReactNode, type HTMLAttributes } from 'react';
import cn from 'classnames';
 
import Bubble from './bubble';
 
import '../styles/components/accordion.scss';
 
import ChevronDown from '../svg/chevron-down.svg';
import ChevronUp from '../svg/chevron-up.svg';
 
const chevronSize = 16;
 
type Props = {
  /**
   * The title, works as a trigger to open/close
   */
  accordionTitle: ReactNode;
  /**
   * Number displayed at the right of the accordion. This could, for example, be used to inform
     the user how many checkboxes have selected in the accodion's hidden content.
   */
  count?: number;
  /**
   * Disable toggling and always open accordion
   */
  alwaysOpen?: boolean;
  initialOpen?: boolean;
};
 
const Accordion: FC<Props & HTMLAttributes<HTMLDivElement>> = ({
  accordionTitle,
  count = 0,
  children,
  alwaysOpen,
  initialOpen = false,
  className,
  ...props
}) => {
  const [open, setOpen] = useState(initialOpen);
 
  const toggleOpen = () => {
    setOpen((open) => !open);
  };
 
  // Note: might be good to use details/summary elements in the future for this
  return (
    <div className={cn(className, 'accordion')} {...props}>
      <button type="button" className="accordion__title" onClick={toggleOpen}>
        <span>{accordionTitle}</span>
        {count > 0 && <Bubble size="small">{count}</Bubble>}
        {!alwaysOpen &&
          (open ? (
            <ChevronUp width={chevronSize} height={chevronSize} />
          ) : (
            <ChevronDown width={chevronSize} height={chevronSize} />
          ))}
      </button>
      {(open || alwaysOpen) && (
        <div className="accordion__content">{children}</div>
      )}
    </div>
  );
};
 
export default Accordion;