From f43779c99ecec3273f7b121a153576b7fbefdba8 Mon Sep 17 00:00:00 2001 From: topkoa Date: Sun, 12 Jul 2026 19:52:32 -0400 Subject: [PATCH] fix(panes): detach the element when the pop-out starts, not when it lands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The window host's place() is asynchronous — it opens the window, waits for /pane to load, and only then adopts the element in. But the manager emits `panes:opened` as soon as place() returns, and the chip reacts by putting its "popped out" stub where the element used to be. So for that gap the user saw BOTH: the real panel still sitting in its original spot, and a stub next to it claiming the panel had left. On a window that never loads, that lasts the full 10s readiness timeout. Detach the element as soon as we commit to moving it. That is not destructive: the node keeps its owner document, its listeners and its closures — it is simply out of the tree, waiting for a document to be adopted into. And if the window never loads, closePane() puts it straight back at its home, which is exactly what the failure path already does. The dock host has no such gap; its place() moves the element synchronously. Signed-off-by: topkoa --- static/panes/pane-window-host.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/static/panes/pane-window-host.js b/static/panes/pane-window-host.js index bca81aa..d261127 100644 --- a/static/panes/pane-window-host.js +++ b/static/panes/pane-window-host.js @@ -225,6 +225,21 @@ wins.set(spec.id, w); _startReaper(); + // Take the element out of the document NOW, not when the window is ready. + // + // Everything below this line is async: the window has to load /pane before + // there is anything to adopt into. But the manager emits `panes:opened` as + // soon as we return, and the chip reacts by putting its "popped out" stub + // where the element used to be — so for that whole gap the user would see + // BOTH the real panel and a stub claiming it had left. On a window that + // never loads, that lasts the full 10s timeout. + // + // Detaching is not destructive: the node keeps its owner document (this + // one), its listeners and its closures. It is simply out of the tree, + // waiting — and if the window never loads, closePane() puts it straight + // back at its home. + el.remove(); + _whenReady(w, (root) => { try { _adopt(w, root, spec, el); } catch (e) {