Sync chat timeline and mobile UX#133
Conversation
|
Warning Review limit reached
Next review available in: 56 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (21)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 730be69678
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| scrollNode.addEventListener("touchmove", handleManualNavigation, { | ||
| passive: true, | ||
| }); | ||
| scrollNode.addEventListener("pointerdown", handleManualNavigation, { |
There was a problem hiding this comment.
Avoid cancelling live follow on ordinary clicks
Because pointerdown bubbles from all controls inside the scroll node, clicking a copy button, link, disclosure, or message area while a response is streaming calls cancelTimelineLiveFollowForUserNavigation() even though no scroll gesture occurred. In the anchored-send path maintainScrollAtEnd is disabled, so after such a click subsequent tokens stop auto-following and the user can be left behind the live edge unexpectedly.
Useful? React with 👍 / 👎.
| const onToggleTurnFold = useCallback((turnId: TurnId) => { | ||
| setFoldToggleSettling(true); | ||
| setExpandedTurnIds((existing) => { |
There was a problem hiding this comment.
Suspend end anchoring when toggling turn folds
This fold toggle now only mutates expandedTurnIds, while the list below keeps maintainScrollAtEnd enabled whenever there is no active anchoredEndSpace. When a user expands/collapses a "Worked for…" fold while already at the live edge, LegendList can re-pin the bottom as rows are inserted/removed above the terminal message, pulling the fold control out of view; the previous settling guard handled exactly this case and was removed without an equivalent for turn folds.
Useful? React with 👍 / 👎.
730be69 to
4798ab9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4798ab9fd6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
4798ab9 to
6258f37
Compare
d4cdb21 to
5f0839b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6258f37f9e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "group/minimap pointer-events-auto absolute top-0 left-0 z-40 hidden w-18 [@media(pointer:fine)]:block", | ||
| hasPersistentGutter | ||
| ? "opacity-100" | ||
| : "opacity-0 transition-opacity duration-150 hover:opacity-100 focus-within:opacity-100", |
There was a problem hiding this comment.
Avoid letting the hidden minimap steal message clicks
When the viewport is too narrow for a persistent gutter (hasPersistentGutter is false for common desktop widths below the helper's 864px threshold), this minimap is only made transparent, but it remains pointer-events-auto and is absolutely placed over the left edge of the timeline. In conversations with at least two user messages, the invisible rail/button can intercept clicks, link activation, and text selection in the first ~50px of assistant content until the user happens to hover it, which makes normal message interaction fail in that strip.
Useful? React with 👍 / 👎.
5f0839b to
ead5a2c
Compare
6258f37 to
eeacb89
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eeacb895c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| scrollNode.addEventListener("wheel", handleManualNavigation, { | ||
| passive: true, | ||
| }); |
There was a problem hiding this comment.
Gate wheel cancellation on vertical timeline movement
When a response is streaming, any wheel event bubbling to the timeline cancels live-follow, even if the wheel gesture is consumed by a nested horizontal scroller such as an overflowing code block/diff or is otherwise not moving the vertical list. In that case the user has not navigated away from the live edge, but subsequent tokens can stop auto-following; check the wheel delta/scroll target or cancel only after an actual timeline scroll.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eeacb895c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| row.kind === "message" ? row.message.id : null, | ||
| ), | ||
| [anchorMessageId, rows], | ||
| const minimapItems = useMemo(() => deriveTimelineMinimapItems(rows), [rows]); |
There was a problem hiding this comment.
Avoid building hidden minimap previews while streaming
This computes minimap previews on every rows change even when TimelineMinimap will immediately return null for threads with fewer than two user messages. During a first large streaming response, each token update changes rows, then deriveTimelineMinimapItems scans the row list and compactMinimapPreview regex-copies the full assistant text even though no minimap can render; gate this work on having enough user rows or compute preview text lazily/truncated.
Useful? React with 👍 / 👎.
eeacb89 to
51615cb
Compare
244ad30 to
35a7c5c
Compare
51615cb to
261c515
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 261c51535c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (pendingTimelineAnchorRef.current !== messageId) { | ||
| return; |
There was a problem hiding this comment.
Clear stale anchor after live-follow cancellation
With this guard now in place, a user who scrolls away immediately after sending can leave timelineAnchor.messageId stuck: the cancellation path clears pendingTimelineAnchorRef, so this branch returns without ever clearing the React anchor state. MessagesTimeline still derives anchoredEndSpace from that prop and disables maintainScrollAtEnd while it is present, so that thread can keep reserved anchor space/end-following disabled until another send or thread switch. Clear the timeline anchor here, or when cancelling the pending anchor.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 88b1735e36
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| useEffect(() => { | ||
| let removeListeners: (() => void) | null = null; | ||
| let frame: number | null = null; | ||
| let attemptsRemaining = 60; |
There was a problem hiding this comment.
Keep retrying until the timeline mounts
The new finite retry still leaves empty threads without the manual-navigation listeners if the user opens a new empty thread and waits more than about a second before sending the first prompt: while the placeholder is rendered getScrollableNode() stays null, the loop exhausts, and this effect will not rerun when rows appear because it only depends on activeThread?.id. During that first streamed response, wheel/touch/key scrolls are then treated as live-follow programmatic movement and can be suppressed, so the list can snap back to the end instead of letting the user read earlier content.
Useful? React with 👍 / 👎.
| isAtEndRef.current = true; | ||
| timelineScrollModeRef.current = "anchoring-new-turn"; | ||
| liveFollowUserScrollGenerationRef.current = anchorUserScrollGenerationRef.current; | ||
| pendingTimelineAnchorRef.current = messageIdForSend; |
There was a problem hiding this comment.
Clear pending anchors when send cleanup removes the row
If the send/start path fails before onAnchorReady runs and the failure cleanup removes this optimistic message, this pending anchor is never cleared because the missing row cannot fire onReady. The live-follow effect bails out while pendingTimelineAnchorRef is non-null, so after a failed send the thread can stop following new output until the user navigates or sends again; clear the pending/timeline anchor in the failure cleanup that removes messageIdForSend.
Useful? React with 👍 / 👎.
8216039 to
61135b3
Compare
8e8ba2e to
9ee152a
Compare
61135b3 to
acee6f6
Compare
9ee152a to
931ea0a
Compare
931ea0a to
53ee88c
Compare
53ee88c to
feb7380
Compare
Merge activity
|

What Changed
Ports chat scroll anchoring, timeline minimap and affordances, right-panel middle-click close, ultrathink CSS restoration, and mobile composer revision-gated updates.
Why
This aligns the fork with upstream chat timeline and mobile UX fixes while keeping the sync work reviewable as a separate stack slice.
UI Changes
Includes upstream chat timeline, right-panel, CSS, and mobile composer UI behavior updates.
Checklist
vp checkvp run typecheckvp run lint:mobilevp testhad one ACP timeout flake; rerunning that file passed