Merge remote-tracking branch 'origin/main' into sarabande
ci / web (push) Successful in 41s
ci / flake (push) Successful in 4m45s
ci / rust (push) Successful in 8m58s

This commit is contained in:
Miguel Palhas
2026-09-04 08:18:02 +01:00
3 changed files with 51 additions and 4 deletions
+17 -3
View File
@@ -215,6 +215,20 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
return fl?.sessionId ?? null;
}
/** The session the operator actually picked — what `focusedLeafSession()`
* would return with the preview undone. A preview moves the active tab and
* its focus, but it is a view: the accent stays on the row the operator
* chose until they choose another (docs/PREVIEW.md). */
function realFocusedSession(): string | null {
const p = preview;
if (!p) return focusedLeafSession();
const tab = layout.tabs.find((t) => t.id === p.prevActiveTabId) ?? activeTab(layout);
const leafId =
p.prevFocus && p.prevFocus.tabId === tab.id ? p.prevFocus.leafId : tab.focusedLeafId;
const fl = leafId ? findLeaf(tab.root, leafId) : null;
return fl?.sessionId ?? null;
}
/** Update focus styling + pool focus + sidebar highlights without rebuilding
* the DOM (cheap path for click-to-focus). */
function syncFocus(): void {
@@ -233,7 +247,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
if (!preview) pool.setFocus(focusedLeafSession());
sidebar.setHighlights({
open: realOpenSessions(),
focused: focusedLeafSession(),
focused: realFocusedSession(),
});
// The row the preview came from wears the same colour, so the sidebar and
// the pane read as one thing rather than two unrelated highlights.
@@ -608,7 +622,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
{ focus: !preview && !quietRender },
);
if (!preview) pool.setFocus(focused.sessionId ?? null);
sidebar.setHighlights({ open: realOpenSessions(), focused: focused.sessionId ?? null });
sidebar.setHighlights({ open: realOpenSessions(), focused: realFocusedSession() });
sidebar.setPreview(preview?.sessionId ?? null);
}
@@ -817,7 +831,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
openSessions: realOpenSessions,
beginSessionDrag,
render,
focusedSessionId: focusedLeafSession,
focusedSessionId: realFocusedSession,
previewSession,
previewedSessionId: () => preview?.sessionId ?? null,
};
+33 -1
View File
@@ -47,12 +47,20 @@ function fakePool(): Spy {
/** Last value the controller pushed to `SidebarHandle.setPreview`. */
const previewRow: { id: string | null } = { id: null };
/** Last highlights the controller pushed to `SidebarHandle.setHighlights`. */
const rowHighlights: { open: Set<string>; focused: string | null } = {
open: new Set(),
focused: null,
};
function fakeSidebar(): SidebarHandle {
return {
el: document.createElement("aside"),
setActive() {},
setHighlights() {},
setHighlights(h) {
rowHighlights.open = h.open;
rowHighlights.focused = h.focused;
},
setPreview(id: string | null) {
previewRow.id = id;
},
@@ -95,6 +103,8 @@ describe("sidebar preview", () => {
stubFetch();
document.body.replaceChildren();
previewRow.id = null;
rowHighlights.open = new Set();
rowHighlights.focused = null;
});
afterEach(() => {
@@ -134,6 +144,28 @@ describe("sidebar preview", () => {
expect(mv.el.querySelectorAll(".mv-pane.is-preview")).toHaveLength(0);
});
it("leaves the accent on the session the pane actually holds", () => {
const layout = twoTabs();
const spy = fakePool();
const mv = makeMv(layout, spy.pool);
expect(rowHighlights.focused).toBe("s2");
// Walking past other rows never moves the accent off what the operator
// picked: only a real open does (docs/PREVIEW.md).
mv.previewSession("s1");
expect(rowHighlights.focused).toBe("s2");
expect(mv.focusedSessionId()).toBe("s2");
mv.previewSession("s9");
expect(rowHighlights.focused).toBe("s2");
mv.previewSession(null);
expect(rowHighlights.focused).toBe("s2");
mv.openSession("s1");
expect(rowHighlights.focused).toBe("s1");
});
it("shows a session no pane holds in a throwaway tab that leaves no trace", () => {
const layout = twoTabs();
const before = serializeLayout(layout);