From d4c4f5f8393c8c4457117454f6ae4bf31392f206 Mon Sep 17 00:00:00 2001 From: ML-dev-crypto Date: Wed, 1 Apr 2026 23:29:56 +0530 Subject: [PATCH 1/2] fix: correct CodeSelectionMenu positioning to follow actual selection - Replace hardcoded x=225 with position.x so menu follows selection horizontally - Convert editor-relative coordinates to viewport coordinates by adding editorRect.left/top - Use getEndPosition for Y so menu appears above last line of multi-line selections - Use getStartPosition for X so menu anchors to selection start, not end cursor Signed-off-by: ML-dev-crypto --- src/components/CodeSelectionMenu.tsx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/CodeSelectionMenu.tsx b/src/components/CodeSelectionMenu.tsx index d2df0c92..38df8648 100644 --- a/src/components/CodeSelectionMenu.tsx +++ b/src/components/CodeSelectionMenu.tsx @@ -220,7 +220,7 @@ const CodeSelectionMenu: React.FC = ({ ref={menuRef} className="twp fixed bg-white border border-gray-300 rounded-lg shadow-lg py-1 z-50 flex" style={{ - left: Math.max(10, Math.min(225, window.innerWidth - 150)), + left: Math.max(10, Math.min(position.x, window.innerWidth - 150)), top: Math.max(10, Math.min(position.y, window.innerHeight - 50)), minWidth: '120px' }} @@ -260,23 +260,26 @@ export const useCodeSelection = (editorType: 'markdown' | 'concerto' | 'json') = if (selection && !selection.isEmpty()) { const selectedText = editor.getModel()?.getValueInRange(selection).trim(); if (selectedText && selectedText.length > 0) { - const position = editor.getScrolledVisiblePosition(selection.getStartPosition()); + const startPosition = editor.getScrolledVisiblePosition(selection.getStartPosition()); + const endPosition = editor.getScrolledVisiblePosition(selection.getEndPosition()); const editorContainer = editor.getDomNode()?.closest('.editorwrapper'); const editorRect = editorContainer?.getBoundingClientRect(); let x: number, y: number; - if (editorRect && position) { - x = Math.max(editorRect.left + 20, Math.min(position.left, editorRect.right - 150)); - y = Math.max(editorRect.top + 20, Math.min(position.top, editorRect.bottom - 50)); + if (!startPosition || !endPosition) { + return; + } + + if (editorRect) { + x = Math.max(editorRect.left + 20, Math.min(editorRect.left + startPosition.left, editorRect.right - 150)); + y = Math.max(editorRect.top + 20, Math.min(editorRect.top + endPosition.top - 40, editorRect.bottom - 50)); x = Math.max(10, Math.min(x, window.innerWidth - 150)); y = Math.max(10, Math.min(y, window.innerHeight - 50)); - } else if (position) { - x = Math.max(10, Math.min(position.left, window.innerWidth - 150)); - y = Math.max(10, Math.min(position.top, window.innerHeight - 50)); } else { - return; + x = Math.max(10, Math.min(startPosition.left, window.innerWidth - 150)); + y = Math.max(10, Math.min(endPosition.top - 40, window.innerHeight - 50)); } setSelectedText(selectedText); From c77844cb1a54bddecb7b2924ac4f11013841d359 Mon Sep 17 00:00:00 2001 From: Ansh Rai Date: Thu, 2 Apr 2026 20:50:12 +0530 Subject: [PATCH 2/2] fix: convert editor-local coords to viewport in fallback branch When .editorwrapper container is not found, the fallback branch was using editor-local coordinates directly as viewport coordinates, causing the menu to appear near the page origin. Fix: use editor.getDomNode().getBoundingClientRect() to get the editor's viewport offset and add it to startPosition.left and endPosition.top before clamping. Return early if getDomNode() returns null. Signed-off-by: Ansh Rai --- src/components/CodeSelectionMenu.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/CodeSelectionMenu.tsx b/src/components/CodeSelectionMenu.tsx index 38df8648..c73acfcb 100644 --- a/src/components/CodeSelectionMenu.tsx +++ b/src/components/CodeSelectionMenu.tsx @@ -278,8 +278,13 @@ export const useCodeSelection = (editorType: 'markdown' | 'concerto' | 'json') = x = Math.max(10, Math.min(x, window.innerWidth - 150)); y = Math.max(10, Math.min(y, window.innerHeight - 50)); } else { - x = Math.max(10, Math.min(startPosition.left, window.innerWidth - 150)); - y = Math.max(10, Math.min(endPosition.top - 40, window.innerHeight - 50)); + const editorDomRect = editor.getDomNode()?.getBoundingClientRect(); + if (!editorDomRect) { + return; + } + + x = Math.max(10, Math.min(editorDomRect.left + startPosition.left, window.innerWidth - 150)); + y = Math.max(10, Math.min(editorDomRect.top + endPosition.top - 40, window.innerHeight - 50)); } setSelectedText(selectedText);