Core: Improve active anchor observer

This commit is contained in:
fuma-nama
2024-08-04 17:03:43 +08:00
parent ed46c9e7fc
commit 37bbfff8d6
2 changed files with 27 additions and 7 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---
Improve active anchor observer
+22 -7
View File
@@ -1,6 +1,9 @@
import { useEffect, useState } from 'react';
/**
* Find the active heading of page
*
* It selects the top heading by default, and the last item when reached the bottom of page.
*
* @param watch - An array of element ids to watch
* @returns Active anchor
@@ -13,12 +16,7 @@ export function useAnchorObserver(watch: string[]): string | undefined {
(entries) => {
setActiveAnchor((f) => {
for (const entry of entries) {
// If above half the viewport
const aboveHalf =
window.innerHeight / 2 > entry.boundingClientRect.y;
const active = aboveHalf && entry.isIntersecting;
if (active) {
if (entry.isIntersecting) {
return entry.target.id;
}
}
@@ -27,9 +25,25 @@ export function useAnchorObserver(watch: string[]): string | undefined {
return f ?? watch[0];
});
},
{ rootMargin: `0% 0% -80% 0%` },
{ rootMargin: `-60px 0% -70% 0%`, threshold: 1 },
);
const scroll = (): void => {
const element = document.scrollingElement;
if (!element) return;
// select the last item when reached the bottom
if (
element.scrollTop >=
// assume you have a 100px margin (including footer & padding)
element.scrollHeight - element.clientHeight - 100
) {
setActiveAnchor(watch.at(-1));
}
};
window.addEventListener('scroll', scroll);
for (const heading of watch) {
const element = document.getElementById(heading);
@@ -39,6 +53,7 @@ export function useAnchorObserver(watch: string[]): string | undefined {
}
return () => {
window.removeEventListener('scroll', scroll);
observer.disconnect();
};
}, [watch]);