fix(web): guard dockview measure against mid-transition sidebar width (#1288)
* fix(web): guard dockview measure against mid-transition sidebar width The unified AppSidebar (#1165) animates its width over 300ms; the dockview content container (a flex sibling) can be measured mid-transition at a tiny positive width in onReady, so the default layout builds too narrow and dockview collapses the horizontal columns into a vertical stack. measureDockviewContainer trusted any positive parent clientWidth. Reject an implausibly-small live width (< 50% of viewport) as a not-yet-laid-out transient and fall back to the viewport; the resize observer then snaps to the exact size. * fix(web): preserve live height when width guard fires; assert it
This commit is contained in:
@@ -23,6 +23,29 @@ describe("measureDockviewContainer", () => {
|
||||
expect(measureDockviewContainer(fakeApi(0, 0))).toEqual({ width: 1500, height: 700 });
|
||||
});
|
||||
|
||||
it("ignores an implausibly-narrow live width (sidebar mid-transition) but keeps the live height", () => {
|
||||
// Regression (post unified-sidebar #1165): the AppSidebar is a root-layout
|
||||
// flex sibling with `transition-all duration-300`, so the dockview content
|
||||
// container can be measured mid-animation at a tiny positive width. Building
|
||||
// the default layout at that width collapses the horizontal columns into a
|
||||
// vertical stack (chat / files+changes / terminal). On desktop the sidebar
|
||||
// maxes at 30vw, so content is always >= ~70vw — a sub-half-viewport read is
|
||||
// definitionally a transient: fall back the width to the viewport so the
|
||||
// build stays horizontal (the resize observer then snaps to the exact size).
|
||||
// The animation is horizontal, so the live height is reliable and is kept.
|
||||
const parent = document.createElement("div");
|
||||
Object.defineProperty(parent, "clientWidth", { value: 80, configurable: true });
|
||||
Object.defineProperty(parent, "clientHeight", { value: 700, configurable: true });
|
||||
const dv = document.createElement("div");
|
||||
dv.className = "dv-dockview";
|
||||
parent.appendChild(dv);
|
||||
document.body.appendChild(parent);
|
||||
|
||||
const result = measureDockviewContainer(fakeApi(0, 0));
|
||||
expect(result.width).toBe(window.innerWidth);
|
||||
expect(result.height).toBe(700);
|
||||
});
|
||||
|
||||
it("never returns a zero size on a fresh mount (no container, api not laid out yet)", () => {
|
||||
// Regression: a 0×0 measurement builds the default layout at zero width, so
|
||||
// dockview collapses the horizontal columns into a vertical stack (chat /
|
||||
|
||||
@@ -25,12 +25,29 @@ export function measureDockviewContainer(api: DockviewApi): { width: number; hei
|
||||
};
|
||||
}
|
||||
|
||||
// The dockview content area sits next to the unified AppSidebar (#1165), whose
|
||||
// width animates over 300ms (`transition-all`). During that animation `onReady`
|
||||
// can read the parent at a tiny positive width — building the default layout at
|
||||
// that width collapses the horizontal columns into a vertical stack. The
|
||||
// sidebar maxes at 30vw (desktop-only surface), so a healthy content width is
|
||||
// always >= ~70vw; anything below half the viewport is a mid-transition
|
||||
// transient and must be treated like a not-yet-laid-out (0-width) container.
|
||||
const MIN_PLAUSIBLE_WIDTH_RATIO = 0.5;
|
||||
|
||||
function liveContainerSize(): { width: number; height: number } | null {
|
||||
if (typeof document === "undefined") return null;
|
||||
const dv = document.querySelector(".dv-dockview") as HTMLElement | null;
|
||||
const parent = dv?.parentElement;
|
||||
if (!parent || parent.clientWidth <= 0 || parent.clientHeight <= 0) return null;
|
||||
return { width: parent.clientWidth, height: parent.clientHeight };
|
||||
// The sidebar animation is horizontal, so only the width can be a transient —
|
||||
// the live height is reliable. Fall back just the width to the viewport so the
|
||||
// build stays horizontal; keep the real height to avoid a needless vertical
|
||||
// transient. The resize observer then snaps the width to the exact size.
|
||||
const plausibleWidth = parent.clientWidth >= viewportWidth() * MIN_PLAUSIBLE_WIDTH_RATIO;
|
||||
return {
|
||||
width: plausibleWidth ? parent.clientWidth : viewportWidth(),
|
||||
height: parent.clientHeight,
|
||||
};
|
||||
}
|
||||
|
||||
function viewportWidth(): number {
|
||||
|
||||
Reference in New Issue
Block a user