@triggery/dom
DOM-мосты для Triggery — направляй обратные вызовы addEventListener, ResizeObserver и IntersectionObserver в события триггеров. Все три хука цепляются в useEffect (commit-фаза, безопасны для StrictMode) и отцепляются при unmount.
Установка
Заголовок раздела «Установка»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-зависимости: react >= 18.0.0.
Что внутри
Заголовок раздела «Что внутри»| Экспорт | Назначение |
|---|---|
useDomEvent(trigger, eventName, target, domEventName, options?) | Пробрасывает DOM-событие из элемента, window/document или React-ref. |
useResizeObserver(trigger, eventName, ref, options?) | Пробрасывает записи ResizeObserver по ref’у элемента. |
useIntersectionObserver(trigger, eventName, ref, options?) | Пробрасывает записи IntersectionObserver по ref’у элемента. |
target может быть EventTarget (например, window), React-ref или null / undefined (no-op, пока не передан реальный target).
Быстрый пример
Заголовок раздела «Быстрый пример»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>;
}Как это работает
Заголовок раздела «Как это работает»Идентичность слушателя стабильна между рендерами, пока mapPayload / listenerOptions / target фактически не изменились, — поэтому React не пересоздаёт подписку на каждом рендере. Тип события в триггере определяет, что должен возвращать mapPayload. Если mapPayload опущен, исходное DOM-событие или запись observer’а пробрасывается как есть.
Связанные пакеты
Заголовок раздела «Связанные пакеты» @triggery/core Экспортирует Trigger.
@triggery/react Это React-хуки.
@triggery/socket Альтернативный источник событий: socket.io и нативный WebSocket.
@triggery/query Сочетай DOM-события с чтением кеша TanStack Query.