"use client";
import * as React from "react";
import { LineHandles } from "@/components/ui/line-handles";
type Point = { x: number; y: number };
/** Same lookup metalui's inkColor() does: the CSS colour of an ink, for drawing with it. */
const inkColor = (ink: string) => `var(--mu-r-draw-ink-${ink})`;
export default function LineHandlesDemo() {
const [ends, setEnds] = React.useState<{ from: Point; to: Point }>({
from: { x: 120, y: 230 },
to: { x: 460, y: 90 },
});
const [hover, setHover] = React.useState(false);
const [selected, setSelected] = React.useState(false);
const drag = React.useRef<"from" | "to" | null>(null);
const box = React.useRef<HTMLDivElement>(null);
const at = (e: React.PointerEvent): Point => {
const r = box.current!.getBoundingClientRect();
return { x: e.clientX - r.left, y: e.clientY - r.top };
};
const { from, to } = ends;
const g = Math.atan2(to.y - from.y, to.x - from.x);
const L = 12;
const head = `M${to.x - L * Math.cos(g - 0.5)} ${to.y - L * Math.sin(g - 0.5)}L${to.x} ${to.y}L${to.x - L * Math.cos(g + 0.5)} ${to.y - L * Math.sin(g + 0.5)}`;
return (
<div
ref={box}
className="mu-snap-canvas"
style={{ height: 320, touchAction: "none" }}
onPointerDown={() => setSelected(false)}
onPointerMove={(e) => {
const k = drag.current;
if (k) setEnds((s) => ({ ...s, [k]: at(e) }));
}}
onPointerUp={() => (drag.current = null)}
>
<svg
width={1}
height={1}
style={{ position: "absolute", left: 0, top: 0, overflow: "visible" }}
>
<path
d={`M${from.x} ${from.y}L${to.x} ${to.y}${head}`}
fill="none"
stroke={inkColor("ink")}
strokeWidth={2.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d={`M${from.x} ${from.y}L${to.x} ${to.y}`}
stroke="transparent"
strokeWidth={18}
style={{ cursor: "pointer" }}
onPointerEnter={() => setHover(true)}
onPointerLeave={() => setHover(false)}
onPointerDown={(e) => {
e.stopPropagation();
setSelected(true);
}}
/>
</svg>
<LineHandles
from={from}
to={to}
state={selected ? "selected" : hover ? "hover" : "rest"}
onHandlePointerDown={(end, e) => {
e.stopPropagation();
try {
box.current!.setPointerCapture(e.pointerId);
} catch {
/* a synthetic pointer */
}
drag.current = end;
}}
/>
</div>
);
}