perf(useMouse): single-pass hit-test and pre-scale mouse coords#5
Merged
Conversation
Reduces mousemove hot-path work without changing behavior: - getChildrenByPosition: collapse BFS filter + max-z scan + queue reassignment per level into a single fused loop. Removes the intermediate currentLevelNodes allocation per descent step and the unreachable isTextNode branch. - Pre-divide mouse coords by deviceLogicalPixelRatio once instead of multiplying every node's absX/absY/width/height. Applied in both getChildrenByPosition and findElementByActiveElement. - Replace .filter() + last-element pick with a single reverse iteration in findElementWithCustomState and the focus effect. - Hoist Config.focusStateKey out of the per-tick filter. - Clean up dead code: findHighestZIndexNode (folded), unreachable `if (!activeElm) return` after the forwardStates walk-up, dead `active &&` check inside findElementByActiveElement's loop. Adds tests/useMouse.test.tsx covering: onMouseClick on focused element, ancestor walk-up on click, deepest-child focus on mousemove, z-index priority, skipFocus / alpha:0 exclusion, hoverState application and transfer, forwardStates propagation, deviceLogicalPixelRatio scaling, mousedown / pressedState lifecycle. All 10 tests pass against both the previous main implementation and this refactor. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
7ec8581 to
ae803db
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cuts work on the mousemove hot path in
useMousewithout changing observable behavior.getChildrenByPosition: collapsed BFS filter → max-z scan → queue reassignment per level into a single fused loop. Removes the per-levelcurrentLevelNodesallocation and the unreachableisTextNodebranch.clientX/clientYbydeviceLogicalPixelRatioonce at entry, instead of multiplying every node'sabsX/absY/width/heighton every collision test. Applied in bothgetChildrenByPositionandfindElementByActiveElement..filter()+ last-element pick replaced with a single reverse iteration infindElementWithCustomStateand the focus effect.Config.focusStateKeyout of the per-tick filter predicate.findHighestZIndexNode(folded into the descent), unreachableif (!activeElm) returnafter the forwardStates walk-up, deadactive &&guard insidefindElementByActiveElement's parent loop, unusedisTextNodeimport.For a level with N children, hit-testing drops from ~3N iterations + 1 allocation to N iterations and no allocations, plus 4 fewer multiplications per node tested.
Tests
New
tests/useMouse.test.tsx(10 cases) covering:onMouseClickinvoked on focused elementfindElementByActiveElementskipFocusandalpha: 0exclude from hit testinghoverStateapplied on mousemoveforwardStatespropagates hover to ancestordeviceLogicalPixelRatioscalingmousedownappliespressedState, click clears itAll 10 pass against the previous main implementation and against this refactor — proves behavioral equivalence.
Test plan
npm test— 120/120 (110 existing + 10 new)npm run tsc— cleanuseMouse.ts(verified viagit stash)useMouse.ts🤖 Generated with Claude Code