import { useMemo, type CSSProperties } from 'react'; export interface HeatmapCell { /** ISO date or any stable label. */ date: string; /** Value — drives intensity. */ value: number; /** Optional tooltip text. */ label?: string; } export interface HeatmapProps { /** Cells laid out top-to-bottom then left-to-right (calendar style). */ cells: HeatmapCell[]; /** Rows. Default 7 (week). */ rows?: number; /** Cell size in px (square). Default 12. */ cell?: number; /** Gap between cells in px. Default 3. */ gap?: number; /** Active color (interpolated by intensity). */ color?: string; /** Empty cell color. */ emptyColor?: string; ariaLabel?: string; className?: string; style?: CSSProperties; } /** * `` — GitHub-style calendar heatmap. Pure CSS grid, no * tooltips library — uses native `title` attributes for the on-hover * label so the bundle stays tiny. */ export function Heatmap({ cells, rows = 7, cell = 12, gap = 3, color = 'var(--bl-accent, #6366f1)', emptyColor = 'var(--bl-surface-muted, rgba(0,0,0,0.04))', ariaLabel, className, style, }: HeatmapProps) { const max = useMemo( () => cells.reduce((m, c) => Math.max(m, c.value), 0) || 1, [cells], ); return (
{cells.map((c, i) => { const intensity = c.value > 0 ? 0.15 + 0.85 * (c.value / max) : 0; return (
); })}
); }