rune-scroller
Version:
Lightweight, high-performance scroll animations for Svelte 5. ~2KB bundle, zero dependencies.
76 lines (75 loc) • 2.54 kB
JavaScript
import { onMount } from 'svelte';
/**
* Composable for handling IntersectionObserver logic
* Reduces duplication between animation components
*/
/**
* Factory function to create intersection observer composables
* Eliminates duplication between useIntersection and useIntersectionOnce
* @param options - IntersectionObserver configuration
* @param onIntersect - Callback handler for intersection changes
* @param once - Whether to trigger only once (default: false)
*/
function createIntersectionObserver(options = {}, onIntersect, once = false) {
const { threshold = 0.5, rootMargin = '-10% 0px -10% 0px', root = null } = options;
let element = $state(null);
let isVisible = $state(false);
let hasTriggeredOnce = false;
let observer = null;
onMount(() => {
if (!element)
return;
observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// For once-only behavior, check if already triggered
if (once && hasTriggeredOnce)
return;
isVisible = entry.isIntersecting;
onIntersect(entry, entry.isIntersecting);
// Unobserve after first trigger if once=true
if (once && entry.isIntersecting) {
hasTriggeredOnce = true;
observer?.unobserve(entry.target);
}
});
}, {
threshold,
rootMargin,
root
});
observer.observe(element);
return () => {
observer?.disconnect();
};
});
return {
get element() {
return element;
},
set element(value) {
element = value;
},
get isVisible() {
return isVisible;
}
};
}
/**
* Track element visibility with IntersectionObserver
* Updates isVisible whenever visibility changes
* @param options - IntersectionObserver configuration
* @param onVisible - Optional callback when visibility changes
*/
export function useIntersection(options = {}, onVisible) {
return createIntersectionObserver(options, (_entry, isVisible) => {
onVisible?.(isVisible);
}, false);
}
/**
* Track element visibility once (until first trigger)
* Unobserves after first visibility
* @param options - IntersectionObserver configuration
*/
export function useIntersectionOnce(options = {}) {
return createIntersectionObserver(options, () => { }, true);
}