/** * Scrollspy allows you to watch visible headings in a specific page. * Useful for table of contents live style updates. */ export function useScrollspy() { const observer = ref() const visibleHeadings = ref([]) const activeHeadings = ref([]) const observerCallback = (entries: IntersectionObserverEntry[]) => { entries.forEach((entry) => { const id = entry.target.id if (entry.isIntersecting) { visibleHeadings.value = [...visibleHeadings.value, id] } else { visibleHeadings.value = visibleHeadings.value.filter(h => h !== id) } }) } const updateHeadings = (headings: Element[]) => { headings.forEach((heading) => { if (!observer.value) { return } observer.value.observe(heading) }) } const reset = () => { if (observer.value) { observer.value.disconnect() observer.value = new IntersectionObserver(observerCallback) } visibleHeadings.value = [] activeHeadings.value = [] } watch(visibleHeadings, (val, oldVal) => { if (val.length === 0) { activeHeadings.value = oldVal } else { activeHeadings.value = val } }) // Create intersection observer onBeforeMount( () => (observer.value = new IntersectionObserver(observerCallback)), ) // Destroy it onBeforeUnmount(() => observer.value?.disconnect()) return { visibleHeadings, activeHeadings, updateHeadings, reset, } }