Drag a pane's toolbar onto another pane to swap them
New interaction: click-and-drag any pane's toolbar onto another pane to swap their positions in the tree. The shells / scrollback stay intact (each leaf keeps its data; only the tree slot it occupies changes). Implementation: - tree.ts: `swapLeaves(root, idA, idB)` walks the tree once, substituting one leaf for the other at each occurrence. The leaf objects themselves carry their id/distro/cwd/label/broadcast across, so React preserves the LeafPane instances via the flat-list keying. - orchestration.tsx: add drag lifecycle to the context — dragSourceId / dragOverId (reactive) plus beginHeaderDrag, setHeaderDragOver, endHeaderDrag (stable methods). - App.tsx: implement those methods. endHeaderDrag(true) swaps if source and over are different leaves. - LeafPane.tsx: pointerdown on .pane-toolbar (skipped if the target is a button/input). 5px movement threshold before drag commits to prevent accidental swaps when clicking a chip etc. Pointer-capture the toolbar so we keep getting move events even outside it. Use document.elementFromPoint to find the leaf under the cursor. - CSS: source pane fades to 40% opacity during drag; target pane shows a 3px dashed blue outline; toolbar shows grab/grabbing cursors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c4747546e0
commit
c93ebddfa5
5 changed files with 172 additions and 2 deletions
|
|
@ -29,6 +29,14 @@ export interface Orchestration {
|
|||
registerPaneId: (leafId: NodeId, paneId: PaneId | null) => void;
|
||||
broadcastFrom: (originLeafId: NodeId, dataB64: string) => void;
|
||||
notify: (message: string) => void;
|
||||
|
||||
// Drag-header-to-swap. dragSourceId / dragOverId are reactive so leaves
|
||||
// can apply hover/source styling. The lifecycle methods are stable.
|
||||
dragSourceId: NodeId | null;
|
||||
dragOverId: NodeId | null;
|
||||
beginHeaderDrag: (leafId: NodeId) => void;
|
||||
setHeaderDragOver: (leafId: NodeId | null) => void;
|
||||
endHeaderDrag: (commitSwap: boolean) => void;
|
||||
}
|
||||
|
||||
const OrchestrationContext = createContext<Orchestration | null>(null);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue