Close: bubble-up DOM hide + key-bump on full collapse
Two improvements to the close-pane workaround:
1. When both children of a parent split are now hidden, the .side hide
bubbles up to the parent split's own .side and hides that too. Needed
for deeply-nested splits where closing leaves at the bottom should
propagate the visual collapse upward.
2. When closeLeaf returns null (the user closed the last remaining
leaf), force a full Pane remount via {#key renderKey} bump. The
DOM-hide approach can't simulate mounting a fresh tree node, so this
is the one place where we take the cost of a full unmount + remount.
Only fires when the entire tree resets — not on intermediate closes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8d5c49155b
commit
40ce27251d
1 changed files with 39 additions and 8 deletions
|
|
@ -56,6 +56,11 @@
|
|||
if (activeLeafId === id) activeLeafId = null;
|
||||
}
|
||||
|
||||
// Bumped to force a full Pane unmount+remount when the tree's structure
|
||||
// changes in a way the DOM-hide workaround can't simulate (specifically,
|
||||
// when ALL panes have been closed and we need to render a fresh leaf).
|
||||
let renderKey = $state(0);
|
||||
|
||||
// ---- tree mutation handlers (closures over tree $state) -----------------
|
||||
function handleSplit(leafId: NodeId, orientation: Orientation) {
|
||||
const parent = findLeaf(tree, leafId);
|
||||
|
|
@ -73,21 +78,45 @@
|
|||
void killPane(paneId).catch((e) => console.warn("killPane failed:", e));
|
||||
orch.paneIdByLeaf.delete(leafId);
|
||||
}
|
||||
// Hide the closed pane's flex container and the adjacent gutter so the
|
||||
// sibling pane visually fills the freed space.
|
||||
|
||||
// DOM-hide the .side wrapping this leaf and the adjacent gutter so the
|
||||
// sibling pane visually fills. If both sides of the parent split are
|
||||
// now hidden, bubble up and hide that whole split too (recursive
|
||||
// collapse — needed for nested closes).
|
||||
const leafEl = document.querySelector(`[data-leaf-id="${leafId}"]`);
|
||||
const sideEl = leafEl?.closest(".side") as HTMLElement | null;
|
||||
const splitEl = sideEl?.parentElement;
|
||||
if (sideEl && splitEl) {
|
||||
let sideEl = leafEl?.closest(".side") as HTMLElement | null;
|
||||
while (sideEl) {
|
||||
sideEl.style.display = "none";
|
||||
const splitEl = sideEl.parentElement;
|
||||
if (!splitEl) break;
|
||||
// Hide the gutter in this split (only one).
|
||||
Array.from(splitEl.children).forEach((c) => {
|
||||
const child = c as HTMLElement;
|
||||
if (child.classList.contains("gutter")) child.style.display = "none";
|
||||
});
|
||||
// If a sibling side is still visible, flex will auto-fill; we're done.
|
||||
const visibleSiblings = Array.from(splitEl.children).filter((c) => {
|
||||
const child = c as HTMLElement;
|
||||
return (
|
||||
child.classList.contains("side") &&
|
||||
child.style.display !== "none"
|
||||
);
|
||||
});
|
||||
if (visibleSiblings.length > 0) break;
|
||||
// Otherwise, this whole split is empty — climb up and hide its parent side.
|
||||
sideEl = splitEl.closest(".side") as HTMLElement | null;
|
||||
}
|
||||
// Update tree state (used by broadcast routing, palette, persistence).
|
||||
|
||||
// Update tree state for persistence / palette / broadcast routing.
|
||||
const next = closeLeaf(tree, leafId);
|
||||
tree = next ?? newLeaf({ distro: defaultDistro });
|
||||
if (next === null) {
|
||||
// Tree fully collapsed. The DOM-hide workaround can't simulate
|
||||
// mounting a brand-new leaf, so force a clean remount via key bump.
|
||||
tree = newLeaf({ distro: defaultDistro });
|
||||
renderKey += 1;
|
||||
} else {
|
||||
tree = next;
|
||||
}
|
||||
clearActiveIf(leafId);
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +361,9 @@
|
|||
|
||||
<div class="pane-wrap">
|
||||
{#if ready}
|
||||
<Pane node={tree} {activeLeafId} />
|
||||
{#key renderKey}
|
||||
<Pane node={tree} {activeLeafId} />
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue