From e9dc485af43c5c872e6280ebb139a53471b25d10 Mon Sep 17 00:00:00 2001 From: yiliang114 Date: Sat, 5 Sep 2026 16:21:34 +0900 Subject: [PATCH] fix(web-shell): keep the auto-sized dialog's gutter on a phone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `auto` size floors the panel at `min-w-[min(100%,560px)]` so a small plan graph does not collapse to a narrow column. tailwind-merge keeps that class alongside the base ceiling `max-w-[calc(100%-2rem)]` — they are different modifier groups — and below the `sm:` breakpoint min-width wins over max-width. On a 390px viewport the Plan & tasks dialog therefore rendered its rounded, ringed panel flush to both screen edges, while every fixed size (sm/md/lg/xl) kept the 1rem gutter at that same width. Floor the panel at the gutter the ceiling already reserves. The size test now pins the new floor, that the old one is gone, and that the base ceiling survives the merge — the three only hold together. --- .../client/components/dialogs/DialogShell.test.tsx | 8 +++++++- .../web-shell/client/components/dialogs/DialogShell.tsx | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/web-shell/client/components/dialogs/DialogShell.test.tsx b/packages/web-shell/client/components/dialogs/DialogShell.test.tsx index 26425e6b1d5..36a507df0f4 100644 --- a/packages/web-shell/client/components/dialogs/DialogShell.test.tsx +++ b/packages/web-shell/client/components/dialogs/DialogShell.test.tsx @@ -187,7 +187,13 @@ describe('DialogShell', () => { // stays full-width and never tracks the content. expect(panel.className).toContain('w-max'); expect(panel.className).not.toContain('w-full'); - expect(panel.className).toContain('min-w-[min(100%,560px)]'); + // The floor has to subtract the same gutter the surviving base ceiling + // (`max-w-[calc(100%-2rem)]`) reserves. twMerge keeps both classes, and + // below `sm:` a bare `min(100%,560px)` floor outranks that ceiling, so the + // panel would render flush to both screen edges on a phone. + expect(panel.className).toContain('min-w-[min(calc(100%-2rem),560px)]'); + expect(panel.className).not.toContain('min-w-[min(100%,560px)]'); + expect(panel.className).toContain('max-w-[calc(100%-2rem)]'); expect(panel.className).toContain( 'sm:max-w-[min(calc(100vw-2rem),1120px)]', ); diff --git a/packages/web-shell/client/components/dialogs/DialogShell.tsx b/packages/web-shell/client/components/dialogs/DialogShell.tsx index 260aab228e0..341a0e2083c 100644 --- a/packages/web-shell/client/components/dialogs/DialogShell.tsx +++ b/packages/web-shell/client/components/dialogs/DialogShell.tsx @@ -43,7 +43,12 @@ const sizeClass: Record = { // room. `w-max` wins over DialogContent's base `w-full` through // tailwind-merge. The floor keeps small graphs from collapsing to a narrow // panel; the ceiling keeps large ones from spanning a wide monitor. - auto: 'w-max min-w-[min(100%,560px)] sm:max-w-[min(calc(100vw-2rem),1120px)]', + // The floor uses the same 2rem gutter the base ceiling + // (`max-w-[calc(100%-2rem)]`) reserves: twMerge keeps both classes, and + // below `sm:` a bare `min(100%,560px)` floor outranks that ceiling, so the + // panel rendered flush to both screen edges on a phone while every fixed + // size kept its gutter. + auto: 'w-max min-w-[min(calc(100%-2rem),560px)] sm:max-w-[min(calc(100vw-2rem),1120px)]', }; const FOCUSABLE_SELECTOR = [