Skip to content

Commit 06ab299

Browse files
committed
fix(response): manually center active match horizontally on jump
scrollIntoView({ inline: 'center' }) wasn't centering the active match inside the virtualized scroll container — the combination of contain:strict on the parent and the absolute-positioned inner slab made it unreliable across match hops. Replace it with an explicit computation: read the mark's bounding rect, project it into the parent's scrollable content space, and set parent.scrollLeft = center - clientWidth/2. Also drop the smooth behaviour on virtualizer.scrollToIndex so the row is at its final position by the time we measure in the next frame.
1 parent 55224f7 commit 06ab299

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

apps/desktop/src/renderer/src/components/ResponseViewer.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -568,24 +568,31 @@ function VirtualTextBody({
568568
});
569569

570570
// Expose a scroll-to callback so BodyPanel can jump to active match line.
571-
// virtualizer handles the vertical scroll; after the row is mounted we also
572-
// center the active <mark> horizontally so long lines (pretty JSON, minified
573-
// HTML) don't hide the hit off the right edge.
571+
// virtualizer handles vertical scroll (instant — smooth left the DOM in an
572+
// intermediate position while we tried to measure). After the row is
573+
// mounted we compute the active mark's left offset manually and set
574+
// parent.scrollLeft directly, which works regardless of contain:strict or
575+
// the absolute-positioned slab we render inside.
574576
useEffect(() => {
575577
scrollToLineRef.current = (lineIndex: number) => {
576-
virtualizer.scrollToIndex(lineIndex, { align: 'center', behavior: 'smooth' });
578+
virtualizer.scrollToIndex(lineIndex, { align: 'center', behavior: 'auto' });
577579
requestAnimationFrame(() => {
578580
requestAnimationFrame(() => {
579-
const el = parentRef.current?.querySelector(
581+
const parent = parentRef.current;
582+
if (!parent) return;
583+
const el = parent.querySelector<HTMLElement>(
580584
'[data-active-match="true"]',
581585
);
582-
if (el instanceof HTMLElement) {
583-
el.scrollIntoView({
584-
inline: 'center',
585-
block: 'nearest',
586-
behavior: 'smooth',
587-
});
588-
}
586+
if (!el) return;
587+
const parentRect = parent.getBoundingClientRect();
588+
const elRect = el.getBoundingClientRect();
589+
const elCenterWithinContent =
590+
elRect.left + elRect.width / 2 - parentRect.left + parent.scrollLeft;
591+
const targetScrollLeft = Math.max(
592+
0,
593+
elCenterWithinContent - parent.clientWidth / 2,
594+
);
595+
parent.scrollLeft = targetScrollLeft;
589596
});
590597
});
591598
};

0 commit comments

Comments
 (0)