import { useId, type CSSProperties } from 'react'; import { compactNumber, extent, linearScale } from './utils.js'; export interface BarDatum { /** Stable id — React key + accessible label. */ id: string; /** Y-value. Negative values are supported (render below the baseline). */ value: number; /** Optional X-axis tick label (default: `id`). */ label?: string; /** Optional override colour. */ color?: string; } export interface BarChartProps { data: BarDatum[]; /** Chart width in px. Default 480. */ width?: number; /** Chart height in px. Default 240. */ height?: number; /** Bar corner radius (px). Default 4. */ cornerRadius?: number; /** Y baseline value (default 0). Use a custom baseline for diverging * charts (e.g. ±deltas around a target). */ baseline?: number; /** Show subtle Y grid lines (3 ticks). Default true. */ grid?: boolean; /** Accessible label. */ ariaLabel?: string; className?: string; style?: CSSProperties; } /** * `` — vertical bar chart with diverging-baseline support. * * Wave 9.A.2. Token-tinted via `--bl-accent` with per-bar override. */ export function BarChart({ data, width = 480, height = 240, cornerRadius = 4, baseline = 0, grid = true, ariaLabel, className, style, }: BarChartProps) { const titleId = useId(); const padL = 36; const padR = 12; const padT = 12; const padB = 28; const innerW = Math.max(0, width - padL - padR); const innerH = Math.max(0, height - padT - padB); const values = data.map((d) => d.value); let [yMin, yMax] = extent(values); yMin = Math.min(yMin, baseline); yMax = Math.max(yMax, baseline); const yScale = linearScale(yMin, yMax, innerH, 0); const yBase = yScale(baseline); const n = data.length; const slot = n > 0 ? innerW / n : 0; const barW = Math.max(2, slot * 0.7); return ( {ariaLabel ?? 'Bar chart'} {grid && [yMin, baseline, yMax].map((t, i) => ( {compactNumber(t)} ))} {data.map((d, i) => { const cx = slot * i + slot / 2; const x = cx - barW / 2; const y = Math.min(yBase, yScale(d.value)); const h = Math.abs(yBase - yScale(d.value)); const colour = d.color ?? 'var(--bl-accent, #6366f1)'; return ( {d.label ?? d.id} ); })} ); }