fix(desktop): overlay scrollbars on conversation code blocks (#73670)

The app-wide `.scrollbar-dt *` webkit rules force classic always-on
gutters on every descendant scroller. Opt code-card scroll surfaces out
via `.scrollbar-overlay` so Electron keeps platform overlay bars (fade
in on scroll, no reserved track).
This commit is contained in:
brooklyn! 2026-07-28 17:13:54 -05:00 committed by GitHub
parent ed5fd3503d
commit f9d7bca252
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 32 additions and 11 deletions

View file

@ -36,7 +36,7 @@ function CodeCardBody({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
className={cn(
'font-mono text-[0.7rem] leading-relaxed text-foreground/90 [&_pre]:m-0 [&_pre]:overflow-x-auto [&_pre]:bg-transparent! [&_pre]:px-2 [&_pre]:py-1.5 [&_pre]:font-mono [&_pre]:leading-relaxed',
'font-mono text-[0.7rem] leading-relaxed text-foreground/90 [&_pre]:m-0 [&_pre]:overflow-x-auto [&_pre]:scrollbar-overlay [&_pre]:bg-transparent! [&_pre]:px-2 [&_pre]:py-1.5 [&_pre]:font-mono [&_pre]:leading-relaxed',
className
)}
data-slot="code-card-body"

View file

@ -37,8 +37,10 @@ describe('ExpandableBlock', () => {
const toggle = screen.getByRole('button', { name: /expand|collapse/i })
const fade = toggle.parentElement!
// Inner container allows horizontal scroll so wide code gets a scrollbar.
// Inner container allows horizontal scroll so wide code gets a scrollbar:
// platform overlay (`scrollbar-overlay`), not the always-on classic gutter.
expect(inner.className).toContain('overflow-x-auto')
expect(inner.className).toContain('scrollbar-overlay')
// The full-width fade is a pure cue: it spans the bottom edge but must not
// intercept pointer events, so the scrollbar drag and text selection on the

View file

@ -32,7 +32,13 @@ export function ExpandableBlock({ children, className }: ExpandableBlockProps) {
return (
<div className="relative">
<div
className={cn('overflow-y-auto overflow-x-auto', expanded ? 'max-h-[40dvh]' : 'max-h-[7.5rem]', className)}
className={cn(
// `scrollbar-overlay` opts out of the app-wide classic thin gutters so
// this scroller keeps platform overlay bars (no always-on track).
'scrollbar-overlay overflow-y-auto overflow-x-auto',
expanded ? 'max-h-[40dvh]' : 'max-h-[7.5rem]',
className
)}
ref={innerRef}
>
{children}

View file

@ -965,36 +965,42 @@ text-* variant utilities. */ .btn-arc {
thin on mac still looks chunky. Use webkit for real thin thumbs; gate the
standard props so only non-webkit engines (Firefox) take that path.
https://developer.chrome.com/docs/css-ui/scrollbar-styling
https://syntackle.com/blog/changes-to-scrollbar-styling-in-chrome-121/ */
https://syntackle.com/blog/changes-to-scrollbar-styling-in-chrome-121/
Any author rule on ::-webkit-scrollbar switches that scroller from
platform overlay (fade in on scroll, zero gutter) to classic always-on
gutters. `.scrollbar-overlay` opts a surface out of the themed rules so
Electron keeps native overlay used by conversation code blocks where a
permanent 4px track eats the card and always draws a bar. */
.scrollbar-dt::-webkit-scrollbar,
.scrollbar-dt *::-webkit-scrollbar {
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar {
width: 0.25rem;
height: 0.25rem;
}
.scrollbar-dt::-webkit-scrollbar-track,
.scrollbar-dt::-webkit-scrollbar-corner,
.scrollbar-dt *::-webkit-scrollbar-track,
.scrollbar-dt *::-webkit-scrollbar-corner {
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-track,
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-corner {
background: transparent;
}
.scrollbar-dt::-webkit-scrollbar-thumb,
.scrollbar-dt *::-webkit-scrollbar-thumb {
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--dt-midground) 18%, transparent);
border-radius: 9999rem;
background-clip: padding-box;
}
.scrollbar-dt::-webkit-scrollbar-thumb:hover,
.scrollbar-dt *::-webkit-scrollbar-thumb:hover {
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-thumb:hover {
background: color-mix(in srgb, var(--dt-midground) 40%, transparent);
background-clip: padding-box;
}
.scrollbar-dt::-webkit-scrollbar-button,
.scrollbar-dt *::-webkit-scrollbar-button {
.scrollbar-dt *:not(.scrollbar-overlay)::-webkit-scrollbar-button {
display: none;
}
@ -1029,7 +1035,7 @@ text-* variant utilities. */ .btn-arc {
@supports not selector(::-webkit-scrollbar) {
.scrollbar-dt,
.scrollbar-dt * {
.scrollbar-dt *:not(.scrollbar-overlay) {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--dt-midground) 18%, transparent) transparent;
}
@ -1038,6 +1044,13 @@ text-* variant utilities. */ .btn-arc {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--dt-midground) 28%, transparent) transparent;
}
/* Firefox has no real overlay mode; thin + transparent track is the closest
match to the Chromium overlay opt-out above. */
.scrollbar-overlay {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--dt-midground) 28%, transparent) transparent;
}
}
}