@adoratorio/medusa
v4.0.0
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
const MODE = {
DEFAULT: 'DEFAULT', // Trigger on every intersection
ONCE: 'ONCE', // Trigger only once
BYPIXELS: 'BYPIXELS', // Trigger every 1% of intersection (101 thresholds)
} as const;
type Mode = (typeof MODE)[keyof typeof MODE];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 — accepts any Iterable<Element>,
// so NodeList / HTMLCollection / Set / arrays all work directly.
const elements = document.querySelectorAll('.targets');
medusa.observe('myObserver', 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:
import type { MedusaEvent } from '@adoratorio/medusa';
// Event name format: medusa-${observerId}
// `addEventListener` cannot infer the payload type from a dynamic event name,
// so cast to `MedusaEvent` for full type-safety on `event.detail`.
element.addEventListener('medusa-myObserver', (e) => {
const event = e as MedusaEvent;
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';