Skip to content

fix(web): restore arrow-key scrolling in chat after click or F6 - #654

Merged
lastobelus merged 1 commit into
lastcode/mainfrom
lastcode/fix-chat-arrow-key-scrolling
Nov 8, 2026
Merged

lastobelus merged 1 commit into
lastcode/mainfrom
lastcode/fix-chat-arrow-key-scrolling

Conversation

@lastobelus

@lastobelus lastobelus commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

🐛 Problem

After clicking the conversation or pressing F6 to move there, ArrowUp/ArrowDown did nothing. Focus landed on the outer data-workspace-area="conversation" wrapper, which doesn't scroll. The timeline is inside that wrapper, so native keyboard scrolling cannot reach it. An earlier local repair (7d9be906f9101d2dd452486da24b9e1482e260c6) never shipped in LastCode.

🔧 Fix

Focus the real scroller, the timeline, so native arrow-key scrolling works again.

  • Timeline focus (MessagesTimeline.tsx): the scroll node gets tabIndex={-1} and data-workspace-focus-default, so clicks and F6 land on it. If an empty conversation held focus before the first list mounted, focus transfers to that list; focus elsewhere stays put.
  • Page keys (timelineViewport.ts): PageUp/PageDown now also fire when the key target is the timeline, not just the outer area. Paging stays composer-aware.
  • F6 target (workspaceFocus.ts): a remembered area is only a fallback. Controls mounted since now take precedence over it, so F6 reaches the timeline.
  • Focus ring (index.css): the ring is drawn on the conversation area via :has(.messages-timeline-scroll:focus-visible). The timeline's own outline is off because its top fade mask would hide it.
  • Window return (ChatView.logic.ts): shouldRefocusComposerOnWindowFocus keeps a keyboard-focused timeline (:focus-visible) where it is. A clicked timeline still yields to the composer.

✅ Proof

  • Before: four regression failures observed.
  • After: 62 browser tests pass (one pre-existing quarantined case skipped).
  • New tests: arrow keys scroll after F6 and after a click, including when an empty conversation gains messages without another F6 press (MessagesTimeline.browser.test.tsx), plus page keys, F6 target selection, and window-return cases.
  • Scoped checks: targeted lint, format, typecheck and React compiler checks pass.
  • QA: click, F6 and page-key behavior verified in an isolated running app.
  • check:changed: passed, including 227 tests and 4 compiler checks.
  • Carry replay: exact same-base compilation passes. The repair stays with the existing workspace-focus and composer-aware paging changes in the Incubator group.

Evidence

Before: ArrowUp leaves the chat stationary.

Before: chat does not scroll

After: ArrowUp moves the chat, and the keyboard focus ring remains visible.

After: chat scrolls with keyboard focus visible

Recording of arrow scrolling after a click and Shift+F6, followed by page keys:

897e07de-4dc0-4792-bef9-8a18bbbfaffd-c875b968-9595-4de1-a0ff-3b5d203c5db0-mp4.mp4

🚦 Status

  • Quick CI: passed on pre-rebase head 975adada6dc0fc5bf11a556ef97ef88055d88746 (base 82a0d94aa92fced9dad13c12fa10277b47358945). The latest rebase only brings in unrelated tooling.
  • Pending: current GitHub CI and Codex review.

Local review: 3 rounds with gpt-6.1-terra (xhigh), approved.

Source: https://redirect.github.com/pingdotgg/t3code/pull/27209
Pinned upstream head: af39cb731be45f64815ae9bc792066170689b94b.

Implemented with GPT-6.1-Sol in the Codex harness.

@lastobelus lastobelus changed the title fix(web): restore cursor-key scrolling in chat fix(web): restore arrow-key scrolling in chat after click or F6 Nov 8, 2026
@lastobelus
lastobelus force-pushed the lastcode/fix-chat-arrow-key-scrolling branch from 8779a6e to a3b0737 Compare November 8, 2026 23:10
@lastobelus
lastobelus marked this pull request as ready for review November 8, 2026 23:11
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-08T23:18:32.346588Z 2585695 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Focus the conversation scrolling element after a click or F6, including when the first messages arrive. Preserve page-key overlap, focus visibility, and keyboard focus on window return.

Restore the locally prepared repair from 7d9be906f9101d2dd452486da24b9e1482e260c6, which had not been published to LastCode.

Carry-Group: incubator

Carry-Upstream: https://redirect.github.com/pingdotgg/t3code/pull/27209 af39cb7

Carry-Observation: The focus repair is inseparable from the existing composer-aware paging and workspace focus changes in incubator; replay them together after those dependencies.

Implemented with GPT-6.1-Sol in the Codex harness.
@lastobelus
lastobelus force-pushed the lastcode/fix-chat-arrow-key-scrolling branch from a3b0737 to 2585695 Compare November 8, 2026 23:16
@lastobelus

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 258569574b

ℹ️ 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".

@lastobelus
lastobelus merged commit 0a9476e into lastcode/main Nov 8, 2026
24 of 38 checks passed
@lastobelus
lastobelus deleted the lastcode/fix-chat-arrow-key-scrolling branch November 8, 2026 23:30
lastobelus added a commit that referenced this pull request Nov 13, 2026
Upstream sends arrow and page keys to the focused element. Since the timeline
scroller became focusable (upstream pingdotgg#27209), ArrowUp/ArrowDown with the
pointer over the sidebar scrolled the conversation. LastCode's per-surface
patches covered page keys only and kept regressing as upstream moved.

One router, lastcodeScrollKeys.ts, now owns the rule: the pointer picks the
pane, focus decides inside it. Text fields and keyboard widgets keep their
keys over their own pane (the composer over its conversation keeps caret
moves, prompt recall and its page handoff); any other key parks the pointer
for arrows until the mouse moves; suggestion lists, the terminal, open
menus, keybindings and modified keys are left alone. The timeline registers
as an owner so routed scrolls release follow and page above the composer.
It replaces the hover-card key handler and the timeline page fallback.

docs/lastcode/keyboard-scrolling.md records the desired behaviour, the
upstream seams it rests on, and when a checkpoint is fighting upstream.

Carry-Group: incubator
Carry-Observation: Inseparable from its tests and docs; the timeline owner registration and hover-card removal replace incubator code in the same mechanism.
Carry-Supersedes: lastCode #654 timeline page fallback; thread hover scroll keys
Carry-Applies-To: upstream 7e1a058 (focus-driven native scrolling, pingdotgg#27209)

Co-Authored-By: Claude <[email protected]>
lastobelus added a commit that referenced this pull request Nov 14, 2026
Upstream sends arrow and page keys to the focused element. Since the timeline
scroller became focusable (upstream pingdotgg#27209), ArrowUp/ArrowDown with the
pointer over the sidebar scrolled the conversation. LastCode's per-surface
patches covered page keys only and kept regressing as upstream moved.

One router, lastcodeScrollKeys.ts, now owns the rule: the pointer picks the
pane, focus decides inside it. Text fields and keyboard widgets keep their
keys over their own pane (the composer over its conversation keeps caret
moves, prompt recall and its page handoff); any other key parks the pointer
for arrows until the mouse moves; suggestion lists, the terminal, open
menus, keybindings and modified keys are left alone. The timeline registers
as an owner so routed scrolls release follow and page above the composer.
It replaces the hover-card key handler and the timeline page fallback.

docs/lastcode/keyboard-scrolling.md records the desired behaviour, the
upstream seams it rests on, and when a checkpoint is fighting upstream.

Carry-Group: incubator
Carry-Observation: Inseparable from its tests and docs; the timeline owner registration and hover-card removal replace incubator code in the same mechanism.
Carry-Supersedes: lastCode #654 timeline page fallback; thread hover scroll keys
Carry-Applies-To: upstream 7e1a058 (focus-driven native scrolling, pingdotgg#27209)

Co-Authored-By: Claude <[email protected]>
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