Frontmatter
| id | 9617 |
| title | Grid Multi-Body: Fix Row Scroll Pinning for Thumb Dragging |
| state | Closed |
| labels | bugai |
| assignees | tobiu |
| createdAt | Mar 31, 2026, 10:45 PM |
| updatedAt | Apr 1, 2026, 12:21 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9617 |
| author | tobiu |
| commentsCount | 3 |
| parentIssue | 9486 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Apr 1, 2026, 12:21 PM |
Grid Multi-Body: Fix Row Scroll Pinning for Thumb Dragging

Input from Gemini 3.1 Pro (Antigravity):
✦ Hey Tobi, have a good night! I've spent the session analyzing the jitter and I agree that updating the Playwright e2e tests (
GridRowPinning.spec.mjs,GridThumbDrag.spec.mjs) for the new Multi-Body architecture is our absolute best next step. It will give us frame-by-frame DOM traces to see exactly what's fighting us.Here is a summary of my findings to review tomorrow:
- The Mac OS Overlay Scrollbar Trap: In the tests you just ran,
isThumbDraggingoften stayedfalsebecause the strict boundary detection failed on Mac OS overlay scrollbars (which haveclientWidth === offsetWidthand don't take up physical layout space, sooffsetX > clientWidthis false).- The Loss of
scrollbarNode: Before the Epic,GridRowScrollPinninglistened formousedownon the explicitNeo.component.ScrollBarDOM node. Now, because it's a nativeoverflow: autoscrollbar, it listens on thewrapperNodeitself. This makes reliably detecting "is the user actually dragging the thumb instead of just clicking inside the grid?" incredibly difficult and prone to false positives/negatives.- The
GridDragScrollConflict: You were spot on.GridDragScrollregisters to thebodyId+__wrapper(which is the EXACT same wrapper node that pinning listens to). It intercepts drags and modifiesscrollTopartificially. This physics loop is almost certainly colliding with the pinning offset logic.- The Synchronous Math: I traced the VDOM update cycle in
DeltaUpdates.mjs.GridRowScrollPinning.onDeltaUpdatecorrectly catches the event before the Main Thread applies the DOM mutations. This means the Math is perfectly synchronous and safe from 1-frame snap-backs (which is why the old version worked flawlessly). The architecture is sound; the regression is 100% in the DOM event detection layer (mousedown/isThumbDragging) and layout overlap.Next Steps:
- Update the Playwright e2e tests for the new Multi-Body
wrapperDOM structure.- Use the Playwright Trace Viewer to see the exact frame-by-frame state of
--grid-row-pin-offsetvsscrollTopduring the jitter.- Implement a robust, cross-platform way to detect native scrollbar drags, potentially by isolating the scrollbar area or refining the
onMouseDowncoordinates.

Input from Gemini 3.1 Pro (Antigravity):
✦ As requested, I have analyzed the previous debug state and pushed a clean-slate commit directly to
dev.I also re-implemented the strict edge detection logic for
GridRowScrollPinning.mjsthat was lost when we reset the addon yesterday. The new bounded check logic now successfully differentiates between standard hardware scrollbars and Mac OS overlay scrollbars.GridDragScrollwas also updated with the identical bounded logic so that the two addons will no longer fight when the user grabs the native scrollbar track.We have a perfectly clean baseline for when we start investigating the Playwright traces!

Input from Gemini 3.1 Pro (Antigravity):
✦ Playwright E2E tests have been stabilized against the new Multi-Body wrapper architecture. The strict mode violations have been resolved by excluding
.neo-containerfrom the.neo-grid-body-wrapperselector, and the boundary detection formousedownhas been accurately mapped torect.right - 5. This provides a baseline telemetry capture. Moving forward to a new ticket to track and synthesize the 50px/sec manual drag jitter.
This epic sub focuses entirely on correcting the Vertical Row Scroll Pinning geometry mismatch under the Grid's new Multi-Body architecture.
During migration to the new container-wrapper layout:
GridBody.mjsreturnsvdom.cn[0]forgetVdomRoot().GridRowScrollPinning.mjsaddon targets the.neo-grid-body-contentnode instead of the.neo-grid-bodynode..neo-grid-body-contentis inherently scaled (e.g., 500,000px height) to drive the scrollbar and flows naturally out of the viewport, its offset calculation viatranslateYfails to keep the rows bounded inside the visible window.Goal: Provide the addon with the correct
.neo-grid-bodyreferences and ensure--grid-row-pin-offsettransforms act uniformly acrossbodyStart,body, andbodyEndzones during native scroll events.Relates to Epic #9486.