feat(ui): unify list virtualization on @tanstack/react-virtual and polish scroll behavior
- Migrate sidebar session groups, git changes panel, virtualized code blocks, and JSON tree viewer from virtua to @tanstack/react-virtual; virtua remains only inside the Pierre diff viewer integration - Sidebar: preserve scroll position when virtualization enables mid-session (enable only once the ancestor scroll element is resolved, seed initial offset from its live scrollTop, render plain rows for the single pre-paint frame); disable native scroll anchoring on the sessions scroller; keep row spacing identical between plain and virtualized modes; absolute row positioning so variable-height rows cannot drift past the container - Chat: expand tool/thinking blocks downward by only adjusting scroll for rows growing above the viewport; raise the desktop history-load lead to 1.5 viewports so prepends land above the visible area - Git changes: compute the prefetch window from the first visible row, skipping overscan rows above the viewport - Sidebar rows: make the whole highlighted row area clickable, guarded against double-firing from interactive children
This commit is contained in:
@@ -747,6 +747,18 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
handleSessionSelect(session.id, sessionDirectory, projectId);
|
||||
};
|
||||
|
||||
// The selection/active highlight covers the WHOLE row box (gutter, edge
|
||||
// paddings), while the primary click target is the inner title button.
|
||||
// Make the rest of the highlighted box clickable too — but only for clicks
|
||||
// that did not originate from an interactive child (title button, chevron,
|
||||
// action menu), so nothing double-fires.
|
||||
const handleRowBackgroundClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (event.defaultPrevented) return;
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.closest('button, a, input, [role="menuitem"], [role="menu"]')) return;
|
||||
handleRowSelect(event as unknown as React.MouseEvent<HTMLButtonElement>);
|
||||
};
|
||||
|
||||
const handleRowMouseDown = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (event.button === 2 || (event.button === 0 && event.ctrlKey && !selectionModeEnabled)) {
|
||||
suppressNextSelectRef.current = true;
|
||||
@@ -974,8 +986,9 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
data-session-row={session.id}
|
||||
data-session-scope={sessionDirectory ?? ''}
|
||||
data-session-archived={archivedBucket ? '1' : '0'}
|
||||
onClick={handleRowBackgroundClick}
|
||||
className={cn(
|
||||
'group relative my-0.5 flex items-center rounded-md py-1 pr-1.5',
|
||||
'group relative my-0.5 flex cursor-pointer items-center rounded-md py-1 pr-1.5',
|
||||
// Pull the row box left into the container gutter so the
|
||||
// selection highlight covers the chevron/status markers
|
||||
// (which sit in that gutter), then re-pad so the title text
|
||||
|
||||
Reference in New Issue
Block a user