Files
explorer-monorepo/frontend/src/components/common/DisclosureSection.tsx
defiQUG 0cb31cfa9d
Some checks failed
Validate Explorer / frontend (push) Failing after 14m45s
Deploy Explorer Live / deploy (push) Failing after 14m52s
Validate Explorer / smoke-e2e (push) Has been cancelled
Improve explorer SSR, hydration, compaction, and smoke coverage.
Defer heavy getServerSideProps on home, operator, addresses, and wallet to cut TTFB; centralize locale-safe formatters with client-only relative times; add compact ops UX, bridge/operator relay pagination, and Playwright route/scroll smoke in deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-22 15:52:47 -07:00

71 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useId, useState, type ReactNode } from 'react'
interface DisclosureSectionProps {
title: string
children: ReactNode
defaultOpen?: boolean
className?: string
headingClassName?: string
/** When true, content is always visible and the toggle is hidden (desktop layout). */
forceOpen?: boolean
/** When true, keep accordion behavior on all breakpoints (no md:auto-expand). */
alwaysCollapsible?: boolean
}
export default function DisclosureSection({
title,
children,
defaultOpen = false,
className = '',
headingClassName = '',
forceOpen = false,
alwaysCollapsible = false,
}: DisclosureSectionProps) {
const [open, setOpen] = useState(defaultOpen || forceOpen)
const panelId = useId().replace(/:/g, '')
const isOpen = forceOpen || open
return (
<section className={className}>
{forceOpen ? (
<div className={`mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400 ${headingClassName}`}>
{title}
</div>
) : (
<button
type="button"
aria-expanded={isOpen}
aria-controls={panelId}
onClick={() => setOpen((current) => !current)}
className={`flex w-full items-center justify-between gap-3 rounded-lg border border-gray-200 bg-gray-50/80 px-3 py-2.5 text-left text-sm font-semibold uppercase tracking-wide text-gray-700 transition hover:border-primary-300 dark:border-gray-800 dark:bg-gray-900/40 dark:text-gray-200 dark:hover:border-primary-700 ${alwaysCollapsible ? '' : 'md:hidden'} ${headingClassName}`}
>
<span>{title}</span>
<span aria-hidden="true" className="text-base text-gray-500 dark:text-gray-400">
{isOpen ? '' : '+'}
</span>
</button>
)}
<div
id={panelId}
className={
forceOpen
? ''
: alwaysCollapsible
? `${isOpen ? 'block' : 'hidden'} mt-3`
: `${isOpen ? 'block' : 'hidden'} mt-3 md:mt-0 md:block`
}
>
{!forceOpen && !alwaysCollapsible ? (
<div className="mb-3 hidden text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400 md:block">
{title}
</div>
) : null}
{children}
</div>
</section>
)
}