diff --git a/packages/studio/src/components/dock/DockTabs.test.tsx b/packages/studio/src/components/dock/DockTabs.test.tsx index c51ca16827..58c53c86e9 100644 --- a/packages/studio/src/components/dock/DockTabs.test.tsx +++ b/packages/studio/src/components/dock/DockTabs.test.tsx @@ -199,16 +199,43 @@ describe("dock tab fill", () => { expect(strip.scrollLeft).toBe(0); }); - it("reveals the shown tab again when its strip comes back from hidden", async () => { + it("keeps a hand scroll through another group being maximised and restored", async () => { const strip = stripOf("design"); if (!strip) throw new Error("no design strip"); await activate("variables"); Object.defineProperty(strip, "clientWidth", { value: 250, configurable: true }); act(() => resizeAll()); - // Another group is maximised, hiding this strip; the browser drops a hidden strip's scroll. + strip.scrollLeft = 0; + // Hidden while another group is maximised; the browser keeps a hidden strip's scroll. Object.defineProperty(strip, "clientWidth", { value: 0, configurable: true }); act(() => resizeAll()); + Object.defineProperty(strip, "clientWidth", { value: 250, configurable: true }); + act(() => resizeAll()); + expect(strip.scrollLeft).toBe(0); + }); + + it("leaves a hand scroll alone when its strip widens", async () => { + const strip = stripOf("design"); + if (!strip) throw new Error("no design strip"); + await activate("variables"); + Object.defineProperty(strip, "clientWidth", { value: 150, configurable: true }); + act(() => resizeAll()); strip.scrollLeft = 0; + // Wider, but the shown tab is still out of view where the user left the strip. + Object.defineProperty(strip, "clientWidth", { value: 200, configurable: true }); + act(() => resizeAll()); + expect(strip.scrollLeft).toBe(0); + }); + + it("reveals the shown tab when its strip comes back narrower than it left", async () => { + const strip = stripOf("design"); + if (!strip) throw new Error("no design strip"); + await activate("variables"); + strip.scrollLeft = 0; + Object.defineProperty(strip, "clientWidth", { value: 1000, configurable: true }); + act(() => resizeAll()); + Object.defineProperty(strip, "clientWidth", { value: 0, configurable: true }); + act(() => resizeAll()); Object.defineProperty(strip, "clientWidth", { value: 250, configurable: true }); act(() => resizeAll()); expect(strip.scrollLeft).toBe(3 * TAB_STEP + TAB_WIDTH + 1 - 250); diff --git a/packages/studio/src/components/dock/dockTabFill.ts b/packages/studio/src/components/dock/dockTabFill.ts index dc12fc69ff..b35062b4ac 100644 --- a/packages/studio/src/components/dock/dockTabFill.ts +++ b/packages/studio/src/components/dock/dockTabFill.ts @@ -19,12 +19,12 @@ function fillOf(list: HTMLElement): HTMLElement { type StripShape = { width: number; tab: HTMLElement | null; left: number; size: number }; /** - * True when the strip narrowed, came back from hidden, or its shown tab moved or resized. dockview + * True when the strip narrowed or its shown tab moved or resized since it was last visible. dockview * reveals a tab only when it is activated, and the user's own scrolling changes none of these. */ function reshaped(before: StripShape | undefined, now: StripShape) { if (!before || now.width === 0) return false; - if (now.width < before.width || before.width === 0) return true; + if (now.width < before.width) return true; return now.tab !== before.tab || now.left !== before.left || now.size !== before.size; } @@ -46,7 +46,8 @@ function measureFill(list: HTMLElement, shapes: WeakMap size: tab?.offsetWidth ?? 0, }; const reveal = tab !== null && reshaped(shapes.get(list), shape); - shapes.set(list, shape); + // A hidden strip (another group maximised) keeps its scroll, so it is compared with its last visible shape. + if (shape.width > 0) shapes.set(list, shape); const scrollLeft = list.scrollLeft; const target = reveal ? revealedScroll(shape, scrollLeft) : scrollLeft; return () => {