Skip to content

fix(client): use browser :hover for card-preview dismiss checks#6600

Merged
matthewevans merged 1 commit into
mainfrom
ship/card-preview-hover-dismiss
Jul 24, 2026
Merged

fix(client): use browser :hover for card-preview dismiss checks#6600
matthewevans merged 1 commit into
mainfrom
ship/card-preview-hover-dismiss

Conversation

@matthewevans

@matthewevans matthewevans commented Jul 24, 2026

Copy link
Copy Markdown
Member

Battlefield card previews never appeared over remote desktop (RDP) and flickered locally with a non-zero hover delay. Both timer-based dismiss checks — the 300ms poll (usePreviewDismiss) and the 50ms delayed-clear (uiStore.inspectObject) — tested "is the cursor still over a card?" by sampling document.elementFromPoint() against a JS-tracked pointer that only updates on pointermove. Over sparse/coalesced RDP pointer streams that coordinate goes stale a few px off the card while the OS cursor is genuinely on it, so the check false-negatived and dismissed (or cancelled the pending show for) a live preview.

Battlefield cards were uniquely affected: their hover element carries a Framer-Motion layoutId that emits spurious mouseleave events routed through the delayed-clear; hand cards have no layoutId and never triggered the stale-pointer check.

Switch both timer-based checks to the browser's authoritative [data-card-hover]:hover element — the engine's continuous hit-test, correct with zero pointermove events — and remove the now-dead lastPointer tracking. The pointerdown-outside handler keeps elementFromPoint (it reads fresh event coordinates).

Summary by CodeRabbit

  • Bug Fixes
    • Improved hover detection for previews and cards by relying on the browser’s active hover state.
    • Prevented previews from dismissing unexpectedly during layout changes or motion transitions.
    • Removed issues caused by stale pointer-position tracking, while preserving dismissal when clicking outside the preview.

Battlefield card previews never appeared over remote desktop (RDP) and flickered locally with a non-zero hover delay. Both timer-based dismiss checks — the 300ms poll (usePreviewDismiss) and the 50ms delayed-clear (uiStore.inspectObject) — tested "is the cursor still over a card?" by sampling document.elementFromPoint() against a JS-tracked pointer that only updates on pointermove. Over sparse/coalesced RDP pointer streams that coordinate goes stale a few px off the card while the OS cursor is genuinely on it, so the check false-negatived and dismissed (or cancelled the pending show for) a live preview.

Battlefield cards were uniquely affected: their hover element carries a Framer-Motion layoutId that emits spurious mouseleave events routed through the delayed-clear; hand cards have no layoutId and never triggered the stale-pointer check.

Switch both timer-based checks to the browser's authoritative [data-card-hover]:hover element — the engine's continuous hit-test, correct with zero pointermove events — and remove the now-dead lastPointer tracking. The pointerdown-outside handler keeps elementFromPoint (it reads fresh event coordinates).
@matthewevans
matthewevans enabled auto-merge July 24, 2026 17:42
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7eb3f970-5eac-4bfd-af47-83dc0efc7b3e

📥 Commits

Reviewing files that changed from the base of the PR and between 192897c and 1f253e4.

📒 Files selected for processing (3)
  • client/src/hooks/usePreviewDismiss.ts
  • client/src/stores/__tests__/uiStoreHoverLatency.test.ts
  • client/src/stores/uiStore.ts

📝 Walkthrough

Walkthrough

Preview hover retention and dismissal now rely on the browser’s continuous [data-card-hover]:hover state rather than pointer coordinates tracked through JavaScript. Store tests were updated to mock document.querySelector for the new behavior.

Changes

Hover-state preview handling

Layer / File(s) Summary
CSS hover detection and dismissal flow
client/src/stores/uiStore.ts, client/src/hooks/usePreviewDismiss.ts, client/src/stores/__tests__/uiStoreHoverLatency.test.ts
Removed pointer-position tracking and coordinate hit-testing, added [data-card-hover]:hover checks for preview retention and dismissal, and updated hover-latency tests to mock the new query path.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • phase-rs/phase#6239: Updates the same hover-preview logic to use [data-card-hover]:hover instead of pointer-coordinate hit-testing.

Suggested reviewers: parthmishra

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: switching card-preview dismiss checks to browser :hover state.
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.
✨ 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 ship/card-preview-hover-dismiss

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

@matthewevans
matthewevans added this pull request to the merge queue Jul 24, 2026
Merged via the queue into main with commit 7ac9d51 Jul 24, 2026
15 checks passed
@matthewevans
matthewevans deleted the ship/card-preview-hover-dismiss branch July 24, 2026 18:18
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