From c40c110e72474561b332cdf989d468dfb4c54944 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 04:45:20 +0000 Subject: [PATCH 1/3] fix(answer): clear mobile footer overlap for table expansion Reserve more bottom scroll room when follow-up suggestion chips are shown so the table expand control stays above the fixed composer dock. Harden ui-smoke scrolling and use direct DOM clicks for reliable expansion. Co-authored-by: BigSimmo --- src/components/AccessibleTable.tsx | 4 ++-- src/components/ClinicalDashboard.tsx | 4 +++- tests/ui-smoke.spec.ts | 35 ++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/components/AccessibleTable.tsx b/src/components/AccessibleTable.tsx index 87f779bab..0b745c16e 100644 --- a/src/components/AccessibleTable.tsx +++ b/src/components/AccessibleTable.tsx @@ -414,7 +414,7 @@ export function AccessibleTable({ function openDialog(trigger: HTMLElement) { if (!canExpand) return; - trigger.scrollIntoView({ block: "center", inline: "nearest" }); + trigger.scrollIntoView({ block: "nearest", inline: "nearest" }); restoreFocusRef.current = trigger; setOpen(true); } @@ -458,7 +458,7 @@ export function AccessibleTable({ event.stopPropagation(); openDialog(event.currentTarget); }} - className="relative z-50 mt-2 inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-raised)] px-3 text-xs font-semibold text-[color:var(--text)] shadow-[var(--shadow-tight)] transition hover:border-[color:var(--border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[color:var(--focus)]/25" + className="relative z-50 mt-2 inline-flex min-h-11 w-full items-center justify-center gap-2 scroll-mb-[calc(18rem+env(safe-area-inset-bottom))] rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-raised)] px-3 text-xs font-semibold text-[color:var(--text)] shadow-[var(--shadow-tight)] transition hover:border-[color:var(--border-strong)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[color:var(--focus)]/25" > Expand table diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 49f12d906..ee545ffd9 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -3170,7 +3170,9 @@ export function ClinicalDashboard({ // bottomSearchScrollHidden only ever goes true on phones.) bottomSearchScrollHidden ? "mb-0 sm:mb-24" - : "mb-[calc(5.25rem+env(safe-area-inset-bottom))] sm:mb-24" + : answerFollowUpSuggestions.length > 0 + ? "mb-[calc(18rem+env(safe-area-inset-bottom))] sm:mb-24" + : "mb-[calc(5.25rem+env(safe-area-inset-bottom))] sm:mb-24" : hasMobileBottomSearch ? bottomSearchScrollHidden ? "mb-0 sm:mb-0" diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index b50b1834e..dd572476e 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -572,26 +572,37 @@ async function scrollMobileTableExpandClearOfFooter(page: Page, clinicalTable: L await clinicalTable.scrollIntoViewIfNeeded(); await page.evaluate(() => { const expand = document.querySelector('[data-testid="table-expand-button"]'); - const main = document.querySelector("main"); + const scrollContainer = document.querySelector("main#main-content"); const footer = document.querySelector( ".answer-footer-search-dock, .dashboard-composer-edge.answer-footer-search-edge", ); - if (!expand || !main) return; - const expandRect = expand.getBoundingClientRect(); - const footerTop = footer?.getBoundingClientRect().top ?? window.innerHeight; - const overlap = expandRect.bottom - footerTop + 20; - if (overlap > 0) { - main.scrollTop += overlap; + if (!expand || !scrollContainer) return; + for (let attempt = 0; attempt < 6; attempt += 1) { + const expandRect = expand.getBoundingClientRect(); + const footerTop = footer?.getBoundingClientRect().top ?? window.innerHeight; + const currentOverlap = expandRect.bottom - footerTop + 24; + if (currentOverlap <= 0) break; + scrollContainer.scrollTop += currentOverlap; } }); } async function openMobileTableFullscreen(page: Page, clinicalTable: Locator) { await scrollMobileTableExpandClearOfFooter(page, clinicalTable); + const expandButton = clinicalTable.getByTestId("table-expand-button"); const tableSurface = clinicalTable.getByTestId("accessible-table-surface"); const tableDialog = page.getByTestId("table-fullscreen-dialog"); await expect(async () => { - await tableSurface.click({ force: true }); + if (await tableDialog.isVisible().catch(() => false)) return; + if (await expandButton.isVisible().catch(() => false)) { + await expandButton.evaluate((button: HTMLButtonElement) => { + button.click(); + }); + } else { + await tableSurface.evaluate((surface: HTMLElement) => { + surface.click(); + }); + } await expect(tableDialog).toBeVisible({ timeout: 2_000 }); }).toPass({ timeout: 15_000 }); return tableDialog; @@ -1208,7 +1219,9 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(clinicalTable.getByTestId("accessible-table-surface")).toBeFocused(); if (await tableExpandButton.isVisible().catch(() => false)) { await scrollMobileTableExpandClearOfFooter(page, clinicalTable); - await tableExpandButton.click({ force: true }); + await tableExpandButton.evaluate((button: HTMLButtonElement) => { + button.click(); + }); await expect(tableDialog).toBeVisible(); await tableDialog.getByRole("button", { name: "Close full-screen table" }).click(); await expect(tableDialog).toBeHidden(); @@ -1799,7 +1812,9 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(expandButton).toBeVisible(); await scrollMobileTableExpandClearOfFooter(page, clinicalTable); - await expandButton.click({ force: true }); + await expandButton.evaluate((button: HTMLButtonElement) => { + button.click(); + }); const dialog = page.getByTestId("table-fullscreen-dialog"); await expect(dialog).toBeVisible(); await expect(dialog.getByRole("table")).toBeVisible(); From d45062b5040514ef1a15748f9c8cb6067d46b4a2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 05:02:51 +0000 Subject: [PATCH 2/3] test(ui-smoke): expect expand-button focus after fullscreen close Co-authored-by: BigSimmo --- tests/ui-smoke.spec.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index dd572476e..43a96a550 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -1216,7 +1216,11 @@ test.describe("Clinical KB UI smoke coverage", () => { await expectNoPageHorizontalOverflow(page); await page.keyboard.press("Escape"); await expect(tableDialog).toBeHidden(); - await expect(clinicalTable.getByTestId("accessible-table-surface")).toBeFocused(); + if (await tableExpandButton.isVisible().catch(() => false)) { + await expect(tableExpandButton).toBeFocused(); + } else { + await expect(clinicalTable.getByTestId("accessible-table-surface")).toBeFocused(); + } if (await tableExpandButton.isVisible().catch(() => false)) { await scrollMobileTableExpandClearOfFooter(page, clinicalTable); await tableExpandButton.evaluate((button: HTMLButtonElement) => { From b1e00d7694703a8ecfebeaec24f12997e44231a2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 05:16:01 +0000 Subject: [PATCH 3/3] test(ui-smoke): use real pointer clicks for table expansion Co-authored-by: BigSimmo --- tests/ui-smoke.spec.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index 43a96a550..38ab4c8bb 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -595,13 +595,9 @@ async function openMobileTableFullscreen(page: Page, clinicalTable: Locator) { await expect(async () => { if (await tableDialog.isVisible().catch(() => false)) return; if (await expandButton.isVisible().catch(() => false)) { - await expandButton.evaluate((button: HTMLButtonElement) => { - button.click(); - }); + await expandButton.click(); } else { - await tableSurface.evaluate((surface: HTMLElement) => { - surface.click(); - }); + await tableSurface.click(); } await expect(tableDialog).toBeVisible({ timeout: 2_000 }); }).toPass({ timeout: 15_000 }); @@ -1223,9 +1219,7 @@ test.describe("Clinical KB UI smoke coverage", () => { } if (await tableExpandButton.isVisible().catch(() => false)) { await scrollMobileTableExpandClearOfFooter(page, clinicalTable); - await tableExpandButton.evaluate((button: HTMLButtonElement) => { - button.click(); - }); + await tableExpandButton.click(); await expect(tableDialog).toBeVisible(); await tableDialog.getByRole("button", { name: "Close full-screen table" }).click(); await expect(tableDialog).toBeHidden(); @@ -1816,9 +1810,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(expandButton).toBeVisible(); await scrollMobileTableExpandClearOfFooter(page, clinicalTable); - await expandButton.evaluate((button: HTMLButtonElement) => { - button.click(); - }); + await expandButton.click(); const dialog = page.getByTestId("table-fullscreen-dialog"); await expect(dialog).toBeVisible(); await expect(dialog.getByRole("table")).toBeVisible();