From 3413d58f83ff7f3c6284b01fcd4b3fcd4ee6337d Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Wed, 11 Mar 2026 17:39:34 +0530 Subject: [PATCH] fix(crop): return cropOverlayRef instead of .current to fix null timing The cropOverlay was created asynchronously inside a polling interval but returned synchronously as .current (null). By returning the ref itself, Editor.tsx reads .current at call time when the overlay actually exists. --- frontend/src/hooks/useCanvasSetup.ts | 2 +- frontend/src/pages/Editor.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/hooks/useCanvasSetup.ts b/frontend/src/hooks/useCanvasSetup.ts index 4185a8c..a120a10 100644 --- a/frontend/src/hooks/useCanvasSetup.ts +++ b/frontend/src/hooks/useCanvasSetup.ts @@ -458,5 +458,5 @@ export function useCanvasSetup(deps: CanvasSetupDeps) { }; }, [boardData, resolvedBoardId, user, isPublicView, onCanvasChange, showToast, canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, uploadManager, setOnlineUsers, setSelectedLayerIds]); - return { annotationStore: annotationStoreRef.current, pinOverlay: pinOverlayRef.current, textEditor: textEditorRef.current, cropOverlay: cropOverlayRef.current }; + return { annotationStore: annotationStoreRef.current, pinOverlay: pinOverlayRef.current, textEditor: textEditorRef.current, cropOverlayRef }; } diff --git a/frontend/src/pages/Editor.tsx b/frontend/src/pages/Editor.tsx index 10aee48..0faede5 100644 --- a/frontend/src/pages/Editor.tsx +++ b/frontend/src/pages/Editor.tsx @@ -169,7 +169,7 @@ export default function Editor({ isPublicView }: EditorProps) { }); // Canvas setup (selection, undo, sync, socket, drag/drop, paste, inbox, annotations) - const { annotationStore, pinOverlay, textEditor, cropOverlay } = useCanvasSetup({ + const { annotationStore, pinOverlay, textEditor, cropOverlayRef } = useCanvasSetup({ boardData, resolvedBoardId, user, isPublicView, canvasRef, selectionRef, undoRef, syncRef, inboxZoneRef, canvasContainerRef, uploadManager, onCanvasChange, showToast, setOnlineUsers, setSelectedLayerIds, @@ -296,14 +296,14 @@ export default function Editor({ isPublicView }: EditorProps) { setShowGrid, setShowHelp, setFocusMode, setReviewMode, startCrop: () => { const selection = selectionRef.current; - if (!selection || !cropOverlay) return; + if (!selection || !cropOverlayRef.current) return; const items = selection.getSelectedItems(); if (items.length !== 1 || items[0].type !== 'image') { showToast('Select a single image to crop'); return; } selection.setEnabled(false); - cropOverlay.start(items[0]); + cropOverlayRef.current.start(items[0]); }, }); @@ -327,14 +327,14 @@ export default function Editor({ isPublicView }: EditorProps) { fitAll: () => canvasRef.current?.fitAll(), startCrop: () => { const selection = selectionRef.current; - if (!selection || !cropOverlay) return; + if (!selection || !cropOverlayRef.current) return; const items = selection.getSelectedItems(); if (items.length !== 1 || items[0].type !== 'image') return; selection.setEnabled(false); - cropOverlay.start(items[0]); + cropOverlayRef.current.start(items[0]); }, }); - }, [writeCanvasToClipboard, onCanvasChange, handleGroup, handleUngroup, refreshLayers, cropOverlay]); + }, [writeCanvasToClipboard, onCanvasChange, handleGroup, handleUngroup, refreshLayers]); // Save on page unload (only for users with edit access) useEffect(() => {