core/observers/document.observer.ts

core/observers/document.observer.ts is a file in Bane's Lab Site. 45 lines of code and 10 definitions.

import { ACTIVE_CLASS } from "#configuration/constants/element.constants";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import type { Disposer } from "#types/base.types";

const ROOT_MARGIN = "-20% 0px -60% 0px";
const THRESHOLD = [0, 0.25, 0.5, 0.75, 1];

const markActive = function markActive(links: readonly HTMLAnchorElement[], id: string): void {
    for (const link of links) {
        link.classList.toggle(ACTIVE_CLASS, link.hash === ANCHOR_PREFIX + id);
    }
};

const bestEntry = function bestEntry(ratios: ReadonlyMap<string, number>): string | null {
    let best: string | null = null;
    let bestRatio = 0;
    for (const [id, ratio] of ratios) {
        if (ratio > bestRatio) {
            bestRatio = ratio;
            best = id;
        }
    }
    return best;
};

export const observeSections = function observeSections(
    sections: readonly Element[],
    links: readonly HTMLAnchorElement[],
): Disposer {
    const ratios = new Map<string, number>();
    const observer = new IntersectionObserver(
        (entries) => {
            for (const entry of entries) {
                ratios.set(entry.target.id, entry.isIntersecting ? entry.intersectionRatio : 0);
            }
            const active = bestEntry(ratios);
            if (active !== null) {
                markActive(links, active);
            }
        },
        { rootMargin: ROOT_MARGIN, threshold: THRESHOLD },
    );
    for (const section of sections) {
        observer.observe(section);
    }
    return () => {
        observer.disconnect();
    };
};