Skip to content

Commit d2df640

Browse files
committed
fix: nicer sidebar scroll position behavior
1 parent abe2f92 commit d2df640

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

src/components/focus-active-link.tsx

+38-7
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,54 @@
11
'use client';
22
import {useEffect} from 'react';
33

4+
import {debounce} from 'sentry-docs/utils';
5+
46
type Props = {
57
activeLinkSelector: string;
68
};
79

810
/** Make sure the active link is visible in the sidebar */
911
export function ScrollActiveLink({activeLinkSelector}: Props) {
10-
const isVsibible = (link: Element) => {
11-
const rect = link.getBoundingClientRect();
12-
return rect.top >= 0 && rect.bottom <= window.innerHeight;
13-
};
12+
useEffect(() => {
13+
const sidebar = document.querySelector('[data-sidebar-link]')?.closest('aside');
14+
if (!sidebar) {
15+
return;
16+
}
17+
sidebar.addEventListener('click', e => {
18+
const target = e.target as HTMLElement;
19+
if (target.hasAttribute('data-sidebar-link')) {
20+
const top = target.getBoundingClientRect().top;
21+
sessionStorage.setItem('sidebar-link-poisition', top.toString());
22+
}
23+
});
24+
// track active link position on scroll as well
25+
sidebar.addEventListener(
26+
'scroll',
27+
debounce(() => {
28+
const activeLink = document.querySelector(activeLinkSelector);
29+
if (activeLink) {
30+
const top = activeLink.getBoundingClientRect().top.toString();
31+
sessionStorage.setItem('sidebar-link-poisition', top);
32+
}
33+
}, 50)
34+
);
35+
}, [activeLinkSelector]);
1436

1537
useEffect(() => {
1638
const activeLink = document.querySelector(activeLinkSelector);
17-
if (activeLink && !isVsibible(activeLink)) {
18-
// try to center the active link in the sidebar
19-
activeLink.scrollIntoView({block: 'center', behavior: 'smooth'});
39+
const sidebar = activeLink?.closest('aside')!;
40+
if (!activeLink || !sidebar) {
41+
return;
42+
}
43+
const previousBoundingRectTop = sessionStorage.getItem('sidebar-link-poisition');
44+
const currentBoundingRectTop = activeLink.getBoundingClientRect().top;
45+
// scroll the sidebar to make sure the active link is visible & has the same position as when it was clicked
46+
if (!previousBoundingRectTop) {
47+
return;
2048
}
49+
const scrollX = 0;
50+
const scrollY = sidebar.scrollTop + currentBoundingRectTop - +previousBoundingRectTop;
51+
sidebar?.scrollTo(scrollX, scrollY);
2152
}, [activeLinkSelector]);
2253
// don't render anything, just exist as a client-side component for the useEffect.
2354
return null;

0 commit comments

Comments
 (0)