The series points to plot, and whether to color by trend.
The sparkline element, or null when there's nothing to draw.
<PriceSparkline points={[{ t: 1, usd: 20 }, { t: 2, usd: 22 }]} />
<PriceSparkline points={series.points} colorByTrend />
export function PriceSparkline({
points,
colorByTrend = false,
}: {
points: readonly PricePoint[];
colorByTrend?: boolean;
}): ReactElement | null {
const theme = useTheme();
if (points.length < 2) return null;
const width = 84;
const height = 22;
const pad = 2;
const values = points.map((p) => p.usd);
const min = Math.min(...values);
const max = Math.max(...values);
const span = max - min || 1;
const stepX = (width - pad * 2) / (points.length - 1);
const coords = points
.map((p, i) => {
const x = pad + i * stepX;
const y = pad + (height - pad * 2) * (1 - (p.usd - min) / span);
return `${x.toFixed(1)},${y.toFixed(1)}`;
})
.join(' ');
// Match the PriceTrend badge's semantics (rising = red, drop = green) by
// resolving the same palette tokens to concrete stroke colors for the SVG.
const trendStroke = {
up: theme.palette.error.main,
down: theme.palette.success.main,
flat: theme.palette.text.secondary,
} as const;
const stroke = colorByTrend ? trendStroke[describeTrend(points).direction] : 'currentColor';
return (
<svg
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
role="img"
aria-label={i18n('product_detail_sparkline_aria')}
style={{ display: 'block' }}
>
<polyline
points={coords}
fill="none"
stroke={stroke}
strokeWidth={1.5}
strokeLinejoin="round"
strokeLinecap="round"
/>
</svg>
);
}
Inline SVG sparkline of a price series. Points are spaced evenly by index and scaled to the series' own min/max. Renders nothing for a series too short to draw a line (fewer than two points).
By default the line inherits the surrounding text color (
currentColor). PasscolorByTrendto instead color it by the series' latest move — matching the PriceTrend badge: rising price = red, drop = green, flat = muted.