@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
68 lines (67 loc) • 2.18 kB
JavaScript
"use client";
import { randomId } from "../utils/random-id/random-id.mjs";
import { useEffect, useRef, useState } from "react";
//#region packages/@mantine/hooks/src/use-scroll-spy/use-scroll-spy.ts
function getHeadingsData(headings, getDepth, getValue) {
const result = [];
for (let i = 0; i < headings.length; i += 1) {
const heading = headings[i];
result.push({
depth: getDepth(heading),
value: getValue(heading),
id: heading.id || randomId(),
getNode: () => heading.id ? document.getElementById(heading.id) : heading
});
}
return result;
}
function getActiveElement(rects, offset = 0) {
if (rects.length === 0) return -1;
return rects.reduce((acc, item, index) => {
if (Math.abs(acc.position - offset) < Math.abs(item.y - offset)) return acc;
return {
index,
position: item.y
};
}, {
index: 0,
position: rects[0].y
}).index;
}
function getDefaultDepth(element) {
return Number(element.tagName[1]);
}
function getDefaultValue(element) {
return element.textContent || "";
}
function useScrollSpy({ selector = "h1, h2, h3, h4, h5, h6", getDepth = getDefaultDepth, getValue = getDefaultValue, offset = 0, scrollHost } = {}) {
const [active, setActive] = useState(-1);
const [initialized, setInitialized] = useState(false);
const [data, setData] = useState([]);
const headingsRef = useRef([]);
const handleScroll = () => {
setActive(getActiveElement(headingsRef.current.map((d) => d.getNode().getBoundingClientRect()), offset));
};
const initialize = () => {
const headings = getHeadingsData(Array.from(document.querySelectorAll(selector)), getDepth, getValue);
headingsRef.current = headings;
setInitialized(true);
setData(headings);
setActive(getActiveElement(headings.map((d) => d.getNode().getBoundingClientRect()), offset));
};
useEffect(() => {
initialize();
const _scrollHost = scrollHost || window;
_scrollHost.addEventListener("scroll", handleScroll);
return () => _scrollHost.removeEventListener("scroll", handleScroll);
}, [scrollHost]);
return {
reinitialize: initialize,
active,
initialized,
data
};
}
//#endregion
export { useScrollSpy };
//# sourceMappingURL=use-scroll-spy.mjs.map