diff --git a/frontend/src/components/shared/markdown-editor/markdown-editor-table-handles.tsx b/frontend/src/components/shared/markdown-editor/markdown-editor-table-handles.tsx index b8298a55..769528bf 100644 --- a/frontend/src/components/shared/markdown-editor/markdown-editor-table-handles.tsx +++ b/frontend/src/components/shared/markdown-editor/markdown-editor-table-handles.tsx @@ -248,10 +248,6 @@ function useTableHandles(editor: Editor): TableHandlesController { const openRef = useRef(null); const cellPosRef = useRef(null); - useEffect(() => { - openRef.current = open; - }, [open]); - useEffect(() => { const dom = editor.view.dom; @@ -367,7 +363,13 @@ function useTableHandles(editor: Editor): TableHandlesController { }, [editor]); const onMenuChange = (menu: 'column' | 'row') => (isOpen: boolean) => { - setOpen(isOpen ? menu : null); + const next = isOpen ? menu : null; + + // Write the ref synchronously, before setOpen. handleMove/dropStaleTarget are continuous-event handlers + // reading openRef.current; mirroring `open` through a passive effect flushes a tick late, so a mousemove + // in that window would retarget the grip to a neighbouring cell just as a menu opens on this one. + openRef.current = next; + setOpen(next); if (!isOpen) { cellPosRef.current = null;