50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import type { ReactNode } from "react";
|
|
|
|
interface ChartTooltipPayload {
|
|
color?: string;
|
|
dataKey?: string | number;
|
|
name?: ReactNode;
|
|
payload?: Record<string, unknown>;
|
|
value?: unknown;
|
|
}
|
|
|
|
interface ChartTooltipProps {
|
|
active?: boolean;
|
|
label?: ReactNode;
|
|
labelFormatter?: (label: ReactNode) => ReactNode;
|
|
payload?: ChartTooltipPayload[];
|
|
valueFormatter?: (entry: ChartTooltipPayload) => ReactNode;
|
|
}
|
|
|
|
export function ChartTooltip({ active, label, labelFormatter, payload, valueFormatter }: ChartTooltipProps) {
|
|
if (!active || !payload?.length) return null;
|
|
|
|
return (
|
|
<div className="min-w-36 rounded-card border border-border/80 bg-surface-raised/95 px-3.5 py-3 text-xs text-foreground shadow-card backdrop-blur-xl">
|
|
{label !== undefined && (
|
|
<p className="mb-2 text-[0.68rem] font-semibold uppercase tracking-[0.14em] text-muted">
|
|
{labelFormatter ? labelFormatter(label) : label}
|
|
</p>
|
|
)}
|
|
<div className="space-y-1.5">
|
|
{payload.map((entry, index) => (
|
|
<div
|
|
className="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4"
|
|
key={`${String(entry.dataKey ?? entry.name ?? "series")}-${index}`}
|
|
>
|
|
<span className="flex min-w-0 items-center gap-2 text-muted">
|
|
{entry.color && (
|
|
<span className="size-2 rounded-full" style={{ backgroundColor: entry.color }} aria-hidden="true" />
|
|
)}
|
|
<span className="truncate">{entry.name}</span>
|
|
</span>
|
|
<span className="font-semibold tabular-nums text-foreground">
|
|
{valueFormatter ? valueFormatter(entry) : String(entry.value ?? "—")}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|