Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada. Session 31325e4f-0fdf-4627-96ed-7983dd1b1002.
Resolves #9491
DRAFT — logic complete + unit-tested; the cross-toolbar motion is pending a visual-verify in a live locked-multi-region grid (operator env) before this goes ready/merge. Draft status keeps it mechanically un-mergeable until that gate passes.
Cross-toolbar column drag-and-drop across the split header (start / center / end toolbars). Builds on the merged within-region fix (#12708) and the merged multi-body SelectionModel (#12754). Three slices:
getDropRegion(dropX, regionRects) — maps the pointer release x-coordinate to the target lock region (start / center / end) via the locked-start / locked-end body x-ranges. The position-based signal a cross-toolbar drag needs (vs the within-region neighbor-inference).
onDragEnd wiring — onDragMove captures the release x; onDragEnd resolves the start/end body rects, calls getDropRegion, and overrides column.locked ONLY for cross-region moves (purely additive — within-region keeps the neighbor-inference path). The column.locked change triggers Container#onColumnLockChange, which already re-sorts (stably), resets indices, redistributes to the toolbars, and re-renders — so the cross-region re-homing rides the existing redistribution.
columnIndexOffset() + moveTo — offsets the owner-toolbar-local index into the global columns collection by preceding-region counts, fixing within-region positioning in locked-multi-region grids. Backward-compatible: offset is 0 in the no-locked case, so #12708's within-region resort is unchanged.
Evidence: L2 (targeted unit tests for the pure helpers getDropRegion + columnIndexOffset) → L4 required (the cross-toolbar MOTION end-to-end is visual; the onDragEnd integration is embedded in the async method, not unit-testable in isolation). Residual: the cross-toolbar drag motion + within-region positioning in a locked-multi-region grid need a live-env visual-verify (operator) — hence DRAFT.
Deltas from ticket
- Scoped to the cross-toolbar functional core (region-detection + re-homing + locked-region positioning). The cross-boundary visual indicators (drag-feedback showing the target region) are deferred to a follow-up — the core re-homing works without them, and the indicators are polish best shaped against the verified motion.
- The "index-remap" originally scoped as a separate concern turned out largely unneeded:
onColumnLockChange already re-indexes + redistributes on a column.locked change; only the within-region moveTo offset (slice 3) was the real gap.
Test Evidence
test/playwright/unit/draggable/grid/header/toolbar/SortZone.spec.mjs — 3 passed: gridBody region-resolution (#12708 regression) + getDropRegion (start/center/end + boundary-inclusive + center-only) + columnIndexOffset (start/center/end offsets + no-locked).
- The pure helpers are unit-tested; the
onDragEnd integration is logic-sound but its end-to-end motion is visual (the DRAFT gate).
Post-Merge Validation
Commits
6bf8fba96 — add cross-toolbar drop-region detection (getDropRegion)
872b9e06a — wire it into onDragEnd (cross-region column.locked override)
8811188ca — moveTo locked-region column-index offset
Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada. Session 31325e4f-0fdf-4627-96ed-7983dd1b1002.
Resolves #9491
Cross-toolbar column drag-and-drop across the split header (start / center / end toolbars). Builds on the merged within-region fix (#12708) and the merged multi-body SelectionModel (#12754). Three slices:
getDropRegion(dropX, regionRects)— maps the pointer release x-coordinate to the target lock region (start / center / end) via the locked-start / locked-end body x-ranges. The position-based signal a cross-toolbar drag needs (vs the within-region neighbor-inference).onDragEndwiring —onDragMovecaptures the release x;onDragEndresolves the start/end body rects, callsgetDropRegion, and overridescolumn.lockedONLY for cross-region moves (purely additive — within-region keeps the neighbor-inference path). Thecolumn.lockedchange triggersContainer#onColumnLockChange, which already re-sorts (stably), resets indices, redistributes to the toolbars, and re-renders — so the cross-region re-homing rides the existing redistribution.columnIndexOffset()+moveTo— offsets the owner-toolbar-local index into the globalcolumnscollection by preceding-region counts, fixing within-region positioning in locked-multi-region grids. Backward-compatible: offset is 0 in the no-locked case, so #12708's within-region resort is unchanged.Evidence: L2 (targeted unit tests for the pure helpers
getDropRegion+columnIndexOffset) → L4 required (the cross-toolbar MOTION end-to-end is visual; theonDragEndintegration is embedded in the async method, not unit-testable in isolation). Residual: the cross-toolbar drag motion + within-region positioning in a locked-multi-region grid need a live-env visual-verify (operator) — hence DRAFT.Deltas from ticket
onColumnLockChangealready re-indexes + redistributes on acolumn.lockedchange; only the within-regionmoveTooffset (slice 3) was the real gap.Test Evidence
test/playwright/unit/draggable/grid/header/toolbar/SortZone.spec.mjs— 3 passed:gridBodyregion-resolution (#12708 regression) +getDropRegion(start/center/end + boundary-inclusive + center-only) +columnIndexOffset(start/center/end offsets + no-locked).onDragEndintegration is logic-sound but its end-to-end motion is visual (the DRAFT gate).Post-Merge Validation
Commits
6bf8fba96— add cross-toolbar drop-region detection (getDropRegion)872b9e06a— wire it intoonDragEnd(cross-regioncolumn.lockedoverride)8811188ca—moveTolocked-region column-index offset