Force gutter-drag resize via direct DOM (same workaround)

Dragging the splitter set node.ratio in the Svelte $state tree
correctly (used by save-restore), but the template binding
style=\"flex: {node.ratio}\" on each .side div didn't re-evaluate
when ratio changed — same prop-reactivity wall we hit with the
active border and broadcast color. The gutter would drag invisibly:
internal state moved, panes stayed at their original ratio.

Workaround: SplitNode's onPointerMove now ALSO writes the flex
style directly to the two .side elements via DOM. Svelte still owns
node.ratio for persistence/serialization, but the visual is owned
by the imperative DOM write.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-05-22 16:33:21 +01:00
parent 50f612e6a6
commit 058ce49d3b
2 changed files with 31 additions and 0 deletions

View file

@ -5,6 +5,7 @@
saveWorkspace,
loadWorkspace,
writeToPane,
killPane,
} from "./ipc";
import Pane from "./lib/layout/Pane.svelte";
import Notifications from "./components/Notifications.svelte";
@ -65,6 +66,29 @@
}
function handleClose(leafId: NodeId) {
// Kill the PTY explicitly — Svelte's onDestroy on LeafPane won't fire
// because Svelte isn't unmounting the component (same reactivity gap as
// the active/broadcast bugs).
const paneId = orch.paneIdByLeaf.get(leafId);
if (paneId != null) {
void killPane(paneId).catch((e) => console.warn("killPane failed:", e));
orch.paneIdByLeaf.delete(leafId);
}
// Brute-force hide the closed pane's flex side + the adjacent gutter so
// the sibling pane visually fills the freed space.
const leafEl = document.querySelector(`[data-leaf-id="${leafId}"]`);
const sideEl = leafEl?.closest(".side") as HTMLElement | null;
const splitEl = sideEl?.parentElement;
if (sideEl && splitEl) {
sideEl.style.display = "none";
Array.from(splitEl.children).forEach((c) => {
const child = c as HTMLElement;
if (child.classList.contains("gutter")) child.style.display = "none";
});
}
// Update tree state (used by broadcast routing, palette, persistence).
const next = closeLeaf(tree, leafId);
tree = next ?? newLeaf({ distro: defaultDistro });
clearActiveIf(leafId);

View file

@ -28,6 +28,13 @@
if (size <= 0) return;
const r = Math.max(0.05, Math.min(0.95, pos / size));
node.ratio = r;
// Brute-force DOM: Svelte's `style="flex: {node.ratio}"` template binding
// doesn't propagate ratio changes in this app. Update the .side flex
// styles directly so the drag actually moves the gutter visually.
const sides = containerEl.querySelectorAll(":scope > .side");
if (sides[0]) (sides[0] as HTMLElement).style.flex = String(r);
if (sides[1]) (sides[1] as HTMLElement).style.flex = String(1 - r);
}
function onPointerUp(e: PointerEvent) {