From 783fb5c5b2f6d110942397927817d50d383ef16a Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Tue, 9 Dec 2025 17:09:30 +0000 Subject: [PATCH] Defer initial message scroll until list renders --- .../ui/src/components/message-block-list.tsx | 39 ++++++++++++++----- .../ui/src/components/message-section.tsx | 27 ++++++++++++- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/message-block-list.tsx b/packages/ui/src/components/message-block-list.tsx index 193c97cc..74278e38 100644 --- a/packages/ui/src/components/message-block-list.tsx +++ b/packages/ui/src/components/message-block-list.tsx @@ -27,24 +27,45 @@ interface MessageBlockListProps { onContentRendered?: () => void setBottomSentinel: (element: HTMLDivElement | null) => void suspendMeasurements?: () => boolean + onInitialRenderComplete?: () => void } export default function MessageBlockList(props: MessageBlockListProps) { + const totalMessages = () => props.messageIds().length + let renderedCount = 0 + let initialRenderReported = false + const handleBlockRendered = () => { + if (initialRenderReported) return + renderedCount += 1 + if (renderedCount >= totalMessages() && totalMessages() > 0) { + initialRenderReported = true + renderedCount = 0 + props.onInitialRenderComplete?.() + } + } + + createEffect(() => { + if (props.loading) { + renderedCount = 0 + initialRenderReported = false + } + }) + return ( <> {(messageId) => { return ( !props.loading} - suspendMeasurements={props.suspendMeasurements} - > - + id={getMessageAnchorId(messageId())} + cacheKey={messageId()} + scrollContainer={props.scrollContainer} + threshold={VIRTUAL_ITEM_MARGIN_PX} + placeholderClass="message-stream-placeholder" + virtualizationEnabled={() => !props.loading} + suspendMeasurements={props.suspendMeasurements} + onMeasured={handleBlockRendered} + > { + const loading = Boolean(props.loading) + if (loading) { + pendingInitialScroll = true + setInitialRenderComplete(false) + return + } + if (pendingInitialScroll && initialRenderComplete()) { + pendingInitialScroll = false + requestScrollToBottom(false) + } + }) + createEffect(() => { if (!props.onQuoteSelection) { clearQuoteSelection() } }) + createEffect(() => { if (typeof document === "undefined") return const handleSelectionChange = () => updateQuoteSelectionFromSelection() @@ -647,6 +671,7 @@ export default function MessageSection(props: MessageSectionProps) { onContentRendered={handleContentRendered} setBottomSentinel={setBottomSentinel} suspendMeasurements={() => props.isActive === false} + onInitialRenderComplete={handleInitialRenderComplete} />