import { useState } from 'react' import { Tooltip } from './ChartFrame' import { useWidth } from './useWidth' const STEPS = ['var(--color-seq-100)', 'var(--color-seq-200)', 'var(--color-seq-300)', 'var(--color-seq-400)', 'var(--color-seq-500)', 'var(--color-seq-600)', 'var(--color-seq-700)'] /** Grid of counts in one hue, light to dark; empty cells stay near the surface. */ export function Heatmap({ grid, rowLabels, colLabels, ariaLabel, describe }: { grid: number[][]; rowLabels: string[]; colLabels: string[]; ariaLabel: string; describe: (row: number, col: number, value: number) => string }) { const [ref, width] = useWidth() const [hover, setHover] = useState<{ r: number; c: number } | null>(null) const max = Math.max(1, ...grid.flat()) const step = (value: number) => (value === 0 ? 'var(--color-line-soft)' : STEPS[Math.min(STEPS.length - 1, Math.floor((value / max) * (STEPS.length - 1)))]) const labelW = 34 const cell = Math.max(10, Math.floor((width - labelW) / colLabels.length)) const height = rowLabels.length * cell + 18 return (
setHover(null)}> {rowLabels.map((label, r) => ( {label} ))} {colLabels.map((label, c) => c % 3 === 0 ? ( {label} ) : null, )} {grid.map((row, r) => row.map((value, c) => ( setHover({ r, c })} onFocus={() => setHover({ r, c })} className="outline-none" /> )), )}
Fewer {STEPS.map((color) => ( ))} More ({max} max)
{hover && ( )}
) }