From b3d588da886c1f39b7a1fbb7bbaa50cc9f8f28eb Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Tue, 3 Nov 2026 22:13:05 +0000 Subject: [PATCH] fix(dashboard): Stop transcript jumps while scrolling up on mobile Transcript rows on phones used content-visibility: auto with a 12rem size estimate. Each row that had not rendered yet changed size when the reader scrolled near it, so the pinning hook corrected the scroll position while the reader scrolled. Lay rows out at their real size instead. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com> --- .../e2e/conversations-mobile.spec.ts | 21 +++++++++++++++++++ .../client/conversations/TranscriptRows.tsx | 11 ++++++++-- packages/junior-dashboard/src/tailwind.css | 5 ----- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/junior-dashboard/e2e/conversations-mobile.spec.ts b/packages/junior-dashboard/e2e/conversations-mobile.spec.ts index 32fd694180..85c2214fcb 100644 --- a/packages/junior-dashboard/e2e/conversations-mobile.spec.ts +++ b/packages/junior-dashboard/e2e/conversations-mobile.spec.ts @@ -721,6 +721,27 @@ test("keeps the message in view while earlier history and late content load", as transcript.getByText("Transcript message 39 "), ).not.toBeInViewport(); + // Rows keep their real size while the reader scrolls up through them, so + // the transcript never corrects the reader's own scroll. On phones, such + // corrections make the transcript jump. + await transcript.evaluate((element) => { + const scrollTo = element.scrollTo.bind(element); + element.dataset.scrollCorrections = "0"; + element.scrollTo = (...args: Parameters) => { + element.dataset.scrollCorrections = String( + Number(element.dataset.scrollCorrections) + 1, + ); + scrollTo(...args); + }; + }); + await transcript.hover(); + for (let step = 0; step < 8; step += 1) { + await page.mouse.wheel(0, -150); + } + await expect(transcript.getByText("Transcript message 30 ")).toBeInViewport(); + await expect(transcript).toHaveAttribute("data-scroll-corrections", "0"); + await transcript.getByText("Transcript message 43 ").scrollIntoViewIfNeeded(); + // Content that grows above the reader, such as an image that loads late, // must not push the message they are reading out of view. await transcript.getByText("Transcript message 20 ").evaluate((element) => { diff --git a/packages/junior-dashboard/src/client/conversations/TranscriptRows.tsx b/packages/junior-dashboard/src/client/conversations/TranscriptRows.tsx index 2ca947768c..a0a683bb17 100644 --- a/packages/junior-dashboard/src/client/conversations/TranscriptRows.tsx +++ b/packages/junior-dashboard/src/client/conversations/TranscriptRows.tsx @@ -35,7 +35,14 @@ export function TranscriptUnreadMarker() { ); } -/** Leave room for control outlines inside the mobile row's paint bounds. */ +/** + * Lay out one transcript row at its real size. + * + * Rows do not use `content-visibility: auto`. A skipped row has an estimated + * size, and it changes size when the reader scrolls near it. Above the + * reader, each change needs a scroll correction while they scroll, and on + * phones those corrections make the transcript jump. + */ export function TranscriptRow(props: { /** Stable row id that holds the reader's place while layout changes. */ anchorKey?: string; @@ -46,7 +53,7 @@ export function TranscriptRow(props: { }) { return (
diff --git a/packages/junior-dashboard/src/tailwind.css b/packages/junior-dashboard/src/tailwind.css index 733b4bd9f1..c9875cf7c7 100644 --- a/packages/junior-dashboard/src/tailwind.css +++ b/packages/junior-dashboard/src/tailwind.css @@ -363,9 +363,4 @@ content-visibility: auto; contain-intrinsic-size: auto 3.5rem; } - - .mobile-transcript-row { - content-visibility: auto; - contain-intrinsic-size: auto 12rem; - } }