refactor(web): composer key handling lives in useComposerCommandKey#23060

merged1
refactor/split2-composer-footer-controls
refactor/split2-composer-command-keys
opened2d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 2d ago

The editor key handler and prompt-history navigation are about 140 lines in the composer body. The handler covers send shortcuts, the slash/mention menu keys, ArrowUp/ArrowDown history, the Shift+Tab plan toggle, and list continuation on Enter/Tab.

This PR moves:

  • navigatePromptHistory, replacePromptFromHistory, the history messages ref and onComposerCommandKey into useComposerCommandKey. The composer passes in the helpers it already had and keeps its existing onComposerCommandKeyStable wrapper. promptHistoryPositionRef stays in the composer, because the prompt-change handler also resets it.
  • extendReplacementRangeForTrailingSpace, a pure helper used by mention, skill and text insertion, into composer-logic.ts next to replaceTextRange, with a test.

The existing layout-effect ref for prompt history messages moved with the code. This PR adds no useStableCallback and no new layout-effect refs.

Filebeforeafter
ChatComposer.tsx4,1113,992
useComposerCommandKey.ts264

Renders are unchanged. Typing 20 chars is 165 renders, the same as #23058.

Tested:

  • vp test run src/composer-logic.test.ts, 54 passed, including the new case.
  • apps/web typecheck and lint on the touched files.
  • React Compiler: 0 bailouts on ChatComposer.tsx, useComposerCommandKey.ts and composer-logic.ts.
  • Hands-on in a dev build:
    • Enter sends from a draft.
    • Enter sends in a seeded thread with history (Take Over PR 6315, Claude, Supervised). The thread first compacted its context, which it was already set to do, then the queued message ran and Claude replied "OK".
    • In that thread, ArrowUp recalls the last prompt and ArrowDown clears it again.
    • In the slash menu, ArrowDown moves the highlight and Escape closes the menu.
  • Not checked: Shift+Tab. This dev environment shows no plan-mode control, so there was nothing to toggle.

🤖 Generated with Claude Code

Checks

All checks passed

Added 1 commit

  • refactor(web): composer key handling lives in useComposerCommandKeyc59c78e
Synced from GitHub

Approvability

Verdict: Approved at c59c78e

Macroscope's review found this PR approvable — This is a localized composer refactor that moves existing key-handling logic into a hook and relocates an unchanged pure helper, with no new user-facing capability or product-default change. The added test covers the helper, and the existing editor wiring and runtime branches remain equivalent.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: a2ae1422-02d9-45ed-98a5-76ce9f3acf44
📥 Commits

Reviewing files that changed from the base of the PR and between 959fea314650da81769dde58c4b89b77ffeada8f and c59c78e7b187b19a88634920f0d19d70270b90ff.

📒 Files selected for processing: 4
  • apps/web/src/components/chat/ChatComposer.tsx
  • apps/web/src/components/chat/useComposerCommandKey.ts
  • apps/web/src/composer-logic.test.ts
  • apps/web/src/composer-logic.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

📝 Walkthrough

ChatComposer now delegates keyboard command handling to useComposerCommandKey. Trailing-space replacement range logic now resides in shared composer logic and has test coverage.

Changes: Composer keyboard handling

Layer / File(s)Summary
Shared replacement range logic
apps/web/src/composer-logic.ts, apps/web/src/composer-logic.test.ts, apps/web/src/components/chat/ChatComposer.tsx
extendReplacementRangeForTrailingSpace now resides in composer logic. Tests cover when it extends the range. ChatComposer imports the shared utility.
Keyboard command hook
apps/web/src/components/chat/useComposerCommandKey.ts
The new hook handles prompt-history navigation, menu keyboard actions, submission dispatch, plan-mode toggling, list continuation, and indentation.
ChatComposer integration
apps/web/src/components/chat/ChatComposer.tsx
ChatComposer imports the hook and passes it composer state, refs, menu handlers, prompt replacement logic, and submission callbacks.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Suggested reviewers: maria-rcks

Merge Risk: ⚪ Minimal · up to c59c7

This refactor moves composer key handling into a hook without changing its behavior in the inspected code. No actionable merge risk remains.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely identifies the main change: moving composer key handling into useComposerCommandKey.
Description checkPassedThe description explains the refactor, affected behaviors, file changes, validation results, manual checks, and the unverified Shift+Tab path. It omits the explicit Scope and approval section, but the…
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the refactor, affected behaviors, file changes, validation results, manual checks, and the unverified Shift+Tab path. It omits the explicit Scope and approval section, but the core required information is present.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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