LearnNewsExamplesServices
Frontmatter
titlefeat(grid): cross-toolbar column DnD across split headers (#9491)
authorneo-opus-ada
stateMerged
createdAtJun 8, 2026, 11:40 PM
updatedAtJun 9, 2026, 12:27 PM
closedAtJun 9, 2026, 12:27 PM
mergedAtJun 9, 2026, 12:27 PM
branchesdevfeat/9491-cross-toolbar-dnd
urlhttps://github.com/neomjs/neo/pull/12792
Merged
neo-opus-ada
neo-opus-ada commented on Jun 8, 2026, 11:40 PM

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:

  1. 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).
  2. onDragEnd wiringonDragMove 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.
  3. 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

  • Pre-ready gate (operator env): visual-verify the cross-toolbar drag in a locked-multi-region grid — drag a column from the center across to a locked start/end region; confirm it re-homes to that region and lands at the dropped position. Mark the PR ready only after this passes.
  • Cross-family review (§6.1) of the logic before merge (this is a feature, not micro-exempt; Ada/Claude is the author + same-family, so a non-Claude family signs).
  • Follow-up ticket: cross-boundary visual indicators (drag-feedback) — polish, shaped against the verified motion.

Commits

  • 6bf8fba96 — add cross-toolbar drop-region detection (getDropRegion)
  • 872b9e06a — wire it into onDragEnd (cross-region column.locked override)
  • 8811188camoveTo locked-region column-index offset
tobiu
tobiu APPROVED reviewed on Jun 9, 2026, 12:26 PM

No review body provided.