/** * Hoover — reactivity.js * * Reactive Proxy state + batched render requests via queueMicrotask. * Multiple property mutations in the same microtask tick produce a single * render cycle across all registered render roots. */ /** * Global flag to prevent duplicate microtask scheduling. */ let _scheduled = false; /** * Callback invoked by render.js to perform the actual batched re-render. * Set via setCommitFn() during render engine initialization. */ let _commitFn = null; /** * Register the commit callback that performs batched re-renders. * Called by render.js during initialization. */ export function setCommitFn(fn) { _commitFn = fn; } /** * Schedule a single batched re-render for all active render roots. * Multiple reactive property mutations in the same tick produce one diff pass. */ export function requestUpdate() { if (_scheduled) return; _scheduled = true; queueMicrotask(() => { _scheduled = false; if (_commitFn) _commitFn(); }); } /** * Wrap an object in a reactive Proxy. * Any property *assignment* that changes the value automatically triggers * a batched re-render via requestUpdate(). */ export function reactive(obj = {}) { return new Proxy(obj, { set(target, key, value, receiver) { const old = target[key]; const ok = Reflect.set(target, key, value, receiver); if (ok && !Object.is(old, value)) { requestUpdate(); } return ok; } }); }