a tool for shared writing and social publishing
1// Generated with claude code, sonnet 4.5 2/** 3 * Scrolls an element into view within a scrolling container using Intersection Observer 4 * and the scrollTo API, instead of the native scrollIntoView. 5 * 6 * @param elementId - The ID of the element to scroll into view 7 * @param scrollContainerId - The ID of the scrolling container (defaults to "pages") 8 * @param threshold - Intersection observer threshold (0-1, defaults to 0.2 for 20%) 9 */ 10export function scrollIntoView( 11 elementId: string, 12 scrollContainerId: string = "pages", 13 threshold: number = 0.9, 14) { 15 const element = document.getElementById(elementId); 16 const scrollContainer = document.getElementById(scrollContainerId); 17 18 if (!element || !scrollContainer) { 19 console.warn(`scrollIntoView: element or container not found`, { 20 elementId, 21 scrollContainerId, 22 element, 23 scrollContainer, 24 }); 25 return; 26 } 27 28 // Create an intersection observer to check if element is visible 29 const observer = new IntersectionObserver( 30 (entries) => { 31 const entry = entries[0]; 32 33 // If element is not sufficiently visible, scroll to it 34 if (!entry.isIntersecting || entry.intersectionRatio < threshold) { 35 const elementRect = element.getBoundingClientRect(); 36 const containerRect = scrollContainer.getBoundingClientRect(); 37 38 // Calculate the target scroll position 39 // We want to center the element horizontally in the container 40 const targetScrollLeft = 41 scrollContainer.scrollLeft + 42 elementRect.left - 43 containerRect.left - 44 (containerRect.width - elementRect.width) / 2; 45 46 scrollContainer.scrollTo({ 47 left: targetScrollLeft, 48 behavior: "smooth", 49 }); 50 } 51 52 // Disconnect after checking once 53 observer.disconnect(); 54 }, 55 { 56 root: scrollContainer, 57 threshold: threshold, 58 }, 59 ); 60 61 observer.observe(element); 62}