@adoratorio/medusa
v3.0.6
Published
Medusa is a lightweight, SSR-friendly utility for managing multiple IntersectionObservers with flexible event emission, fine-grained control, native once support, and memory-safe cleanup. Ideal for lazy loading, animations, and viewport-based triggers in
Readme
Medusa
A lightweight utility for managing multiple IntersectionObserver instances with TypeScript support.
Installation
npm install @adoratorio/medusaUsage
import Medusa from '@adoratorio/medusa';
const medusa = new Medusa({ debug: true });Configuration
MedusaOptions
| Parameter | Type | Default | Description |
| :-------: | :--: | :-----: | :---------- |
| observers | MedusaObserverConfig[] | [] | Array of observer configurations |
| debug | boolean | false | Enable console debugging |
Observer Configuration
interface MedusaObserverConfig {
id: string;
root?: Element | null;
rootMargin?: string;
threshold?: number | number[];
nodes?: Element | Element[];
mode?: MODE;
emit?: boolean;
callback?: MedusaCallback;
}
type MedusaCallback = (
entry: IntersectionObserverEntry,
observer: IntersectionObserver | null,
) => void;Configuration Options
| Parameter | Type | Default | Description |
| :-------: | :--: | :-----: | :---------- |
| id | string | required | Unique observer identifier |
| root | Element | null | Viewport element for intersection checking |
| rootMargin | string | '0px' | Margin around root (CSS format) |
| threshold | number\|number[] | 0 | Intersection threshold(s) |
| mode | MODE | DEFAULT | Observer behavior mode |
| emit | boolean | false | Emit custom events on intersection |
| callback | MedusaCallback | undefined | Intersection callback function |
Available Modes
enum MODE {
DEFAULT = 'DEFAULT', // Trigger on every intersection
ONCE = 'ONCE', // Trigger only once
BYPIXELS = 'BYPIXELS', // Trigger per pixel in viewport
}Methods
Adding Observers
// Add single observer
medusa.addObserver({
id: 'myObserver',
threshold: 0.5,
callback: (entry, observer) => console.log('Intersecting:', entry.isIntersecting),
});
// Add multiple observers
medusa.addObserver([
{ id: 'observer1', mode: Medusa.MODE.ONCE },
{ id: 'observer2', mode: Medusa.MODE.BYPIXELS },
]);Observing Elements
// Observe single element
const element = document.querySelector('.target');
medusa.observe('myObserver', element);
// Observe with custom callback
medusa.observe('myObserver', element, (entry, observer) => {
console.log('Custom callback for this element');
});
// Observe multiple elements
const elements = document.querySelectorAll('.targets');
medusa.observe('myObserver', Array.from(elements));Management Methods
// Get observer instance
const observer = medusa.getObserver('myObserver');
// Clear specific observer
medusa.clearObserver('myObserver');
// Clear all observers
medusa.clearAllObservers();
// Remove specific observer
medusa.removeObserver('myObserver');
// Remove all observers
medusa.removeAllObservers();
// Unobserve elements
medusa.unobserve('myObserver', element);
// Destroy instance
medusa.destroy();Events
When emit: true is set, Medusa emits custom events on intersecting elements:
// Event name format: medusa-${observerId}
element.addEventListener('medusa-myObserver', (event: CustomEvent) => {
const entry: IntersectionObserverEntry = event.detail;
console.log('Intersection ratio:', entry.intersectionRatio);
});Event Details
The event.detail contains the IntersectionObserverEntry:
{
time: number;
rootBounds: DOMRectReadOnly;
boundingClientRect: DOMRectReadOnly;
intersectionRect: DOMRectReadOnly;
isIntersecting: boolean;
intersectionRatio: number;
target: Element;
}TypeScript Support
Medusa is written in TypeScript and includes full type definitions:
import type {
MedusaOptions,
MedusaObserverConfig,
MedusaCallback,
} from '@adoratorio/medusa';