mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Fix task conversation scroll reset
This commit is contained in:
@@ -811,10 +811,10 @@ export function AgentConversationScreen({
|
||||
emptyTitle="No conversation messages yet"
|
||||
hasComposerOverlay
|
||||
isLoading={messagesQuery.isLoading && timelineMessages.length === 0}
|
||||
layoutShiftKey={conversation.id}
|
||||
messageListPlacement="top"
|
||||
messages={timelineMessages}
|
||||
profiles={profiles}
|
||||
scrollResetKey={conversation.id}
|
||||
scrollContainerRef={timelineScrollRef}
|
||||
showInitialDayDivider={false}
|
||||
trailingContent={
|
||||
|
||||
@@ -794,7 +794,6 @@ export const ChannelPane = React.memo(function ChannelPane({
|
||||
hasComposerOverlay={hasMainComposerOverlay}
|
||||
hasOlderMessages={hasOlderMessages}
|
||||
isFetchingOlder={isFetchingOlder}
|
||||
layoutShiftKey={useSplitAuxiliaryPane ? "split" : "overlay"}
|
||||
isFollowingThreadById={isFollowingThreadById}
|
||||
isMessageUnreadById={isMessageUnreadById}
|
||||
personaLookup={personaLookup}
|
||||
|
||||
@@ -56,7 +56,7 @@ type MessageTimelineProps = {
|
||||
hasComposerOverlay?: boolean;
|
||||
contentTopPadding?: "chrome" | "compact";
|
||||
isFetchingOlder?: boolean;
|
||||
layoutShiftKey?: string | number | null;
|
||||
scrollResetKey?: string | number | null;
|
||||
messageListPlacement?: "bottom" | "top";
|
||||
messageFooters?: Record<string, React.ReactNode>;
|
||||
/** Map from lowercase pubkey → persona display name for bot members. */
|
||||
@@ -164,7 +164,7 @@ const MessageTimelineBase = React.forwardRef<
|
||||
contentTopPadding = "chrome",
|
||||
hasOlderMessages = true,
|
||||
isFetchingOlder = false,
|
||||
layoutShiftKey = null,
|
||||
scrollResetKey = null,
|
||||
messageListPlacement = "bottom",
|
||||
followThreadById,
|
||||
huddleMemberPubkeys,
|
||||
@@ -233,16 +233,15 @@ const MessageTimelineBase = React.forwardRef<
|
||||
liveSnapshot,
|
||||
});
|
||||
const isRenderPending = deferredSnapshot !== liveSnapshot;
|
||||
const scrollRouteKey = `${channelId ?? "none"}:${layoutShiftKey ?? "none"}`;
|
||||
const scrollIdentityKey = `${channelId ?? "none"}:${scrollResetKey ?? "none"}`;
|
||||
const scrollRestorationId = targetMessageId
|
||||
? `message-timeline:${scrollRouteKey}:target:${targetMessageId}`
|
||||
: `message-timeline:${scrollRouteKey}`;
|
||||
// Keep the scroll node's DOM lifetime scoped to a channel. TanStack Router's
|
||||
// scroll-restoration listener runs outside React and may write a saved
|
||||
// scrollTop into the current scroll element during navigation; reusing the
|
||||
// same node across channel routes can leave the newly-loaded message list
|
||||
// painted at a stale offset until the user's next scroll event forces layout.
|
||||
const scrollContainerDomKey = scrollRouteKey;
|
||||
? `message-timeline:${scrollIdentityKey}:target:${targetMessageId}`
|
||||
: `message-timeline:${scrollIdentityKey}`;
|
||||
// Keep the scroll node's DOM lifetime scoped to the rendered conversation.
|
||||
// Channel layout changes (for example opening the thread panel) should keep
|
||||
// this stable, while switching task conversations should start from a fresh
|
||||
// scroll state.
|
||||
const scrollContainerDomKey = scrollIdentityKey;
|
||||
|
||||
const timelineBodySurface = selectTimelineBodySurface({
|
||||
deferredCount: deferredMessages.length,
|
||||
@@ -265,7 +264,7 @@ const MessageTimelineBase = React.forwardRef<
|
||||
isLoading: showTimelineSkeleton,
|
||||
messages: deferredMessages,
|
||||
onTargetReached,
|
||||
resetKey: scrollRouteKey,
|
||||
resetKey: scrollIdentityKey,
|
||||
scrollContainerRef,
|
||||
targetMessageId,
|
||||
});
|
||||
|
||||
@@ -38,10 +38,10 @@ type UseAnchoredScrollOptions = {
|
||||
/** Inner content element — must wrap every renderable row, including the
|
||||
* sentinel and bottom anchor. Used to schedule layout work on resize. */
|
||||
contentRef: React.RefObject<HTMLDivElement | null>;
|
||||
/** Resets when changed; lets us drop anchor + scroll state across channels. */
|
||||
/** Scopes channel-level side effects and observer subscriptions. */
|
||||
channelId?: string | null;
|
||||
/** Resets when changed; includes channel plus route-specific layout state. */
|
||||
resetKey?: string | null;
|
||||
resetKey?: string | number | null;
|
||||
/** Suppresses initial scroll-to-bottom while a skeleton is showing. */
|
||||
isLoading: boolean;
|
||||
/** Source of truth for the rendered list. Used to detect new-at-bottom
|
||||
|
||||
@@ -42,10 +42,14 @@ async function ensureTimelineScrollable(
|
||||
) {
|
||||
const input = senderPage.getByTestId("message-input");
|
||||
const sendButton = senderPage.getByTestId("send-message");
|
||||
const minimumSeedMessages = 8;
|
||||
|
||||
for (let index = 0; index < 24; index += 1) {
|
||||
const metrics = await getTimelineMetrics(receiverPage);
|
||||
if (metrics.scrollHeight > metrics.clientHeight + 160) {
|
||||
if (
|
||||
index >= minimumSeedMessages &&
|
||||
metrics.scrollHeight > metrics.clientHeight + 160
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user