Skip to content

Commit 97788a0

Browse files
committed
fix: prevent scroll-reset from avatar preload and lazy chart mount
- Remove avatarVersion from chart stack key to stop full chart remount on avatar resolve - Keep minHeight on LazyChart wrapper and lock to actual height after render - Add .angular/ to .gitignore (270MB leftover cache)
1 parent e1cf737 commit 97788a0

3 files changed

Lines changed: 28 additions & 3 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dist
1212
dist-ssr
1313
*.local
1414
coverage
15+
.angular
1516

1617
# Editor directories and files
1718
.vscode/*

src/components/ReportPageLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ export function ReportPageLayout({ schema, allowedReportTypes, metricOptions }:
589589
|| activeReport?.type === REPORT_TYPES.ENTERPRISE_MEMBERS;
590590
return (
591591
<Suspense fallback={null}>
592-
<div className={styles.chartStack} key={`${activeReportIndex}-${avatarVersion}`}>
592+
<div className={styles.chartStack} key={activeReportIndex}>
593593
{!isFlatReport && (
594594
<div className={styles.chartSurface}>
595595
<TimeSeriesChart metricOptions={chartMetricOptions} />

src/components/charts/LazyChart.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState, type ReactNode } from 'react';
1+
import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react';
22

33
interface LazyChartProps {
44
children: ReactNode;
@@ -10,6 +10,9 @@ interface LazyChartProps {
1010
/**
1111
* Defers rendering of a chart component until it enters (or is near) the viewport.
1212
* Prevents off-screen charts from blocking the main thread during filter changes.
13+
*
14+
* Uses `contain: content` while loading to prevent layout shifts from propagating
15+
* up the DOM, and keeps minHeight after mount to avoid scroll-jump on transition.
1316
*/
1417
export function LazyChart({ children, className, minHeight = 400 }: LazyChartProps) {
1518
const ref = useRef<HTMLDivElement>(null);
@@ -33,8 +36,29 @@ export function LazyChart({ children, className, minHeight = 400 }: LazyChartPro
3336
return () => observer.disconnect();
3437
}, []);
3538

39+
// After chart renders, lock the wrapper to the actual rendered height to
40+
// prevent scroll jumps when the chart's intrinsic size differs from minHeight.
41+
const lockHeight = useCallback((node: HTMLDivElement | null) => {
42+
if (!node) return;
43+
// Wait a tick for Highcharts to finish its initial reflow
44+
requestAnimationFrame(() => {
45+
const h = node.getBoundingClientRect().height;
46+
if (h > 0) {
47+
node.style.minHeight = `${h}px`;
48+
}
49+
});
50+
}, []);
51+
3652
return (
37-
<div ref={ref} className={className} style={visible ? undefined : { minHeight }}>
53+
<div
54+
ref={(node) => {
55+
// Merge refs
56+
(ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
57+
if (visible) lockHeight(node);
58+
}}
59+
className={className}
60+
style={{ minHeight, contain: visible ? undefined : 'content' }}
61+
>
3862
{visible ? children : null}
3963
</div>
4064
);

0 commit comments

Comments
 (0)