diff --git a/entrypoints/content.ts b/entrypoints/content.ts index 0fef752..ee7bac1 100644 --- a/entrypoints/content.ts +++ b/entrypoints/content.ts @@ -27,7 +27,7 @@ export default defineContentScript({ const end = el.selectionEnd ?? -1; if (end - start >= 2) { const text = el.value.substring(start, end).trim(); - if (text.length >= 2) { + if (text.length > 10) { selectedText = text; storedStart = start; storedEnd = end; @@ -43,7 +43,7 @@ export default defineContentScript({ const sel = window.getSelection(); if (sel && sel.rangeCount > 0) { const text = sel.toString().trim(); - if (text.length >= 2) { + if (text.length > 10) { selectedText = text; storedRange = sel.getRangeAt(0).cloneRange(); // CLONE — selection will be lost later storedElement = null; @@ -98,29 +98,32 @@ export default defineContentScript({ // ─── Toolbar ────────────────────────────────────────────────────────────── - function getToolbarPosition(mouseX: number, mouseY: number) { + function getToolbarPosition(rect: DOMRect) { const TOOLBAR_W = 280; const TOOLBAR_H = 40; const MARGIN = 8; - const vpW = window.innerWidth; - const vpH = window.innerHeight; const scrollX = window.scrollX; const scrollY = window.scrollY; - let top = mouseY + scrollY - TOOLBAR_H - MARGIN; - let left = mouseX + scrollX - TOOLBAR_W / 2; + // Center above the selection rect + let left = rect.left + scrollX + rect.width / 2 - TOOLBAR_W / 2; + let top = rect.top + scrollY - TOOLBAR_H - MARGIN; - left = Math.max(scrollX + MARGIN, Math.min(left, scrollX + vpW - TOOLBAR_W - MARGIN)); - if (top < scrollY + MARGIN) top = mouseY + scrollY + MARGIN + 16; - if (top + TOOLBAR_H > scrollY + vpH - MARGIN) top = mouseY + scrollY - TOOLBAR_H - MARGIN - 16; + // Clamp horizontally to viewport + left = Math.max(scrollX + MARGIN, Math.min(left, scrollX + window.innerWidth - TOOLBAR_W - MARGIN)); + + // Flip below if not enough space above + if (top < scrollY + MARGIN) { + top = rect.bottom + scrollY + MARGIN; + } return { top, left }; } - function showToolbar(mouseX: number, mouseY: number) { + function showToolbar(rect: DOMRect) { hideToolbar(); - const { top, left } = getToolbarPosition(mouseX, mouseY); + const { top, left } = getToolbarPosition(rect); toolbar = document.createElement('div'); toolbar.id = 'lexai-toolbar'; @@ -412,16 +415,31 @@ export default defineContentScript({ if (target?.closest?.('[data-lexai="true"]')) return; // Capture selection state IMMEDIATELY — positions are valid right now. - // The setTimeout below is only for showing the toolbar (lets browser finalise). + // The setTimeout below lets the browser finalise the selection before we read it. const captured = captureSelectionNow(); setTimeout(() => { - if (captured && selectedText) { - showToolbar(e.clientX + window.scrollX, e.clientY + window.scrollY); + if (!captured || !selectedText || selectedText.length <= 10) { + hideToolbar(); + return; + } + + // Get bounding rect from the live selection (still valid inside setTimeout) + let rect: DOMRect | null = null; + const sel = window.getSelection(); + if (sel && sel.rangeCount > 0) { + rect = sel.getRangeAt(0).getBoundingClientRect(); + } else if (storedElement) { + // fallback: use the element's bounding rect for textarea/input + rect = storedElement.getBoundingClientRect(); + } + + if (rect && rect.width > 0) { + showToolbar(rect); } else { hideToolbar(); } - }, 50); + }, 10); }); // Hide toolbar when clicking elsewhere (not on our UI)