# All files / src/components/ui collapsible.tsx

95.55% Statements 86/90
50% Branches 3/6
75% Functions 3/4
95.55% Lines 86/90

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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    911x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x

    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x

    24x
    24x
    24x
    24x
    1x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    1x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    24x
    1x
    1x
     import { ComponentProps, ReactNode, useState } from "react"
    import { cn } from "@/lib/utils"

    interface CollapsibleProps extends Omit<ComponentProps<"div">, "children"> {
      open?: boolean
      onOpenChange?: (open: boolean) => void
      defaultOpen?: boolean
      children?: ReactNode | ((state: { open: boolean; onOpenChange: (open: boolean) => void }) => ReactNode)
    }

    function Collapsible({
      open,
      onOpenChange,
      defaultOpen = false,
      children,
      className,
      ...props
    }: CollapsibleProps) {
      const [isOpen, setIsOpen] = useState(defaultOpen)
      const actualOpen = open !== undefined ? open : isOpen

      const handleOpenChange = (newOpen: boolean) => {
        setIsOpen(newOpen)
        onOpenChange?.(newOpen)
      }

      return (
        <div
          data-slot="collapsible"
          data-state={actualOpen ? "open" : "closed"}
          className={cn("w-full", className)}
          {...props}
        >
          {typeof children === "function"
            ? children({ open: actualOpen, onOpenChange: handleOpenChange })
            : children}
        </div>
      )
    }

    function CollapsibleTrigger({
      onClick,
      children,
      className,
      ...props
    }: ComponentProps<"button"> & { children?: ReactNode }) {
      return (
        <button
          data-slot="collapsible-trigger"
          className={cn(
            "mat-mdc-button",
            "flex items-center justify-between w-full",
            "px-3 py-2 rounded-md",
            "hover:bg-gray-200 dark:hover:bg-gray-700",
            "focus-visible:ring-2 focus-visible:ring-offset-2",
            "transition-colors",
            className
          )}
          onClick={onClick}
          {...props}
        >
          {children}
        </button>
      )
    }

    function CollapsibleContent({
      className,
      children,
      ...props
    }: ComponentProps<"div">) {
      return (
        <div
          data-slot="collapsible-content"
          className={cn(
            "overflow-hidden transition-all duration-200",
            "data-[state=open]:animate-in data-[state=closed]:animate-out",
            "data-[state=closed]:collapse",
            className
          )}
          {...props}
        >
          <div className="px-3 py-2">
            {children}
          </div>
        </div>
      )
    }

    export { Collapsible, CollapsibleTrigger, CollapsibleContent }