'use client'; import { Table2 } from 'lucide-react'; import { useId, useState, type ReactNode } from 'react'; import { t } from '@/i18n'; import { cn } from '@/lib/cn'; import type { Provenance } from '@/lib/types'; import type { ProvenancePayload } from '@/components/data/provenance-context'; import { SourceLine } from './source-line'; export interface TableColumn { key: string; label: string; numeric?: boolean; } export interface TableData { columns: TableColumn[]; rows: Array>; } /** * Wraps any chart: optional heading, the chart, a source attribution line (clickable → provenance), * and the accessible data-table toggle. `summary` is the auto-generated text summary announced to AT. */ export function ChartFrame({ title, subtitle, summary, provenance, payload, table, actions, legend, note, children, className, minHeight, }: { title?: ReactNode; subtitle?: ReactNode; summary: string; provenance?: Provenance | null; payload?: ProvenancePayload | null; table?: TableData; actions?: ReactNode; legend?: ReactNode; note?: ReactNode; children: ReactNode; className?: string; /** Reserve height to avoid layout shift while the chart mounts. */ minHeight?: number; }) { const [showTable, setShowTable] = useState(false); const id = useId(); return (
{title || actions ? (
{title ?
{title}
: null} {subtitle ?
{subtitle}
: null}
{actions ?
{actions}
: null}
) : null} {legend}
{children}

{summary}

{note ?

{note}

: null}
{table ? ( ) : null}
{table && showTable ? (
{table.columns.map((c) => ( ))} {table.rows.map((r, i) => ( {table.columns.map((c) => ( ))} ))}
{t('chart.table.caption')}
{c.label}
{r[c.key] ?? t('common.na')}
) : null}
); } /** Legend for ≥ 2 series (a single series needs none — the title names it). */ export function Legend({ items }: { items: Array<{ label: string; color: string; dashed?: boolean; shape?: 'line' | 'rect' }> }) { if (items.length < 2) return null; return ( ); }