selection-reorder: integration#176
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lock the selection-reorder model in canonical docs ahead of implementation. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce src/shared/reorder-row.ts: detectReorderableRow (equal-gap eligibility gate + slot definition, FigJam parity), dropIndexForCursor, and reorderRowPositions (axis repack preserving per-item cross-axis). Pure, side-effect-free; unit-tested across every predicate branch. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase B of selection reorder (ADR 0015 D7). Adds reorderSelection in the main runtime: the position-only sibling of reorderManagedChild. Reads the equal-gap row off current geometry via detectReorderableRow, repacks with reorderRowPositions, and writes the changed origins through each entity's per-kind mutator inside one beginBatch/endBatch + markUndoBoundary — one undo step, no entityOrder write, no managedLayout group, no commitAsOneTransaction. Nothing persists but the new positions. Adds a test-only /test/canvas-reorder-selection/commit route, an AppClient helper, and a smoke test covering the permute + one-undo round-trip, entityOrder-unchanged, no-group-on-disk, and the unequal-gap no-op. Mutation-verified by (1) making reorderSelection a no-op and (2) swapping the written x/y — both fail the smoke assertions; restored to green. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ure (#174) Phase C of selection reorder (ADR 0015 D7). Add one shared `reorderableDots` selector returning the union of both doors — eligible loose equal-gap selection (`detectReorderableRow`) plus a selected managed-row group's children — and consume it from both `hit-test.ts` and `ReorderDotsLayer`, deleting the copy-pasted predicate. Rename the interaction mode `reordering-child {groupId, childId, dropIndex}` → `reordering-row {ids, movingId, dropIndex, axis}` across interaction-types, the controller, interaction-state, and the broadcast snapshot, so the renderer draws the insertion line door-agnostically. `begin-reorder-drag` now carries only `movingId`; `reorder-gesture.ts` resolves which door armed the gesture (managed-row child → managed door, else selection door), freezes the row at start, and branches commit: selection → `reorderSelection` (positions only), managed → `reorderManagedChild` (unchanged). Covered by a full begin/move/commit/cancel-{escape,blur,undo,tab-switch} smoke matrix for the selection door, a managed-door regression, and unit coverage of the union selector + the unequal-gap "no hit target" gate. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the insertion line with a live reflow: while a reordering-row drag is in flight, repack the frozen row at the current drop index via the shared reorderRowPositions kernel and shift each row entity to its previewed slot, so siblings visibly make room as the dragged dot crosses boundaries. Pure renderer ephemera — the broadcast layout is untouched; only the geometry layers (canvas items, selection outlines, dots) see the override, and release commits to exactly the previewed arrangement. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…older Upgrade selection-reorder Phase D from the live-reflow preview to dnd-kit / FigJam-style drag feedback. The dragged item lifts as a 50%-opacity ghost that floats under the cursor (grab offset preserved); its destination slot paints a grayscale placeholder that snaps between slots at the neighbour midpoint (50% crossing). The multi-select bounding box wraps both the placeholder slot and the lifted ghost, so the selection resizes during the drag. Renderer ephemera only: the gesture publishes the live canvas-space cursor delta through useCanvasPointerRouter, and App rebuilds the ghost/placeholder from the broadcast layout and the shared reorder-row kernel. No new IPC, no doc mutation until release. Page rows show the gap/placeholder but no floating body, since page bodies are native WebContentsViews rather than React. Also respecs Phase D in docs/plans/selection-reorder.md to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Drag-to-reorder for any evenly-spaced multi-selection. Select 2+ entities that form an equal-gap row, a center dot appears on each, drag a dot to reorder, siblings reflow to keep the row even. No
Cmd+G, no managed group required — reorder is now a property of having an aligned selection, not of being a managed group. Nothing persists but the new positions.Plan:
docs/plans/selection-reorder.md. Built AFK as five step PRs into this branch.Parts
src/shared/reorder-row.ts—detectReorderableRow(equal-gap gate),dropIndexForCursor,reorderRowPositions(cross-axis preserved)reorderSelectioncommit path (main runtime) — batched multi-entity position write, one undo step, noentityOrder/managedLayout/commitAsOneTransactionreorderableDotsselector (union of selection + managed doors), mode renamereordering-child→reordering-row, door-resolvingbegin-reorder-dragreorderPreview.ts; insertion line removedArchitecture
Two doors, one gesture. The gesture, dots, and
reordering-rowmode are shared; only eligibility and commit branch:detectReorderableRow(selectedBoxes)≠ null →reorderSelection, positions only, ephemeral.reorderManagedChild, rewritesentityOrder, persists.make-auto-layoutis demoted from "the way to get reorder" to "crystallize this arrangement into a persistent managed row." Zero new persisted state on the selection path.Tests (all green except pre-existing environmental
pages > takes a screenshot)pnpm test:unit, 650 pass) — everyreorder-rowpredicate branch +reorderable-dotsunion + selection-door hit-test cases.pnpm test:smoke) — Phase B: permute-to-sequence in one transaction, one-undo restore,entityOrderunchanged, nomanagedLayoutgroup on disk, cross-axis preserved, unequal-gap no-op. Phase C: full begin/move/commit/cancel-{escape,blur,undo,tab-switch} matrix for the selection door, managed-door regression, unequal-gap "no gesture armed" gate.pnpm typecheck) clean.Needs human verification (Phase D)
Phase D's live-reflow feel is a visual check the headless loop couldn't do. Before merging, please
/verifyin-app:managedLayouton disk)🤖 Generated with Claude Code