diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx index ceef9f2e1..dc8966571 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx @@ -267,12 +267,18 @@ export function DocumentsTableShell({ const [metadataJson, setMetadataJson] = useState | null>(null); const [metadataLoading, setMetadataLoading] = useState(false); const [previewScrollPos, setPreviewScrollPos] = useState<"top" | "middle" | "bottom">("top"); + const previewRafRef = useRef(); const handlePreviewScroll = useCallback((e: React.UIEvent) => { const el = e.currentTarget; - const atTop = el.scrollTop <= 2; - const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; - setPreviewScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + if (previewRafRef.current) return; + previewRafRef.current = requestAnimationFrame(() => { + const atTop = el.scrollTop <= 2; + const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; + setPreviewScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + previewRafRef.current = undefined; + }); }, []); + useEffect(() => () => { if (previewRafRef.current) cancelAnimationFrame(previewRafRef.current); }, []); const [deleteDoc, setDeleteDoc] = useState(null); const [isDeleting, setIsDeleting] = useState(false); diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx index 0d0163d8a..0f230cec3 100644 --- a/surfsense_web/components/assistant-ui/thread.tsx +++ b/surfsense_web/components/assistant-ui/thread.tsx @@ -816,12 +816,18 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false const isDesktop = useMediaQuery("(min-width: 640px)"); const { openDialog: openUploadDialog } = useDocumentUploadDialog(); const [toolsScrollPos, setToolsScrollPos] = useState<"top" | "middle" | "bottom">("top"); + const toolsRafRef = useRef(); const handleToolsScroll = useCallback((e: React.UIEvent) => { const el = e.currentTarget; - const atTop = el.scrollTop <= 2; - const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; - setToolsScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + if (toolsRafRef.current) return; + toolsRafRef.current = requestAnimationFrame(() => { + const atTop = el.scrollTop <= 2; + const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; + setToolsScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + toolsRafRef.current = undefined; + }); }, []); + useEffect(() => () => { if (toolsRafRef.current) cancelAnimationFrame(toolsRafRef.current); }, []); const isComposerTextEmpty = useAuiState(({ composer }) => { const text = composer.text?.trim() || ""; return text.length === 0; diff --git a/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx index 72400a589..4aa8d4c60 100644 --- a/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx @@ -178,12 +178,18 @@ export function InboxSidebarContent({ const [mounted, setMounted] = useState(false); const [openDropdown, setOpenDropdown] = useState<"filter" | null>(null); const [connectorScrollPos, setConnectorScrollPos] = useState<"top" | "middle" | "bottom">("top"); + const connectorRafRef = useRef(); const handleConnectorScroll = useCallback((e: React.UIEvent) => { const el = e.currentTarget; - const atTop = el.scrollTop <= 2; - const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; - setConnectorScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + if (connectorRafRef.current) return; + connectorRafRef.current = requestAnimationFrame(() => { + const atTop = el.scrollTop <= 2; + const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 2; + setConnectorScrollPos(atTop ? "top" : atBottom ? "bottom" : "middle"); + connectorRafRef.current = undefined; + }); }, []); + useEffect(() => () => { if (connectorRafRef.current) cancelAnimationFrame(connectorRafRef.current); }, []); const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); const [markingAsReadId, setMarkingAsReadId] = useState(null);