@triggery/dom
DOM bridges for Triggery — pipe addEventListener, ResizeObserver, and IntersectionObserver callbacks into trigger events. All three hooks attach in useEffect (commit phase, StrictMode-safe) and detach on unmount.
Install
Section titled “Install”pnpm add @triggery/core @triggery/react @triggery/dom npm install @triggery/core @triggery/react @triggery/dom yarn add @triggery/core @triggery/react @triggery/dom bun add @triggery/core @triggery/react @triggery/dom Peer deps: react >= 18.0.0.
What’s inside
Section titled “What’s inside”| Export | Purpose |
|---|---|
useDomEvent(trigger, eventName, target, domEventName, options?) | Forward a DOM event from an element, window/document, or React ref. |
useResizeObserver(trigger, eventName, ref, options?) | Forward ResizeObserver entries from an element ref. |
useIntersectionObserver(trigger, eventName, ref, options?) | Forward IntersectionObserver entries from an element ref. |
target may be an EventTarget (e.g. window), a React ref, or null / undefined (no-op until you provide one).
Quick example
Section titled “Quick example”import { useRef } from 'react';
import {
useDomEvent,
useResizeObserver,
useIntersectionObserver,
} from '@triggery/dom';
function Input() {
const ref = useRef<HTMLInputElement>(null);
useDomEvent(chatTrigger, 'submit', ref, 'keydown', {
mapPayload: (e) => ({ key: (e as KeyboardEvent).key }),
listenerOptions: { passive: true },
});
return <input ref={ref} />;
}
function GlobalEscapeWatcher() {
useDomEvent(uiTrigger, 'escape', window, 'keydown', {
mapPayload: (e) => (e as KeyboardEvent).key,
});
return null;
}
function Panel() {
const ref = useRef<HTMLDivElement>(null);
useResizeObserver(layoutTrigger, 'panel-resized', ref, {
mapPayload: (e) => ({
width: e.contentRect.width,
height: e.contentRect.height,
}),
});
return <div ref={ref}>...</div>;
}
function VirtualRow() {
const ref = useRef<HTMLLIElement>(null);
useIntersectionObserver(virtualTrigger, 'row-visible', ref, {
rootMargin: '200px',
mapPayload: (e) => ({ visible: e.isIntersecting, ratio: e.intersectionRatio }),
});
return <li ref={ref}>...</li>;
}How it works
Section titled “How it works”Listener identity is stable across renders unless mapPayload / listenerOptions / target actually change, so React doesn’t tear down on every render. The trigger’s event payload type defines what mapPayload should produce. If mapPayload is omitted, the raw DOM event or observer entry is forwarded unchanged.
Related packages
Section titled “Related packages” @triggery/core Exposes Trigger.
@triggery/react These are React hooks.
@triggery/socket Alternative event source: socket.io and native WebSocket.
@triggery/query Pair DOM events with TanStack Query cache reads.