"use client"; import { PEN_CURSOR } from "@/preview/components/cursors"; import { usePreviewViewport } from "@/preview/components/preview-viewport"; import { useMaskHandles } from "@/masks/use-mask-handles"; import type { SnapLine } from "@/preview/preview-snap"; import { CornerHandle, CircleHandle, CanvasPathOutline, EdgeHandle, IconHandle, LineOverlay, BoundingBoxOutline, ShapeOutline, } from "./handle-primitives"; const CUSTOM_MASK_ANCHOR_SIZE = 7; const CUSTOM_MASK_TANGENT_SIZE = 6; import { Rotate01Icon, FeatherIcon } from "@hugeicons/core-free-icons"; export function MaskHandles({ onSnapLinesChange, }: { onSnapLinesChange?: (lines: SnapLine[]) => void; }) { const viewport = usePreviewViewport(); const { selectedWithMask, handlePositions, overlays, isCreatingCustomMask, handleCanvasPointerDown, handlePointerDown, handlePointerMove, handlePointerUp, } = useMaskHandles({ onSnapLinesChange }); if (!selectedWithMask) return null; const toOverlay = ({ canvasX, canvasY, }: { canvasX: number; canvasY: number; }) => viewport.canvasToOverlay({ canvasX, canvasY, }); const { x: scaleX, y: scaleY } = viewport.getDisplayScale(); const canvasOrigin = toOverlay({ canvasX: 0, canvasY: 0 }); const onPointerMove = (event: React.PointerEvent) => { if (viewport.handlePanPointerMove({ event })) { return; } handlePointerMove({ event }); }; const onPointerUp = (event: React.PointerEvent) => { if (viewport.handlePanPointerUp({ event })) { return; } handlePointerUp(); }; const handleMaskPointerDown = ({ event, handleId, }: { event: React.PointerEvent; handleId: string; }) => { if (viewport.handlePanPointerDown({ event })) { return; } handlePointerDown({ event, handleId }); }; const handleCanvasOverlayPointerDown = (event: React.PointerEvent) => { if (viewport.handlePanPointerDown({ event })) { return; } handleCanvasPointerDown({ event }); }; return (
{isCreatingCustomMask ? (
) : null} {overlays.map((overlay) => { const overlayHandleId = overlay.handleId; const pointerHandlers = overlayHandleId ? { onPointerDown: (event: React.PointerEvent) => handleMaskPointerDown({ event, handleId: overlayHandleId }), onPointerMove, onPointerUp, } : {}; if (overlay.type === "line") { return ( ); } if (overlay.type === "rect") { return ( ); } if (overlay.type === "shape") { return ( ); } if (overlay.type === "canvas-path") { return ( ); } return null; })} {handlePositions.map((handle) => { const screen = toOverlay({ canvasX: handle.x, canvasY: handle.y }); if (handle.kind === "icon" && handle.icon === "rotate") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } if (handle.kind === "icon" && handle.icon === "feather") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } if (handle.kind === "edge" && handle.edgeAxis === "horizontal") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } if (handle.kind === "edge" && handle.edgeAxis === "vertical") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } if (handle.kind === "point" || handle.kind === "tangent") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } if (handle.kind === "corner") { return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); } return ( handleMaskPointerDown({ event, handleId: handle.id }) } onPointerMove={onPointerMove} onPointerUp={onPointerUp} /> ); })}
); }