UNPKG

@redocly/theme

Version:

Shared UI components lib

79 lines 3.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useActiveHeading = useActiveHeading; const react_1 = require("react"); const react_router_dom_1 = require("react-router-dom"); function useActiveHeading(contentElement, displayedHeaders) { const [heading, setHeading] = (0, react_1.useState)(displayedHeaders.length > 1 ? displayedHeaders[0] : undefined); const [headingElements, setHeadingElements] = (0, react_1.useState)([]); const headingElementsRef = (0, react_1.useRef)({}); const location = (0, react_router_dom_1.useLocation)(); const getVisibleHeadings = () => { const visibleHeadings = []; for (const key in headingElementsRef.current) { const headingElement = headingElementsRef.current[key]; if (headingElement.isIntersecting) { visibleHeadings.push(headingElement); } } return visibleHeadings; }; const getIndexFromId = (0, react_1.useCallback)((id) => { return headingElements.findIndex((item) => item.id === id); }, [headingElements]); const findHeaders = (allContent) => { const allHeaders = allContent.querySelectorAll('.heading-anchor'); return Array.from(allHeaders); }; const intersectionCallback = (0, react_1.useCallback)((headings) => { var _a; headingElementsRef.current = headings.reduce((map, headingElement) => { map[headingElement.target.id] = headingElement; return map; }, headingElementsRef.current); const totalHeight = window.scrollY + window.innerHeight; // handle bottom of the page if (totalHeight >= document.body.scrollHeight) { const newHeading = ((_a = headingElements[(headingElements === null || headingElements === void 0 ? void 0 : headingElements.length) - 1]) === null || _a === void 0 ? void 0 : _a.id) || undefined; setHeading(newHeading); return; } const visibleHeadings = getVisibleHeadings(); if (!visibleHeadings.length) { return; } if (visibleHeadings.length === 1) { setHeading(visibleHeadings[0].target.id); return; } visibleHeadings.sort((a, b) => { return getIndexFromId(a.target.id) - getIndexFromId(b.target.id); }); setHeading(visibleHeadings[0].target.id); }, [getIndexFromId, headingElements]); (0, react_1.useEffect)(() => { if (!contentElement) { return; } setHeadingElements(findHeaders(contentElement)); }, [contentElement, location]); (0, react_1.useEffect)(() => { if (!(headingElements === null || headingElements === void 0 ? void 0 : headingElements.length)) { return; } headingElementsRef.current = {}; // Bottom rootMargin -30% changes part of the view where IntersectionObserver starts to detect headers const observer = new IntersectionObserver(intersectionCallback, { rootMargin: '0px 0px -30% 0px', threshold: 1, }); headingElements === null || headingElements === void 0 ? void 0 : headingElements.forEach((element) => { if (displayedHeaders.includes(element.id)) { observer.observe(element); } }); return () => observer.disconnect(); }, [headingElements, displayedHeaders, intersectionCallback]); return heading; } //# sourceMappingURL=use-active-heading.js.map