diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx index 7fb01401f..c8851acc6 100644 --- a/surfsense_web/components/assistant-ui/thread.tsx +++ b/surfsense_web/components/assistant-ui/thread.tsx @@ -28,8 +28,7 @@ import { import { AnimatePresence, motion } from "motion/react"; import Image from "next/image"; import { useParams } from "next/navigation"; -import { type FC, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; -import { createPortal } from "react-dom"; +import { type FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { agentToolsAtom, disabledToolsAtom, @@ -339,10 +338,7 @@ const Composer: FC = () => { const [showPromptPicker, setShowPromptPicker] = useState(false); const [mentionQuery, setMentionQuery] = useState(""); const [actionQuery, setActionQuery] = useState(""); - const [containerPos, setContainerPos] = useState({ bottom: "200px", left: "50%", top: "auto" }); const editorRef = useRef(null); - const editorContainerRef = useRef(null); - const composerBoxRef = useRef(null); const documentPickerRef = useRef(null); const promptPickerRef = useRef(null); const viewportRef = useRef(null); @@ -363,38 +359,13 @@ const Composer: FC = () => { viewportRef.current = document.querySelector(".aui-thread-viewport"); }, []); - // Compute picker positions using ResizeObserver to avoid layout reads during render - useLayoutEffect(() => { - if (!editorContainerRef.current) return; - - const updatePosition = () => { - if (!editorContainerRef.current) return; - const rect = editorContainerRef.current.getBoundingClientRect(); - const composerRect = composerBoxRef.current?.getBoundingClientRect(); - setContainerPos({ - bottom: `${window.innerHeight - rect.top + 8}px`, - left: `${rect.left}px`, - top: composerRect ? `${composerRect.bottom + 8}px` : "auto", - }); - }; - - updatePosition(); - const ro = new ResizeObserver(updatePosition); - ro.observe(editorContainerRef.current); - if (composerBoxRef.current) { - ro.observe(composerBoxRef.current); - } - - return () => ro.disconnect(); - }, []); - const electronAPI = useElectronAPI(); const [clipboardInitialText, setClipboardInitialText] = useState(); const clipboardLoadedRef = useRef(false); useEffect(() => { if (!electronAPI || clipboardLoadedRef.current) return; clipboardLoadedRef.current = true; - electronAPI.getQuickAskText().then((text) => { + electronAPI.getQuickAskText().then((text: string) => { if (text) { setClipboardInitialText(text); } @@ -705,28 +676,54 @@ const Composer: FC = () => { ); return ( - + -
+ {showDocumentPopover && ( +
+ { + setShowDocumentPopover(false); + setMentionQuery(""); + }} + initialSelectedDocuments={mentionedDocuments} + externalSearch={mentionQuery} + /> +
+ )} + {showPromptPicker && ( +
+ { + setShowPromptPicker(false); + setActionQuery(""); + }} + externalSearch={actionQuery} + /> +
+ )} +
{clipboardInitialText && ( setClipboardInitialText(undefined)} /> )} - {/* Inline editor with @mention support */} -
+
{ className="min-h-[24px]" />
- {/* Document picker popover (portal to body for proper z-index stacking) */} - {showDocumentPopover && - typeof document !== "undefined" && - createPortal( - { - setShowDocumentPopover(false); - setMentionQuery(""); - }} - initialSelectedDocuments={mentionedDocuments} - externalSearch={mentionQuery} - containerStyle={{ - bottom: containerPos.bottom, - left: containerPos.left, - }} - />, - document.body - )} - {showPromptPicker && - typeof document !== "undefined" && - createPortal( - { - setShowPromptPicker(false); - setActionQuery(""); - }} - externalSearch={actionQuery} - containerStyle={{ - position: "fixed", - ...(clipboardInitialText - ? { top: containerPos.top } - : { bottom: containerPos.bottom }), - left: containerPos.left, - zIndex: 50, - }} - />, - document.body - )} diff --git a/surfsense_web/components/new-chat/document-mention-picker.tsx b/surfsense_web/components/new-chat/document-mention-picker.tsx index a087463ba..f2985278d 100644 --- a/surfsense_web/components/new-chat/document-mention-picker.tsx +++ b/surfsense_web/components/new-chat/document-mention-picker.tsx @@ -29,8 +29,6 @@ interface DocumentMentionPickerProps { onDone: () => void; initialSelectedDocuments?: Pick[]; externalSearch?: string; - /** Positioning styles for the container */ - containerStyle?: React.CSSProperties; } const PAGE_SIZE = 20; @@ -75,7 +73,6 @@ export const DocumentMentionPicker = forwardRef< onDone, initialSelectedDocuments = [], externalSearch = "", - containerStyle, }, ref ) { @@ -396,11 +393,7 @@ export const DocumentMentionPicker = forwardRef< return (
void; onDone: () => void; externalSearch?: string; - containerStyle?: React.CSSProperties; } export const PromptPicker = forwardRef(function PromptPicker( - { onSelect, onDone, externalSearch = "", containerStyle }, + { onSelect, onDone, externalSearch = "" }, ref ) { const setUserSettingsDialog = useSetAtom(userSettingsDialogAtom); @@ -113,13 +112,7 @@ export const PromptPicker = forwardRef(funct ); return ( -
+
{isLoading ? (