From 205ce65a8b45ec8bf1eaaeef9c7638c04a79dd96 Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Tue, 10 Mar 2026 11:20:26 +0530 Subject: [PATCH] =?UTF-8?q?fix(refboard):=20drag-drop=20opening=20in=20new?= =?UTF-8?q?=20tab=20=E2=80=94=20use=20ref=20for=20drop=20target?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drag/drop setup was searching for a element to find its parent, which was fragile and could fail (returning null). When it failed, document-level dragover/drop prevention was never registered, so the browser's default behavior (open file in new tab) kicked in. Fix: pass a direct ref to the outer canvas container div from Editor to useCanvasSetup. No more DOM querying for the drop target. --- frontend/src/hooks/useCanvasSetup.ts | 21 ++++++--------------- frontend/src/pages/Editor.tsx | 5 +++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/frontend/src/hooks/useCanvasSetup.ts b/frontend/src/hooks/useCanvasSetup.ts index 3c2f943..8367fec 100644 --- a/frontend/src/hooks/useCanvasSetup.ts +++ b/frontend/src/hooks/useCanvasSetup.ts @@ -40,6 +40,7 @@ interface CanvasSetupDeps { undoRef: React.MutableRefObject; syncRef: React.MutableRefObject; inboxZoneRef: React.MutableRefObject; + canvasContainerRef: React.RefObject; onCanvasChange: (changedIds?: string[]) => void; showToast: (msg: string) => void; setOnlineUsers: React.Dispatch>; @@ -53,7 +54,7 @@ interface CanvasSetupDeps { export function useCanvasSetup(deps: CanvasSetupDeps) { const { boardData, resolvedBoardId, user, isPublicView, - canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, + canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, canvasContainerRef, onCanvasChange, showToast, setOnlineUsers, setSelectedLayerIds, } = deps; @@ -252,21 +253,11 @@ export function useCanvasSetup(deps: CanvasSetupDeps) { // Setup drag/drop and paste if (!isPublicView || user) { - const canvasElements = document.querySelectorAll('canvas'); - let domContainer: HTMLElement | null = null; - for (const c of canvasElements) { - if (c.parentElement && c.width > 100) { - domContainer = c.parentElement; - break; - } - } - - if (domContainer) { - dropCleanupRef.current = setupDragDrop(domContainer, viewport, scene, resolvedBoardId, onCanvasChange); - pasteCleanupRef.current = setupPaste(viewport, scene, resolvedBoardId, onCanvasChange); - } else { - pasteCleanupRef.current = setupPaste(viewport, scene, resolvedBoardId, onCanvasChange); + const dropTarget = canvasContainerRef.current; + if (dropTarget) { + dropCleanupRef.current = setupDragDrop(dropTarget, viewport, scene, resolvedBoardId, onCanvasChange); } + pasteCleanupRef.current = setupPaste(viewport, scene, resolvedBoardId, onCanvasChange); } }, 200); diff --git a/frontend/src/pages/Editor.tsx b/frontend/src/pages/Editor.tsx index 99e8083..dacdd9d 100644 --- a/frontend/src/pages/Editor.tsx +++ b/frontend/src/pages/Editor.tsx @@ -59,6 +59,7 @@ export default function Editor({ isPublicView }: EditorProps) { const toolCleanupRef = useRef<(() => void) | null>(null); const inboxZoneRef = useRef(null); const clipboardRef = useRef([]); + const canvasContainerRef = useRef(null); // UI state const [activeTool, setActiveTool] = useState(ToolType.SELECT); @@ -136,7 +137,7 @@ export default function Editor({ isPublicView }: EditorProps) { // Canvas setup (selection, undo, sync, socket, drag/drop, paste, inbox) useCanvasSetup({ boardData, resolvedBoardId, user, isPublicView, - canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, + canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, canvasContainerRef, onCanvasChange, showToast, setOnlineUsers, setSelectedLayerIds, }); @@ -473,7 +474,7 @@ export default function Editor({ isPublicView }: EditorProps) { />} {/* Canvas */} -
+
{/* Dot grid — behind transparent canvas */} {showGrid && (() => { const scale = canvasTransform[0] || 1;