"use client"; import { useEffect, useRef, useState } from "react"; import type { Heading } from "@/lib/types"; export function DocsToc({ headings }: { headings: Heading[] }) { const [activeId, setActiveId] = useState(headings[0]?.id ?? null); const observerRef = useRef(null); useEffect(() => { if (typeof window === "undefined" || headings.length === 0) return; const ids = headings.map((h) => h.id); const elements = ids .map((id) => document.getElementById(id)) .filter((el): el is HTMLElement => el !== null); if (elements.length === 0) return; const visible = new Set(); const observer = new IntersectionObserver( (entries) => { for (const entry of entries) { if (entry.isIntersecting) visible.add(entry.target.id); else visible.delete(entry.target.id); } let next = null; for (const h of headings) { if (visible.has(h.id)) { next = h.id; break; } } if (!next && visible.size === 0) { const scrollY = window.scrollY; for (let i = elements.length - 1; i >= 0; i--) { if (elements[i].offsetTop <= scrollY + 80) { next = elements[i].id; break; } } } if (next) setActiveId(next); }, { rootMargin: "-64px 0px -60% 0px", threshold: 0 }, ); elements.forEach((el) => observer.observe(el)); observerRef.current = observer; return () => observer.disconnect(); }, [headings]); if (headings.length === 0) return null; return ( ); }