Skip to content

Commit

Permalink
[docs] Sturdier quick nav math (#1182)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladmoroz authored Dec 20, 2024
1 parent bf1ff49 commit 331e3b7
Showing 1 changed file with 22 additions and 14 deletions.
36 changes: 22 additions & 14 deletions docs/src/components/QuickNav/QuickNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,25 @@ function onMounted(ref: React.RefObject<HTMLDivElement | null>) {

ref.current.style.top = '0px';
ref.current.style.bottom = '';
ref.current.style.marginTop = '0px';
ref.current.style.marginTop = '';
ref.current.style.marginBottom = '';

// Get the nav top Y coordinate from the start of the document
// if it was `position: static` and `position: absolute`
// relative to the start of the document
ref.current.style.position = 'static';
const staticTop = window.scrollY + ref.current.getBoundingClientRect().y;
const staticTop = window.scrollY + Math.round(ref.current.getBoundingClientRect().y);
ref.current.style.marginTop = '0px';
ref.current.style.position = 'absolute';
const absoluteTop = window.scrollY + ref.current.getBoundingClientRect().y;
const absoluteTop = window.scrollY + Math.round(ref.current.getBoundingClientRect().y);

// Get the nav bottom Y coordinate when it's at its maximum possible bottom position
// relative to the start of the document
ref.current.style.position = 'absolute';
ref.current.style.top = 'auto';
ref.current.style.bottom = '0';
const rect = ref.current.getBoundingClientRect();
const absoluteBottom = window.scrollY + rect.bottom;
const absoluteBottom = window.scrollY + Math.round(rect.bottom);

ref.current.style.position = '';
ref.current.style.top = initialStyles.top;
Expand Down Expand Up @@ -159,14 +160,12 @@ function onMounted(ref: React.RefObject<HTMLDivElement | null>) {
if (!ref.current || isScrollLocked) {
return;
}

const delta = window.scrollY - prevScrollY;
prevScrollY = window.scrollY;

// We may get into <0.1px rounding issues in Safari and Firefox
const rect = ref.current.getBoundingClientRect();
top = Math.round(rect.top);
bottom = Math.round(rect.bottom);
top = rect.top;
bottom = rect.bottom;

// Skip when scrolling in the direction that matches the sticky position
if ((delta > 0 && state === 'StickyBottom') || (delta < 0 && state === 'StickyTop')) {
Expand All @@ -184,11 +183,12 @@ function onMounted(ref: React.RefObject<HTMLDivElement | null>) {
if (state === 'StickyTop') {
const clippedAtBottom = bottom - window.innerHeight;

if (clippedAtBottom - top >= stickyTopThreshold) {
if (clippedAtBottom - top > stickyTopThreshold) {
if (delta >= clippedAtBottom) {
stickToBottom();
} else {
unstick(top - delta, bottom - delta);
// Unstick if we are scrolling down (and not recovering from overscroll)
} else if (delta > 0 && !isOverscrolling()) {
unstick(Math.round(top) - delta, Math.round(bottom) - delta);
}
}
return;
Expand All @@ -197,13 +197,14 @@ function onMounted(ref: React.RefObject<HTMLDivElement | null>) {
if (state === 'StickyBottom') {
if (delta <= top) {
stickToTop();
} else {
unstick(top - delta, bottom - delta);
// Unstick if we are scrolling up (and not recovering from overscroll)
} else if (delta < 0 && !isOverscrolling()) {
unstick(Math.round(top) - delta, Math.round(bottom) - delta);
}
return;
}

if (state === 'Scrollable' && delta <= 0 && top - delta >= cssTop) {
if (state === 'Scrollable' && delta < 0 && top - delta >= cssTop) {
stickToTop();
return;
}
Expand Down Expand Up @@ -259,6 +260,13 @@ function onMounted(ref: React.RefObject<HTMLDivElement | null>) {
};
}

function isOverscrolling() {
return (
window.scrollY < 0 ||
window.scrollY + window.innerHeight > document.documentElement.scrollHeight
);
}

export function Title({ className, ...props }: React.ComponentProps<'header'>) {
return <header className={clsx('QuickNavTitle', className)} {...props} />;
}
Expand Down

0 comments on commit 331e3b7

Please sign in to comment.