Context
A safe, standalone slice of #9872's "View as master body orchestrator" tier, extracted from PR #12754 (which was originally scoped wider — it also attempted the SelectionModel rework; that half was reverted and re-homed in the grid.View-owned SM migration follow-up after a REQUEST_CHANGES review). This leaf is the part that is behavior-preserving + E2E-verified safe.
The Problem
Body scroll-synchronization (syncBodies) lived on Neo.grid.Container, conflating the macro-routing layer with body orchestration. #9872 calls for grid.View to own the 1-3 bodies' lifecycle and row-synchronization. Without the back-reference, View also could not reach the macro layer (column distribution, ScrollManager) it does not own.
The Architectural Reality
Container.syncBodies(scrollTop) pushed synchronized scroll coords (startIndex/scrollLeft/scrollTop) into body/bodyStart/bodyEnd and then bumped view.update().
grid.View is the body-wrapper (hbox of the 1-3 bodies) but had no reference back to the Container macro layer.
- Split bodies created in
Container.onColumnsMutate → createOrUpdateSubGrids() were not covered by the resize-driven measurement, so their containerWidth/columnPositions could stay unset and Body.createViewData short-circuit to an empty body.
The Fix
- Move
syncBodies to grid.View (reads gridContainer.scrollManager for horizontal position); Container.syncBodies delegates to this.view.syncBodies.
- Add
View.gridContainer back-reference (set at Container View-construction).
- Split-body initial render: in
Container.onColumnsMutate, after createOrUpdateSubGrids(), passSizeToBody() then updateMountedAndVisibleColumns() on each present body.
- Preserves the row/cell pooling invariant (silent
createViewData(true)).
Acceptance Criteria
Out of Scope
- SelectionModel ownership / per-body model elimination → the
grid.View-owned single SelectionModel follow-up.
Container macro-routing strip + grid.header.Wrapper orchestrator → remainder of #9872.
Related
Decision Record impact
aligned-with #9872 (delivers its View-orchestrator tier incrementally).
Origin Session ID: 3f9ffeb7-a284-4783-912b-f39912115d2e
Context
A safe, standalone slice of #9872's "View as master body orchestrator" tier, extracted from PR #12754 (which was originally scoped wider — it also attempted the SelectionModel rework; that half was reverted and re-homed in the
grid.View-owned SM migration follow-up after aREQUEST_CHANGESreview). This leaf is the part that is behavior-preserving + E2E-verified safe.The Problem
Body scroll-synchronization (
syncBodies) lived onNeo.grid.Container, conflating the macro-routing layer with body orchestration. #9872 calls forgrid.Viewto own the 1-3 bodies' lifecycle and row-synchronization. Without the back-reference,Viewalso could not reach the macro layer (column distribution, ScrollManager) it does not own.The Architectural Reality
Container.syncBodies(scrollTop)pushed synchronized scroll coords (startIndex/scrollLeft/scrollTop) intobody/bodyStart/bodyEndand then bumpedview.update().grid.Viewis the body-wrapper (hbox of the 1-3 bodies) but had no reference back to theContainermacro layer.Container.onColumnsMutate→createOrUpdateSubGrids()were not covered by the resize-driven measurement, so theircontainerWidth/columnPositionscould stay unset andBody.createViewDatashort-circuit to an empty body.The Fix
syncBodiestogrid.View(readsgridContainer.scrollManagerfor horizontal position);Container.syncBodiesdelegates tothis.view.syncBodies.View.gridContainerback-reference (set atContainerView-construction).Container.onColumnsMutate, aftercreateOrUpdateSubGrids(),passSizeToBody()thenupdateMountedAndVisibleColumns()on each present body.createViewData(true)).Acceptance Criteria
syncBodiesowned bygrid.View;Containerdelegates.View.gridContainerback-reference present.test/playwright/e2e/GridThumbDrag.spec.mjsgreen.GridSelectionMultiBody.spec.mjscross-body selection test green.Out of Scope
grid.View-owned single SelectionModel follow-up.Containermacro-routing strip +grid.header.Wrapperorchestrator → remainder of #9872.Related
Decision Record impact
aligned-with#9872 (delivers its View-orchestrator tier incrementally).Origin Session ID: 3f9ffeb7-a284-4783-912b-f39912115d2e