37 lines
1.2 KiB
TypeScript
37 lines
1.2 KiB
TypeScript
import { useState, type ReactNode } from 'react';
|
|
import { ChevronRight } from 'lucide-react';
|
|
export function CollapsibleSection({
|
|
title,
|
|
children,
|
|
defaultOpen = true,
|
|
forceOpen = false,
|
|
badge,
|
|
}: {
|
|
title: string;
|
|
children: ReactNode;
|
|
defaultOpen?: boolean;
|
|
forceOpen?: boolean;
|
|
badge?: ReactNode;
|
|
}) {
|
|
const [open, setOpen] = useState(defaultOpen);
|
|
const expanded = forceOpen || open;
|
|
return (
|
|
<section className="border-b border-border">
|
|
<button
|
|
type="button"
|
|
aria-expanded={expanded}
|
|
onClick={() => setOpen((value) => !value)}
|
|
className="flex h-9 w-full items-center gap-2 px-3 text-left text-xs font-semibold text-text-secondary transition-colors hover:bg-element-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent/30"
|
|
>
|
|
<ChevronRight
|
|
aria-hidden="true"
|
|
className={`h-3.5 w-3.5 transition-transform ${expanded ? 'rotate-90' : ''}`}
|
|
/>
|
|
<span className="min-w-0 flex-1 truncate">{title}</span>
|
|
{badge}
|
|
</button>
|
|
{expanded && <div className="px-3 pb-3">{children}</div>}
|
|
</section>
|
|
);
|
|
}
|