Skip to content

Chat Flicker Scroll Snap#524

Merged
arul28 merged 2 commits into
mainfrom
ade/chat-flicker-scroll-snap-7ffceeec
Jun 3, 2026
Merged

Chat Flicker Scroll Snap#524
arul28 merged 2 commits into
mainfrom
ade/chat-flicker-scroll-snap-7ffceeec

Conversation

@arul28
Copy link
Copy Markdown
Owner

@arul28 arul28 commented Jun 3, 2026

Summary

Describe the change.

What Changed

Key files and behaviors.

Validation

How you tested.

Risks

Anything to watch.

ADE   Open in ADE  ·  ade/chat-flicker-scroll-snap-7ffceeec branch  ·  PR #524

Summary by CodeRabbit

  • Improvements
    • Enhanced chat message auto-scroll behavior during streaming. The app now respects user scrolling intent—if you scroll upward while new messages are streaming, auto-scroll pauses instead of forcing the view back to the bottom.
    • Improved chat history recovery and merge logic for more reliable message synchronization and data integrity.

Greptile Summary

This PR improves the auto-scroll experience in the chat view by detecting user scroll intent (wheel and touch events) before new streaming content arrives and triggers an auto-snap. It also refines mergeChatHistorySnapshot to preserve object identity for unchanged events, enabling React to skip unnecessary re-renders.

  • Scroll intent detection: handleWheel and handleTouchMove call releaseBottomStickinessForUserScroll before the RAF-based auto-scroll fires, so upward gestures during streaming reliably break free. shouldStickToBottomAfterScroll introduces hysteresis: re-sticking only happens when the user returns to within 24 px of the bottom.
  • History merge optimisation: mergeChatHistorySnapshot now builds a key→entry map over existing and substitutes matching parsed entries with their original object references, short-circuiting to return the same array when nothing changed.

Confidence Score: 4/5

Safe to merge with the pinch-to-zoom guard applied; without it, zooming in during streaming silently disables auto-scroll for the rest of the session.

The wheel handler releases auto-scroll stickiness on any negative deltaY without checking ctrlKey. Trackpad pinch-to-zoom delivers exactly those events (negative deltaY, ctrlKey true) but does not move scrollTop, so handleScroll never fires to re-engage stickiness — leaving auto-scroll permanently disabled for the conversation. Everything else in the PR (touch handling, hysteresis logic, history merge) looks correct and is well-covered by tests.

apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx — specifically the handleWheel callback

Important Files Changed

Filename Overview
apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx Adds wheel/touch intent detection to break auto-scroll stickiness before streaming content snaps back; handleWheel misses the ctrlKey guard needed to ignore pinch-to-zoom gestures, which can permanently disable auto-scroll.
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx mergeChatHistorySnapshot now preserves object identity for unchanged events (dedup-key lookup via Map) and short-circuits by returning the original array when no entries changed; logic is correct and well-tested.
apps/desktop/src/renderer/components/chat/AgentChatMessageList.test.tsx Adds unit tests for shouldStickToBottomAfterScroll and an integration test verifying that an upward wheel event breaks streaming auto-scroll; coverage is appropriate for the new behavior.
apps/desktop/src/renderer/components/chat/AgentChatPane.test.tsx Adds two tests for the mergeChatHistorySnapshot identity-preservation optimization; both cases (fully identical and partially matching) are covered.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User wheel / touch event] --> B{Event type}
    B -->|onWheel deltaY < 0| C{ctrlKey?}
    C -->|No - scroll up| D[releaseBottomStickinessForUserScroll]
    C -->|Yes - pinch-to-zoom| E[⚠ Bug: also releases stickiness]
    B -->|onTouchMove nextY - prevY > 2px| D
    D --> F[stickToBottomRef = false\ncancel RAF]
    F --> G[Streaming content grows\nResizeObserver fires]
    G --> H{stickToBottomRef?}
    H -->|true| I[scrollToBottomSoon RAF]
    H -->|false| J[No auto-scroll ✓]
    K[onScroll] --> L[shouldStickToBottomAfterScroll]
    L --> M{wasStuckToBottom?}
    M -->|true| N[stick if dist < 160 px]
    M -->|false| O[stick if dist ≤ 24 px]
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx:4478-4482
**Pinch-to-zoom kills auto-scroll permanently**

On trackpads, browsers fire `wheel` events with `ctrlKey: true` when the user pinch-zooms. Zooming in (spreading fingers) produces `deltaY < 0`, so this handler calls `releaseBottomStickinessForUserScroll()` — which sets `stickToBottomRef.current = false` and cancels the RAF. Crucially, pinch-to-zoom does **not** move `scrollTop`, so `handleScroll` never fires to re-engage stickiness. The result: a user who zooms in while a message is streaming silently loses auto-scroll for the rest of the conversation and must manually click "Jump to latest".

```suggestion
  const handleWheel = useCallback((event: React.WheelEvent<HTMLDivElement>) => {
    if (event.deltaY < 0 && !event.ctrlKey) {
      releaseBottomStickinessForUserScroll();
    }
  }, [releaseBottomStickinessForUserScroll]);
```

Reviews (2): Last reviewed commit: "Address chat scroll review note" | Re-trigger Greptile

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jun 3, 2026 8:46am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR improves chat rendering during streaming and snapshot recovery by introducing dual-threshold scroll stickiness with explicit user-gesture release, and updating snapshot merging to preserve object identity for deduplicated events.

Changes

Chat Streaming and Snapshot Recovery

Layer / File(s) Summary
Scroll stickiness threshold and decision logic
apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx
STICK_RESUME_THRESHOLD_PX defines a smaller distance threshold for resuming bottom-follow after user scroll. New exported helper shouldStickToBottomAfterScroll uses larger STICK_THRESHOLD_PX when already stuck and smaller STICK_RESUME_THRESHOLD_PX when not stuck.
User scroll and gesture release mechanism
apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx
lastTouchYRef tracks most recent touch Y coordinate. releaseBottomStickinessForUserScroll() drops sticky state, clears pending scroll targets, and cancels scheduled scroll-to-bottom animation on user input.
Scroll and gesture event handling integration
apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx
handleScroll now uses shouldStickToBottomAfterScroll for sticky-state computation. Wheel handler detects upward wheel scrolling; touch handlers detect sufficient delta (>2px) to trigger release. Scroll container is wired to onWheel, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel handlers.
Scroll stickiness behavior validation
apps/desktop/src/renderer/components/chat/AgentChatMessageList.test.tsx
Tests import shouldStickToBottomAfterScroll and validate decision logic across distance and stickiness combinations. Additional tests simulate user upward wheel intent during streaming and confirm scroll position remains stable after rerender with extra streamed output.
Chat history snapshot identity preservation
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
mergeChatHistorySnapshot builds existingByKey map and normalizes parsed events by replacing matches with existing event objects. Merged result is assembled from normalizedParsed and tail, with identity-preservation check returning the original existing array when reference-equal.
Snapshot merge identity validation
apps/desktop/src/renderer/components/chat/AgentChatPane.test.tsx
Test cases verify that recovery input matching existing snapshot returns same array/object identities, and that existing entries are reused by reference with only new recovery events appended.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • arul28/ADE#175: The mergeChatHistorySnapshot identity-preservation changes are directly related to prior chat history snapshot and merge behavior work in AgentChatPane.

Suggested labels

desktop

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Chat Flicker Scroll Snap' is partially related to the changeset. It references scroll behavior, which is a real aspect of the changes, but is vague and doesn't clearly convey the specific improvements: better bottom-stickiness thresholds, user-input release handling, and array identity preservation in chat history merging. Consider using a more specific title that better describes the main changes, such as 'Improve chat bottom-stickiness behavior with threshold tuning and user-input release' or 'Fix chat scroll stability with separate resume thresholds and identity preservation'.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/chat-flicker-scroll-snap-7ffceeec

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Jun 3, 2026

@copilot review but do not make fixes

Comment thread apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx
Comment thread apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx Outdated
@arul28 arul28 merged commit 39274e4 into main Jun 3, 2026
28 checks passed
@arul28 arul28 deleted the ade/chat-flicker-scroll-snap-7ffceeec branch June 3, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant