"use client"; import { useState } from "react"; import { cn } from "@/lib/utils"; const SERIES_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"]; export type BarChartGroup = { label: string; values: number[]; }; /** Grouped vertical bar chart — hand-rolled SVG (no charting lib), series * colors assigned by fixed index (never repainted if a filter changes * which groups are visible). Includes a hover tooltip and a table-view * toggle for the low-contrast-slot / no-color accessibility path. */ export function BarChart({ data, seriesLabels, formatValue = (n) => String(n), height = 220, }: { data: BarChartGroup[]; seriesLabels: string[]; formatValue?: (n: number) => string; height?: number; }) { const [hovered, setHovered] = useState(null); const [showTable, setShowTable] = useState(false); const max = Math.max(1, ...data.flatMap((d) => d.values)); const width = 600; const paddingBottom = 28; const paddingTop = 12; const plotHeight = height - paddingBottom - paddingTop; const groupWidth = width / Math.max(1, data.length); const barGap = 2; const barWidth = Math.max(4, (groupWidth - 16 - barGap * (seriesLabels.length - 1)) / seriesLabels.length); if (data.length === 0) { return

No data yet.

; } return (
{seriesLabels.length > 1 && (
{seriesLabels.map((label, i) => (
{label}
))}
)} {showTable ? (
{seriesLabels.map((label) => ( ))} {data.map((d) => ( {d.values.map((v, i) => ( ))} ))}
Label{label}
{d.label}{formatValue(v)}
) : (
{data.map((group, gi) => { const gx = gi * groupWidth + 8; return ( setHovered(gi)} onMouseLeave={() => setHovered(null)}> {group.values.map((v, si) => { const barHeight = Math.max(0, (v / max) * plotHeight); const bx = gx + si * (barWidth + barGap); const by = height - paddingBottom - barHeight; return ( ); })} {group.label} {seriesLabels.length === 1 && group.values[0]! > 0 && ( {formatValue(group.values[0]!)} )} ); })} {hovered !== null && (

{data[hovered]!.label}

{data[hovered]!.values.map((v, i) => (

{seriesLabels[i]}: {formatValue(v)}

))}
)}
)}
); }