import { useRef, useState, type CSSProperties } from "react"; interface BeforeAfterCompareProps { sourceSrc: string; resultSrc: string; sourceLabel?: string; resultLabel?: string; sourceAlt?: string; resultAlt?: string; className?: string; onSourceLoad?: (width: number, height: number) => void; } const MIN_POSITION = 5; const MAX_POSITION = 95; function clamp(value: number) { return Math.min(MAX_POSITION, Math.max(MIN_POSITION, value)); } export default function BeforeAfterCompare({ sourceSrc, resultSrc, sourceLabel, resultLabel, sourceAlt = "原图", resultAlt = "结果", className = "", onSourceLoad, }: BeforeAfterCompareProps) { const stageRef = useRef(null); const [position, setPosition] = useState(50); const updatePosition = (clientX: number) => { const stage = stageRef.current; if (!stage) return; const rect = stage.getBoundingClientRect(); if (!rect.width) return; setPosition(clamp(((clientX - rect.left) / rect.width) * 100)); }; return (
{sourceAlt} { onSourceLoad?.(event.currentTarget.naturalWidth, event.currentTarget.naturalHeight); }} />
{resultAlt}
{sourceLabel && (
{sourceLabel}
)} {resultLabel && (
{resultLabel}
)}
{ if (event.key === "ArrowLeft") { event.preventDefault(); setPosition((current) => clamp(current - 2)); } if (event.key === "ArrowRight") { event.preventDefault(); setPosition((current) => clamp(current + 2)); } }} onPointerDown={(event) => { event.currentTarget.setPointerCapture(event.pointerId); updatePosition(event.clientX); }} onPointerMove={(event) => { if (!event.currentTarget.hasPointerCapture(event.pointerId)) return; updatePosition(event.clientX); }} onPointerUp={(event) => { if (event.currentTarget.hasPointerCapture(event.pointerId)) { event.currentTarget.releasePointerCapture(event.pointerId); } }} onPointerCancel={(event) => { if (event.currentTarget.hasPointerCapture(event.pointerId)) { event.currentTarget.releasePointerCapture(event.pointerId); } }} >
); }