diff --git a/src/components/nodes/FloatingNodeHeader.tsx b/src/components/nodes/FloatingNodeHeader.tsx index 8da8f732..9326f95c 100644 --- a/src/components/nodes/FloatingNodeHeader.tsx +++ b/src/components/nodes/FloatingNodeHeader.tsx @@ -209,7 +209,7 @@ export function FloatingNodeHeader({ const { setNodes, getNodes, getViewport } = useReactFlow(); const isDraggingRef = useRef(false); - const handleHeaderMouseDown = useCallback((e: React.MouseEvent) => { + const handleHeaderPointerDown = useCallback((e: React.PointerEvent) => { // Don't drag from interactive elements if ((e.target as HTMLElement).closest('.nodrag, button, input, textarea, a')) return; if (e.button !== 0) return; @@ -241,7 +241,7 @@ export function FloatingNodeHeader({ isDraggingRef.current = false; - const handleMouseMove = (e: MouseEvent) => { + const handlePointerMove = (e: PointerEvent) => { const { zoom } = getViewport(); const dx = (e.clientX - startX) / zoom; const dy = (e.clientY - startY) / zoom; @@ -262,30 +262,32 @@ export function FloatingNodeHeader({ } }; - const handleMouseUp = () => { - document.removeEventListener('mousemove', handleMouseMove); - document.removeEventListener('mouseup', handleMouseUp); + const handlePointerUp = () => { + document.removeEventListener('pointermove', handlePointerMove); + document.removeEventListener('pointerup', handlePointerUp); isDraggingRef.current = false; }; - document.addEventListener('mousemove', handleMouseMove); - document.addEventListener('mouseup', handleMouseUp); + document.addEventListener('pointermove', handlePointerMove); + document.addEventListener('pointerup', handlePointerUp); }, [id, getNodes, getViewport, setNodes]); return (
setIsHeaderHovered(true)} - onMouseLeave={() => setIsHeaderHovered(false)} - onMouseDown={handleHeaderMouseDown} > -
+
setIsHeaderHovered(true)} + onMouseLeave={() => setIsHeaderHovered(false)} + onPointerDown={handleHeaderPointerDown} + > {/* Title Section */}
{titlePrefix} diff --git a/src/components/nodes/VideoStitchNode.tsx b/src/components/nodes/VideoStitchNode.tsx index aac0ebd5..ff969545 100644 --- a/src/components/nodes/VideoStitchNode.tsx +++ b/src/components/nodes/VideoStitchNode.tsx @@ -251,7 +251,12 @@ export function VideoStitchNode({ id, data, selected }: NodeProps { + const handlePointerUp = useCallback((e: React.PointerEvent) => { + // Always release pointer capture to prevent capture leak + try { + (e.target as HTMLElement).releasePointerCapture(e.pointerId); + } catch { /* element may have been removed */ } + if (!draggedClipId || !hoverClipId || draggedClipId === hoverClipId) { setDraggedClipId(null); setHoverClipId(null);