fix(ui-chat): clip horizontal overflow in the chat transcript (#6930)

This commit is contained in:
imccyu authored and GitHub committed 2026-10-22 12:43:26 +08:00
commit 4349b4e5f2
2 files changed
+32 -1

No files matched your search

@@ -22,6 +22,10 @@
.scroll {
flex: 1 1 auto;
min-height: 0;
/* Never expose horizontal scrollable overflow: the absolutely positioned
text-interaction surface adds it transiently, and the changing scroll range
makes the transcript jitter while the tail is pinned. */
overflow-x: clip;
overflow-y: auto;
/* Sides = composer clearance + 16px: on narrow viewports the transcript
stays exactly 32px narrower than the input card (the shared width rule). */
@@ -46,7 +50,10 @@
}
:global([data-conversation-scroll]) .scroll {
overflow: visible;
/* A host scrollport still owns vertical overflow; horizontal overflow is
clipped for the same reason as the self-scrolled case above. */
overflow-x: clip;
overflow-y: visible;
flex: 0 0 auto;
min-height: auto;
}
@@ -0,0 +1,24 @@
/** The transcript scroller never exposes horizontal scrollable overflow. */
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
const read = (name: string): string =>
readFileSync(fileURLToPath(new URL(`../src/client/chat/${name}`, import.meta.url)), 'utf8')
const rule = (css: string, selector: string): string => {
const start = css.indexOf(`${selector} {`)
return css.slice(start, css.indexOf('}', start) + 1)
}
describe('Transcript scroll overflow', () => {
it('clips the horizontal axis in both scrollport modes', () => {
// The text-interaction surface is absolutely positioned inside the message
// column and can reach past its right edge; an `auto` horizontal axis turns
// that into a scroll range whose appearance and resolution jitter the
// transcript while the tail is pinned.
const css = read('ChatView.module.css')
expect(rule(css, '.scroll')).toMatch(/overflow-x:\s*clip/)
expect(rule(css, ':global([data-conversation-scroll]) .scroll')).toMatch(/overflow-x:\s*clip/)
})
})