Skip to content

Add app:focusfollowscursor setting (off/on/term) for hover-based block focus#2908

Merged
sawka merged 4 commits intowavetermdev:mainfrom
jfeust:feature/focus-follows-cursor
Feb 20, 2026
Merged

Add app:focusfollowscursor setting (off/on/term) for hover-based block focus#2908
sawka merged 4 commits intowavetermdev:mainfrom
jfeust:feature/focus-follows-cursor

Conversation

@jfeust
Copy link
Contributor

@jfeust jfeust commented Feb 20, 2026

This PR adds a new app setting to control whether block focus follows cursor movement:

  • app:focusfollowscursor: "off" | "on" | "term"
  • Default is "off" (no behavior change unless enabled)

What changed

  • Added hover-focus behavior on block pointer enter.
  • Added guardrails so hover focus does not trigger when:
  • touch input is used
  • pointer buttons are pressed (drag/select scenarios)
  • modal is open
  • pointer events are disabled
  • block is resizing
  • Added config key plumbing across settings types and schema:
  • pkg/wconfig/settingsconfig.go
  • pkg/wconfig/metaconsts.go
  • schema/settings.json
  • pkg/wconfig/defaultconfig/settings.json -> "app:focusfollowscursor": "off"
  • Added docs for the new key and default example:
  • docs/docs/config.mdx

Behavior

  • "off": do not focus on cursor movement
  • "on": focus follows cursor for all block types
  • "term": focus follows cursor only for terminal blocks

…low your cursor. Options are "off" (default), "on", or "term" to only have focus follow in term tabs.
@CLAassistant
Copy link

CLAassistant commented Feb 20, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a new configuration key app:focusfollowscursor (enum "off", "on", "term") across schema, Go config types, metaconsts, default settings, docs, and frontend type declarations. Frontend: introduces onPointerEnter to block component model and wires a new pointer-enter focus handler in BlockFull that conditionally focuses blocks based on app:focusfollowscursor, input buttons/touch, modal/resizing/magnification state, and duplicate-focus checks. LayoutModel and NodeModel gain an anyMagnified Atom exposing global magnification state to node models.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a new app:focusfollowscursor configuration setting with three allowed values (off/on/term) for controlling hover-based block focus behavior.
Description check ✅ Passed The description clearly explains the purpose, implementation details, and behavior of the new focus-follows-cursor feature with appropriate guardrails and configuration changes across multiple files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

@kiloconnect
Copy link
Contributor

kiloconnect bot commented Feb 20, 2026

Code Review Summary

Status: No New Issues Found | Recommendation: Address existing comment before merge

Overview

This PR implements a "focus follows cursor" feature that allows blocks to automatically receive focus when the mouse pointer enters them. The implementation includes:

  • New configuration setting app:focusfollowscursor with three modes: "off" (default), "on" (all blocks), and "term" (terminal blocks only)
  • Proper integration across frontend (React), backend (Go), and documentation
  • Smart guards to prevent unwanted focus changes (touch events, dragging, modals, resizing, magnified blocks)

Technical Implementation

Well-structured changes:

  • Configuration properly defined in schema with enum validation
  • Type definitions consistent across TypeScript and Go
  • Event handler correctly wired through BlockComponentModel2BlockFrameonPointerEnter
  • Appropriate use of useMemo and useCallback for performance
  • Good defensive checks (touch events, button state, modal state, etc.)

⚠️ Note: There is one existing critical issue already flagged in the comments regarding a stale closure bug in the focusFromPointerEnter callback's dependency array. Please address that before merging.

Files Reviewed (10 files)

Fix these issues in Kilo Cloud

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/docs/config.mdx`:
- Line 46: The new config entry for app:focusfollowscursor is missing the
VersionBadge used for other v0.14 settings; update the docs line describing
app:focusfollowscursor to include the VersionBadge component (e.g. add
<VersionBadge version="v0.14" /> adjacent to the setting name) so it matches the
convention used for app:confirmquit, app:hideaibutton,
app:disablectrlshiftarrows and app:disablectrlshiftdisplay.

…iew. Added VersionBadge to the new config.mdx entry.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
frontend/app/block/block.tsx (1)

230-259: Hover-focus triggers the blockClicked layout-effect path — minor redundant renders.

When focusFromPointerEnter calls nodeModel.focusNode(), isFocused transitions to true, which triggers useLayoutEffect(() => setBlockClicked(isFocused), [isFocused]) (line 158). The second layout effect then runs but correctly skips all focus calls because focusedBlockId() == nodeModel.blockId is already satisfied and !isFocused is false. No correctness issue, but every hover-focus event incurs two extra React renders from the blockClicked state mutation.

This is inherited from the pre-existing click-focus architecture rather than a bug introduced here. If hover-focus paths become performance-sensitive (e.g., on systems with many open blocks), consider gating the setBlockClicked(isFocused) effect with a ref flag to distinguish hover-triggered isFocused changes from click-triggered ones.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/block/block.tsx` around lines 230 - 259, Hover-triggered focus
causes an extra setBlockClicked update; add a ref flag (e.g., hoverFocusRef) to
differentiate hover vs click: in focusFromPointerEnter set hoverFocusRef.current
= true just before calling nodeModel.focusNode(), and ensure click handlers set
hoverFocusRef.current = false; update the useLayoutEffect that runs
setBlockClicked(isFocused) to bail out when hoverFocusRef.current is true (so it
only sets blockClicked for click-initiated focuses), and clear
hoverFocusRef.current after focus handling so future focus changes behave
normally; reference symbols: focusFromPointerEnter, nodeModel.focusNode,
isFocused, setBlockClicked, focusedBlockId, and the useLayoutEffect that updates
blockClicked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/app/block/block.tsx`:
- Around line 230-259: Hover-triggered focus causes an extra setBlockClicked
update; add a ref flag (e.g., hoverFocusRef) to differentiate hover vs click: in
focusFromPointerEnter set hoverFocusRef.current = true just before calling
nodeModel.focusNode(), and ensure click handlers set hoverFocusRef.current =
false; update the useLayoutEffect that runs setBlockClicked(isFocused) to bail
out when hoverFocusRef.current is true (so it only sets blockClicked for
click-initiated focuses), and clear hoverFocusRef.current after focus handling
so future focus changes behave normally; reference symbols:
focusFromPointerEnter, nodeModel.focusNode, isFocused, setBlockClicked,
focusedBlockId, and the useLayoutEffect that updates blockClicked.

@sawka sawka merged commit b9067fb into wavetermdev:main Feb 20, 2026
2 of 3 checks passed
stevenwang288 pushed a commit to stevenwang288/waveterm that referenced this pull request Feb 21, 2026
…k focus (wavetermdev#2908)

This PR adds a new app setting to control whether block focus follows
cursor movement:

  - `app:focusfollowscursor: "off" | "on" | "term"`
  - Default is `"off"` (no behavior change unless enabled)

  ## What changed

  - Added hover-focus behavior on block pointer enter.
  - Added guardrails so hover focus does not trigger when:
  - touch input is used
  - pointer buttons are pressed (drag/select scenarios)
  - modal is open
  - pointer events are disabled
  - block is resizing
  - Added config key plumbing across settings types and schema:
  - `pkg/wconfig/settingsconfig.go`
  - `pkg/wconfig/metaconsts.go`
  - `schema/settings.json`
- `pkg/wconfig/defaultconfig/settings.json` ->
`"app:focusfollowscursor": "off"`
  - Added docs for the new key and default example:
  - `docs/docs/config.mdx`

  ## Behavior

  - `"off"`: do not focus on cursor movement
  - `"on"`: focus follows cursor for all block types
  - `"term"`: focus follows cursor only for terminal blocks
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.

3 participants