"use client"; import { CompareIcon } from "../ui/icons.tsx"; import { useId, useRef, useState } from "react"; export function ImageCompare({ before, after, value, onValueChange, label = "Image comparison", beforeLabel = "Before", afterLabel = "After", className = "", }: { before: { src: string; alt: string }; after: { src: string; alt: string }; value: number; onValueChange: (value: number) => void; label?: string; beforeLabel?: string; afterLabel?: string; className?: string; }) { const ref = useRef(null), id = useId(), [failed, setFailed] = useState(), current = Math.max(0, Math.min(100, Number.isFinite(value) ? value : 50)), broken = failed === before.src || failed === after.src; const update = (x: number) => { const r = ref.current!.getBoundingClientRect(); if (r.width) onValueChange( Math.round(Math.max(0, Math.min(100, ((x - r.left) / r.width) * 100))), ); }; return (
{label}
{ if (e.button === 0 && !broken) { e.currentTarget.setPointerCapture(e.pointerId); update(e.clientX); } }} onPointerMove={(e) => { if (e.currentTarget.hasPointerCapture(e.pointerId)) update(e.clientX); }} onPointerUp={(e) => { if (e.currentTarget.hasPointerCapture(e.pointerId)) e.currentTarget.releasePointerCapture(e.pointerId); }} > {broken ? (

Comparison image unavailable.

) : ( <> {before.alt} setFailed(before.src)} /> {after.alt} setFailed(after.src)} /> )}
onValueChange(Number(e.target.value))} />
{beforeLabel} {current}% {afterLabel.toLowerCase()} {afterLabel}
); }