import { useId, type CSSProperties } from 'react'; import { compactNumber, extent, filterFinite, linearScale, smoothPath } from './utils.js'; export interface AreaChartProps { /** Series Y-values. */ values: number[]; /** Chart width in px. Default 480. */ width?: number; /** Chart height in px. Default 240. */ height?: number; /** Smooth (catmull-rom) vs straight polyline. Default smooth. */ smooth?: boolean; /** Override stroke + fill base colour. */ color?: string; /** Accessible label. */ ariaLabel?: string; className?: string; style?: CSSProperties; } /** * `` — single-series filled area chart with gradient. * * Wave 9.A.3. */ export function AreaChart({ values, width = 480, height = 240, smooth = true, color = 'var(--bl-accent, #6366f1)', ariaLabel, className, style, }: AreaChartProps) { const titleId = useId(); const gradId = useId(); const padL = 36; const padR = 12; const padT = 12; const padB = 24; const innerW = Math.max(0, width - padL - padR); const innerH = Math.max(0, height - padT - padB); const finitePairs = filterFinite(values); const finiteValues = finitePairs.map(([, v]) => v); const [yMin, yMax] = extent(finiteValues); const yMinDisplay = Math.min(0, yMin); const yScale = linearScale(yMinDisplay, yMax, innerH, 0); const xScale = (i: number) => values.length > 1 ? (i / (values.length - 1)) * innerW : innerW / 2; const points: Array<[number, number]> = finitePairs.map(([i, v]) => [ xScale(i), yScale(v), ]); const linePath = smooth ? smoothPath(points) : `M ${points.map(([x, y]) => `${x} ${y}`).join(' L ')}`; const closeY = yScale(yMinDisplay); const areaPath = points.length ? `${linePath} L ${points[points.length - 1]![0]} ${closeY} L ${points[0]![0]} ${closeY} Z` : ''; return ( {ariaLabel ?? 'Area chart'} {/* baseline + max labels */} {compactNumber(yMinDisplay)} {compactNumber(yMax)} ); }