import { constant } from './util' export type ObserverCallbackState = { mutations: MutationRecord[]; observer: MutationObserver; target: T; } export type ObserverCallback = (state: ObserverCallbackState) => unknown; interface Observe { (target: T, init: MutationObserverInit, callback: ObserverCallback): MutationObserver; (target: T, callback: ObserverCallback): MutationObserver; (init: MutationObserverInit, callback: ObserverCallback): MutationObserver; (callback: ObserverCallback): MutationObserver; } type ObserveArgs = | [Element, MutationObserverInit, ObserverCallback] | [Element, ObserverCallback] | [MutationObserverInit, ObserverCallback] | [ObserverCallback] const INIT: MutationObserverInit = { childList: true, subtree: true } export const done = constant(false) export const resume = constant(true) // a Mutation Observer wrapper without the boilerplate export const observe = ((...args: ObserveArgs) => { const [target, init, callback] = args.length === 3 ? args : args.length === 2 ? ( args[0] instanceof Element ? [args[0], INIT, args[1]] : [document.body, args[0], args[1]] ) : [document.body, INIT, args[0]] const onMutate: MutationCallback = (mutations, observer) => { observer.disconnect() const resume = callback({ mutations, observer, target }) if (resume !== false) { observer.observe(target, init) } } const observer = new MutationObserver(onMutate) queueMicrotask(() => onMutate([], observer)) return observer })