Skip to content

Commit

Permalink
fix: Prevent initial unnecessary IntersectionObserver callback execut…
Browse files Browse the repository at this point in the history
…ion (#2523)
  • Loading branch information
sy-records authored Jan 6, 2025
1 parent 5826863 commit a73e07e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 14 deletions.
39 changes: 26 additions & 13 deletions src/core/event/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function Events(Base) {
// =========================================================================
/**
* Initialize cover observer
* Toggles sticky behavior when when cover is not in view
* Toggles sticky behavior when cover is not in view
* @void
*/
#initCover() {
Expand Down Expand Up @@ -74,11 +74,17 @@ export function Events(Base) {
#initHeadings() {
const headingElms = dom.findAll('#main :where(h1, h2, h3, h4, h5)');
const headingsInView = new Set();
let isInitialLoad = true;

// Mark sidebar active item on heading intersection
this.#intersectionObserver?.disconnect();
this.#intersectionObserver = new IntersectionObserver(
entries => {
if (isInitialLoad) {
isInitialLoad = false;
return;
}

if (this.#isScrolling) {
return;
}
Expand All @@ -89,18 +95,25 @@ export function Events(Base) {
headingsInView[op](entry.target);
}

const activeHeading =
headingsInView.size > 1
? // Sort headings by proximity to viewport top and select first
Array.from(headingsInView).sort((a, b) =>
a.compareDocumentPosition(b) &
Node.DOCUMENT_POSITION_FOLLOWING
? -1
: 1,
)[0]
: // Get first and only item in set.
// May be undefined if no headings are in view.
headingsInView.values().next().value;
let activeHeading;
if (headingsInView.size === 1) {
// Get first and only item in set.
// May be undefined if no headings are in view.
activeHeading = headingsInView.values().next().value;
} else if (headingsInView.size > 1) {
// Find the closest heading to the top of the viewport
// Reduce over the Set of headings currently in view (headingsInView) to determine the closest heading.
activeHeading = Array.from(headingsInView).reduce(
(closest, current) => {
return !closest ||
closest.compareDocumentPosition(current) &
Node.DOCUMENT_POSITION_FOLLOWING
? current
: closest;
},
null,
);
}

if (activeHeading) {
const id = activeHeading.getAttribute('id');
Expand Down
2 changes: 1 addition & 1 deletion src/core/render/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class Compiler {
}

/**
* Compile sidebar, it uses _sidebar.md ( or specific file) or the content's headings toc to render sidebar.
* Compile sidebar, it uses _sidebar.md (or specific file) or the content's headings toc to render sidebar.
* @param {String} text Text content from the sidebar file, maybe empty
* @param {Number} level Type of heading (h<level> tag)
* @returns {String} Sidebar element
Expand Down

0 comments on commit a73e07e

Please sign in to comment.