import * as React from "react"; import { ResponsiveContainer, LineChart as RLineChart, Line, BarChart as RBarChart, Bar, AreaChart as RAreaChart, Area, CartesianGrid, XAxis, YAxis, Tooltip, Legend, } from "recharts"; import { cn } from "../../utils/cn"; export interface ChartSeries { key: string; label?: string; /** Defaults to the token-based palette below, cycling if there are more series than colors. */ color?: string; } /** Token-driven default palette — the first color is the current accent (so charts repaint when the color picker changes), the rest are fixed semantic tones for contrast against it. */ const DEFAULT_PALETTE = [ "var(--ui-primary)", "var(--ui-success)", "var(--ui-warning)", "var(--ui-danger)", "var(--ui-color-neutral-400)", ]; function resolveColor(series: ChartSeries, index: number) { return series.color ?? DEFAULT_PALETTE[index % DEFAULT_PALETTE.length]; } interface ChartTooltipProps { active?: boolean; label?: string | number; payload?: { name: string; value: number | string; color: string }[]; } function ChartTooltipContent({ active, label, payload }: ChartTooltipProps) { if (!active || !payload?.length) return null; return (
{label !== undefined &&
{label}
}
{payload.map((entry) => (
{entry.name}: {entry.value}
))}
); } interface BaseChartProps { data: Record[]; xKey: string; series: ChartSeries[]; height?: number; showGrid?: boolean; showLegend?: boolean; className?: string; } const axisStyle = { fontSize: 12, fill: "var(--ui-fg-muted)" }; /** Line chart — trends over time/sequence. Reads its colors from the current design tokens by default, so it repaints with the accent color picker like every other component. */ export function LineChart({ data, xKey, series, height = 320, showGrid = true, showLegend = series.length > 1, className }: BaseChartProps) { return (
{showGrid && } } /> {showLegend && } {series.map((s, i) => ( ))}
); } /** Bar chart — comparisons across categories. */ export function BarChart({ data, xKey, series, height = 320, showGrid = true, showLegend = series.length > 1, className }: BaseChartProps) { return (
{showGrid && } } cursor={{ fill: "var(--ui-bg-subtle)" }} /> {showLegend && } {series.map((s, i) => ( ))}
); } /** Area chart — volume/magnitude over time. */ export function AreaChart({ data, xKey, series, height = 320, showGrid = true, showLegend = series.length > 1, className }: BaseChartProps) { return (
{showGrid && } } /> {showLegend && } {series.map((s, i) => ( ))}
); }