MCPcopy
hub / github.com/npmx-dev/npmx.dev / setupObserver

Function setupObserver

app/composables/useActiveTocItem.ts:22–89  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

20 const headingElements = new Map<string, Element>()
21
22 const setupObserver = () => {
23 // Clean up previous observer
24 if (observer) {
25 observer.disconnect()
26 }
27 headingElements.clear()
28
29 // Find all heading elements that match TOC IDs
30 const ids = toc.value.map(item => item.id)
31 if (ids.length === 0) return
32
33 for (const id of ids) {
34 const el = document.getElementById(id)
35 if (el) {
36 headingElements.set(id, el)
37 }
38 }
39
40 if (headingElements.size === 0) return
41
42 // Create observer that triggers when headings cross the top 20% of viewport
43 observer = new IntersectionObserver(
44 entries => {
45 // Get all visible headings sorted by their position
46 const visibleHeadings: { id: string; top: number }[] = []
47
48 for (const entry of entries) {
49 if (entry.isIntersecting) {
50 visibleHeadings.push({
51 id: entry.target.id,
52 top: entry.boundingClientRect.top,
53 })
54 }
55 }
56
57 // If there are visible headings, pick the one closest to the top
58 if (visibleHeadings.length > 0) {
59 visibleHeadings.sort((a, b) => a.top - b.top)
60 activeId.value = visibleHeadings[0]?.id ?? null
61 } else {
62 // No headings visible in intersection zone - find the one just above viewport
63 const headingsWithPosition: { id: string; top: number }[] = []
64 for (const [id, el] of headingElements) {
65 const rect = el.getBoundingClientRect()
66 headingsWithPosition.push({ id, top: rect.top })
67 }
68
69 // Find the heading that's closest to (but above) the viewport top
70 const aboveViewport = headingsWithPosition
71 .filter(h => h.top < 100) // Allow some buffer
72 .sort((a, b) => b.top - a.top) // Sort descending (closest to top first)
73
74 if (aboveViewport.length > 0) {
75 activeId.value = aboveViewport[0]?.id ?? null
76 }
77 }
78 },
79 {

Callers

nothing calls this directly

Calls 3

disconnectMethod · 0.80
clearMethod · 0.80
setMethod · 0.65

Tested by

no test coverage detected