UNPKG

@vorthain/react-state

Version:

A minimal and reactive state management library for React, enabling automatic UI updates through direct, mutable state changes.

1,186 lines (1,182 loc) 65.7 kB
'use strict'; var React = require('react'); var jsxRuntime = require('react/jsx-runtime'); let currentComponent = null; const propertySubscriptions = new Map(); const liveComponents = new WeakSet(); const observableCache = new WeakMap(); let objectIdCounter = 1; const objectIds$1 = new WeakMap(); const computedDependencies = new Map(); const computedCache = new Map(); let isBatching = false; let batchedUpdates = new Set(); let vGripNotifier = null; let vGripBatchStartFn = null; let vGripBatchEndFn = null; let vGripGetCurrentTracker$1 = null; let vGripTrackDependency$1 = null; function registerVGripNotifier(notifier) { vGripNotifier = notifier; } function registerVGripBatchHandlers(startFn, endFn) { vGripBatchStartFn = startFn; vGripBatchEndFn = endFn; } function registerVGripTracking(getCurrentTracker, trackDependency) { vGripGetCurrentTracker$1 = getCurrentTracker; vGripTrackDependency$1 = trackDependency; } function getObjectId$1(obj) { if (!objectIds$1.has(obj)) { objectIds$1.set(obj, objectIdCounter++); } return objectIds$1.get(obj); } function getPropertyKey(target, prop) { return `${getObjectId$1(target)}:${String(prop)}`; } function isObservable(obj) { return obj && typeof obj === 'object' && obj.__vorthainReactive === true; } function vAction(actionFn) { if (isBatching) { return actionFn(); } isBatching = true; batchedUpdates.clear(); if (vGripBatchStartFn) { vGripBatchStartFn(); } try { const result = actionFn(); if (batchedUpdates.size > 0 || vGripBatchEndFn) { queueMicrotask(() => { batchedUpdates.forEach((updateFn) => { if (liveComponents.has(updateFn)) { try { updateFn(); } catch (e) { console.error('Error in batched update:', e); } } }); batchedUpdates.clear(); if (vGripBatchEndFn) { vGripBatchEndFn(); } }); } return result; } finally { isBatching = false; } } function makeObservable(target) { if (!target || typeof target !== 'object') return target; if (target.__vorthainReactive) return target; if (observableCache.has(target)) { return observableCache.get(target); } if (target instanceof Date || target instanceof RegExp || target instanceof HTMLElement || target instanceof File || target instanceof Blob || target instanceof FormData || target instanceof ArrayBuffer || ArrayBuffer.isView(target) || target instanceof NodeList || target instanceof HTMLCollection) { return target; } observableCache.set(target, target); if (Array.isArray(target)) { return makeArrayObservable(target); } else if (target instanceof Map) { return makeMapObservable(target); } else if (target instanceof Set) { return makeSetObservable(target); } else { return makeObjectObservable(target); } } function makeObjectObservable(target) { Object.defineProperty(target, '__vorthainReactive', { value: true, writable: false, enumerable: false, configurable: false }); const allProps = new Set([ ...Object.getOwnPropertyNames(target), ...Object.getOwnPropertySymbols(target) ]); allProps.forEach((prop) => { if (prop === '__vorthainReactive') return; const descriptor = Object.getOwnPropertyDescriptor(target, prop); if (!descriptor || !descriptor.configurable) return; if (descriptor.get || descriptor.set) { makeGetterSetterReactive(target, prop, descriptor); } else { if (descriptor.value && typeof descriptor.value === 'object') { descriptor.value = makeObservable(descriptor.value); } makePropertyReactive(target, prop, descriptor.value); } }); return target; } function makePropertyReactive(target, prop, initialValue) { let currentValue = initialValue; if (currentValue && typeof currentValue === 'object') { currentValue = makeObservable(currentValue); } Object.defineProperty(target, prop, { get() { const propKey = getPropertyKey(target, prop); if (currentComponent && !vGripGetCurrentTracker$1?.()) { let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } if (vGripGetCurrentTracker$1 && vGripTrackDependency$1) { const tracker = vGripGetCurrentTracker$1(); if (tracker && tracker.isRendering) { vGripTrackDependency$1(tracker, target, prop, currentValue); } } if (currentComputedContext) { trackComputedDependency(propKey); } return currentValue; }, set(newValue) { if (currentValue === newValue) return; if (newValue && typeof newValue === 'object') { newValue = makeObservable(newValue); } currentValue = newValue; invalidateComputedsThatDependOn(target, prop); const propKey = getPropertyKey(target, prop); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, prop); } }, enumerable: true, configurable: true }); } let currentComputedContext = null; function trackComputedDependency(propKey) { if (!currentComputedContext) return; const { target, prop } = currentComputedContext; if (!computedDependencies.has(target)) { computedDependencies.set(target, new Map()); } const targetDeps = computedDependencies.get(target); if (!targetDeps.has(prop)) { targetDeps.set(prop, new Set()); } targetDeps.get(prop).add(propKey); } function invalidateComputedsThatDependOn(obj, prop) { const propKey = getPropertyKey(obj, prop); computedCache.forEach((cache, target) => { cache.forEach((cacheEntry, computedProp) => { const deps = computedDependencies.get(target)?.get(computedProp); if (deps && deps.has(propKey)) { const oldValue = cacheEntry.value; cacheEntry.isValid = false; if (vGripNotifier) { const descriptor = Object.getOwnPropertyDescriptor(target, computedProp); if (descriptor && descriptor.get) { try { const newValue = descriptor.get.call(target); if (newValue !== oldValue) { vGripNotifier(target, computedProp); } } catch (e) { vGripNotifier(target, computedProp); } } } } }); }); } function makeGetterSetterReactive(target, prop, descriptor) { const originalGet = descriptor.get; const originalSet = descriptor.set; Object.defineProperty(target, prop, { get() { if (!originalGet) return undefined; if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, prop); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } if (!computedCache.has(target)) { computedCache.set(target, new Map()); } const cache = computedCache.get(target); if (!cache.has(prop)) { cache.set(prop, { value: undefined, isValid: false }); } const cacheEntry = cache.get(prop); const tracker = vGripGetCurrentTracker$1?.(); const shouldUseCache = cacheEntry.isValid && !currentComponent && !tracker; if (shouldUseCache) { return cacheEntry.value; } const prevComponent = currentComponent; const prevComputedContext = currentComputedContext; currentComputedContext = { target, prop }; const computedNotifier = () => { const propKey = getPropertyKey(target, prop); notifySubscribers(propKey); }; if (!tracker) { currentComponent = computedNotifier; } try { const result = originalGet.call(target); cacheEntry.value = result; cacheEntry.isValid = true; if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, prop, result); } return result; } finally { if (!tracker) { currentComponent = prevComponent; } currentComputedContext = prevComputedContext; } }, set(newValue) { if (!originalSet) return; if (newValue && typeof newValue === 'object') { newValue = makeObservable(newValue); } originalSet.call(target, newValue); const cache = computedCache.get(target); if (cache && cache.has(prop)) { cache.get(prop).isValid = false; } const propKey = getPropertyKey(target, prop); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, prop); } }, enumerable: descriptor.enumerable, configurable: true }); } const ARRAY_METHODS = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'fill', 'copyWithin' ]; function makeArrayObservable(target) { Object.defineProperty(target, '__vorthainReactive', { value: true, writable: false, enumerable: false, configurable: false }); for (let i = 0; i < target.length; i++) { if (target[i] && typeof target[i] === 'object' && !isObservable(target[i])) { target[i] = makeObservable(target[i]); } } const originalMethods = {}; ARRAY_METHODS.forEach((method) => { const fn = target[method]; if (typeof fn === 'function') { originalMethods[method] = fn.bind(target); } }); const arrayProxy = new Proxy(target, { get(target, prop, receiver) { if (typeof prop === 'string' && ARRAY_METHODS.includes(prop)) { return function (...args) { const oldLength = target.length; const oldItems = [...target]; let processedArgs = args; if (prop === 'push' || prop === 'unshift') { processedArgs = args.map((item) => item && typeof item === 'object' ? makeObservable(item) : item); } else if (prop === 'splice' && args.length > 2) { processedArgs = [...args]; for (let i = 2; i < processedArgs.length; i++) { if (processedArgs[i] && typeof processedArgs[i] === 'object') { processedArgs[i] = makeObservable(processedArgs[i]); } } } const result = originalMethods[prop].apply(target, processedArgs); for (let i = 0; i < target.length; i++) { if (target[i] && typeof target[i] === 'object' && !isObservable(target[i])) { target[i] = makeObservable(target[i]); } } const lengthChanged = target.length !== oldLength; const itemsChanged = !oldItems.every((item, i) => target[i] === item); if (lengthChanged) { const lengthKey = getPropertyKey(target, 'length'); notifySubscribers(lengthKey); } if (vGripNotifier) { if (lengthChanged) { vGripNotifier(target, 'length'); } if (itemsChanged || ['sort', 'reverse'].includes(prop)) { const maxLength = Math.max(target.length, oldLength); for (let i = 0; i < maxLength; i++) { if (i >= target.length || i >= oldItems.length || target[i] !== oldItems[i]) { vGripNotifier(target, i.toString()); } } } } return result; }; } if (typeof prop === 'string' && !isNaN(Number(prop))) { const index = Number(prop); let item = target[index]; if (item && typeof item === 'object' && !isObservable(item)) { item = makeObservable(item); target[index] = item; } if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, prop); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, prop, item); } return item; } if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, prop); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { const value = Reflect.get(target, prop, receiver); vGripTrackDependency$1(tracker, target, prop, value); return value; } return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { if (prop === 'length') { const oldLength = target.length; const newLength = Number(value); if (newLength < oldLength) { for (let i = newLength; i < oldLength; i++) { delete target[i]; } } target.length = newLength; const propKey = getPropertyKey(target, 'length'); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, 'length'); for (let i = newLength; i < oldLength; i++) { vGripNotifier(target, i.toString()); } } return true; } if (value && typeof value === 'object' && !isObservable(value)) { value = makeObservable(value); } const oldValue = target[prop]; const result = Reflect.set(target, prop, value, receiver); if (oldValue !== value) { const propKey = getPropertyKey(target, prop); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, prop); } } return result; }, deleteProperty(target, prop) { const result = Reflect.deleteProperty(target, prop); if (result) { const propKey = getPropertyKey(target, prop); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, prop); } } return result; } }); return arrayProxy; } function makeMapObservable(target) { Object.defineProperty(target, '__vorthainReactive', { value: true, writable: false, enumerable: false, configurable: false }); for (const [key, value] of target) { if (value && typeof value === 'object' && !isObservable(value)) { target.set(key, makeObservable(value)); } } const originalGet = target.get.bind(target); const originalSet = target.set.bind(target); const originalDelete = target.delete.bind(target); const originalClear = target.clear.bind(target); const originalForEach = target.forEach.bind(target); const originalEntries = target.entries.bind(target); const originalValues = target.values.bind(target); const originalKeys = target.keys.bind(target); const mapProxy = new Proxy(target, { get(target, prop, receiver) { if (prop === 'size') { const size = target.size; if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, 'size'); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, 'size', size); } return size; } if (prop === 'get') { return function (key) { const value = originalGet(key); if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, key); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, key, value); } if (value && typeof value === 'object' && !isObservable(value)) { const reactiveValue = makeObservable(value); originalSet(key, reactiveValue); return reactiveValue; } return value; }; } if (prop === 'set') { return function (key, value) { if (value && typeof value === 'object') { value = makeObservable(value); } const oldValue = originalGet(key); const oldSize = target.size; const result = originalSet(key, value); if (oldValue !== value) { const propKey = getPropertyKey(target, key); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, key); } } if (oldSize !== target.size) { const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); if (vGripNotifier) { vGripNotifier(target, 'size'); } } const iterKey = getPropertyKey(target, Symbol.for('__map_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, Symbol.for('__map_iteration__')); } return result; }; } if (prop === 'delete') { return function (key) { const oldSize = target.size; const result = originalDelete(key); if (result) { const propKey = getPropertyKey(target, key); notifySubscribers(propKey); const iterKey = getPropertyKey(target, Symbol.for('__map_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, key); vGripNotifier(target, Symbol.for('__map_iteration__')); } if (oldSize !== target.size) { const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); if (vGripNotifier) { vGripNotifier(target, 'size'); } } } return result; }; } if (prop === 'clear') { return function () { const oldSize = target.size; const oldKeys = Array.from(target.keys()); const result = originalClear(); if (oldSize > 0) { oldKeys.forEach((key) => { const propKey = getPropertyKey(target, key); notifySubscribers(propKey); if (vGripNotifier) { vGripNotifier(target, key); } }); const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); const iterKey = getPropertyKey(target, Symbol.for('__map_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, 'size'); vGripNotifier(target, Symbol.for('__map_iteration__')); } } return result; }; } if (prop === 'forEach') { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__map_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__map_iteration__'), null); } return function (callback, thisArg) { return originalForEach((value, key, map) => { if (value && typeof value === 'object' && !isObservable(value)) { value = makeObservable(value); originalSet(key, value); } callback.call(thisArg, value, key, map); }); }; } if (prop === 'keys') { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__map_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__map_iteration__'), null); } return function* () { for (const key of originalKeys()) { yield key; } }; } if (prop === 'entries' || prop === Symbol.iterator) { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__map_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__map_iteration__'), null); } return function* () { for (const [key, value] of originalEntries()) { let reactiveValue = value; if (value && typeof value === 'object' && !isObservable(value)) { reactiveValue = makeObservable(value); originalSet(key, reactiveValue); } yield [key, reactiveValue]; } }; } if (prop === 'values') { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__map_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__map_iteration__'), null); } return function* () { for (const value of originalValues()) { if (value && typeof value === 'object' && !isObservable(value)) { const key = Array.from(originalEntries()).find(([k, v]) => v === value)?.[0]; if (key !== undefined) { const reactiveValue = makeObservable(value); originalSet(key, reactiveValue); yield reactiveValue; } else { yield value; } } else { yield value; } } }; } return Reflect.get(target, prop, target); } }); return mapProxy; } function makeSetObservable(target) { Object.defineProperty(target, '__vorthainReactive', { value: true, writable: false, enumerable: false, configurable: false }); const existingValues = Array.from(target); target.clear(); existingValues.forEach((value) => { if (value && typeof value === 'object' && !isObservable(value)) { target.add(makeObservable(value)); } else { target.add(value); } }); const originalAdd = target.add.bind(target); const originalDelete = target.delete.bind(target); const originalClear = target.clear.bind(target); const originalForEach = target.forEach.bind(target); const originalValues = target.values.bind(target); const originalEntries = target.entries.bind(target); const originalHas = target.has.bind(target); // Bind the 'has' method const setProxy = new Proxy(target, { get(target, prop, receiver) { if (prop === 'size') { const size = target.size; if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, 'size'); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, 'size', size); } return size; } if (prop === 'has') { return function (value) { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const iterKey = getPropertyKey(target, Symbol.for('__set_iteration__')); let subscribers = propertySubscriptions.get(iterKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(iterKey, subscribers); } subscribers.add(currentComponent); } return originalHas(value); }; } if (prop === 'add') { return function (value) { if (value && typeof value === 'object') { value = makeObservable(value); } const oldSize = target.size; const result = originalAdd(value); if (oldSize !== target.size) { const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); const iterKey = getPropertyKey(target, Symbol.for('__set_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, 'size'); vGripNotifier(target, Symbol.for('__set_iteration__')); } } return result; }; } if (prop === 'delete') { return function (value) { target.size; const result = originalDelete(value); if (result) { const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); const iterKey = getPropertyKey(target, Symbol.for('__set_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, 'size'); vGripNotifier(target, Symbol.for('__set_iteration__')); } } return result; }; } if (prop === 'clear') { return function () { const oldSize = target.size; const result = originalClear(); if (oldSize > 0) { const sizeKey = getPropertyKey(target, 'size'); notifySubscribers(sizeKey); const iterKey = getPropertyKey(target, Symbol.for('__set_iteration__')); notifySubscribers(iterKey); if (vGripNotifier) { vGripNotifier(target, 'size'); vGripNotifier(target, Symbol.for('__set_iteration__')); } } return result; }; } if (prop === 'forEach') { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__set_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__set_iteration__'), null); } return function (callback, thisArg) { return originalForEach((value, set) => { if (value && typeof value === 'object' && !isObservable(value)) { value = makeObservable(value); } callback.call(thisArg, value, value, set); }); }; } if (prop === 'values' || prop === 'keys' || prop === Symbol.iterator) { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__set_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__set_iteration__'), null); } return function* () { for (const value of originalValues()) { if (value && typeof value === 'object' && !isObservable(value)) { yield makeObservable(value); } else { yield value; } } }; } if (prop === 'entries') { if (currentComponent && !vGripGetCurrentTracker$1?.()) { const propKey = getPropertyKey(target, Symbol.for('__set_iteration__')); let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(currentComponent); } const tracker = vGripGetCurrentTracker$1?.(); if (tracker && tracker.isRendering && vGripTrackDependency$1) { vGripTrackDependency$1(tracker, target, Symbol.for('__set_iteration__'), null); } return function* () { for (const [value1, value2] of originalEntries()) { let reactiveValue = value1; if (value1 && typeof value1 === 'object' && !isObservable(value1)) { reactiveValue = makeObservable(value1); } yield [reactiveValue, reactiveValue]; } }; } return Reflect.get(target, prop, target); } }); return setProxy; } function notifySubscribers(propKey) { const subscribers = propertySubscriptions.get(propKey); if (!subscribers || subscribers.size === 0) return; const subscriberArray = Array.from(subscribers); subscriberArray.forEach((subscriber) => { if (liveComponents.has(subscriber)) { if (isBatching) { batchedUpdates.add(subscriber); } else { queueMicrotask(() => { if (liveComponents.has(subscriber)) { try { subscriber(); } catch (e) { console.error('Error in subscriber update:', e); liveComponents.delete(subscriber); subscribers.delete(subscriber); } } }); } } else { subscribers.delete(subscriber); } }); if (subscribers.size === 0) { propertySubscriptions.delete(propKey); } } function useObservableSubscription(observableState) { const [, forceUpdate] = React.useReducer((x) => x + 1, 0); const instanceRef = React.useRef(null); if (!instanceRef.current) { instanceRef.current = { subscriptions: new Set(), forceUpdate, isCleanedUp: false }; } instanceRef.current.forceUpdate = forceUpdate; liveComponents.add(forceUpdate); React.useEffect(() => { const instance = instanceRef.current; liveComponents.add(instance.forceUpdate); currentComponent = instance.forceUpdate; try { subscribeToObject(observableState); } catch (e) { console.warn('Error subscribing to observable:', e); } finally { currentComponent = null; } instance.subscriptions.forEach((propKey) => { let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.forEach((sub) => { if (!liveComponents.has(sub) && sub !== instance.forceUpdate) { subscribers.delete(sub); } }); subscribers.add(instance.forceUpdate); }); instance.isCleanedUp = false; return () => { instance.isCleanedUp = true; queueMicrotask(() => { if (instance.isCleanedUp) { liveComponents.delete(instance.forceUpdate); instance.subscriptions.forEach((propKey) => { const subscribers = propertySubscriptions.get(propKey); if (subscribers) { subscribers.delete(instance.forceUpdate); if (subscribers.size === 0) { propertySubscriptions.delete(propKey); } } }); } }); }; }, [observableState]); return new Proxy(observableState, { get(target, prop, receiver) { const instance = instanceRef.current; // Helper function to wrap Map.get return values const wrapMapGetResult = (originalGet, target) => { return function (key) { const result = originalGet.call(target, key); if (result && typeof result === 'object') { const proxyKey = Symbol.for('__vorthain_proxy__'); if (result[proxyKey]) { return result; } const proxy = new Proxy(result, { get(innerTarget, innerProp, innerReceiver) { if (innerProp === proxyKey) return true; // Recursive handling for nested Maps if (typeof innerTarget[innerProp] === 'function') { if (innerTarget instanceof Map && innerProp === 'get') { return wrapMapGetResult(Reflect.get(innerTarget, innerProp, innerReceiver), innerTarget); } return Reflect.get(innerTarget, innerProp, innerReceiver); } currentComponent = instance.forceUpdate; liveComponents.add(instance.forceUpdate); const innerPropKey = getPropertyKey(innerTarget, innerProp); if (!instance.subscriptions.has(innerPropKey)) { instance.subscriptions.add(innerPropKey); } let innerSubscribers = propertySubscriptions.get(innerPropKey); if (!innerSubscribers) { innerSubscribers = new Set(); propertySubscriptions.set(innerPropKey, innerSubscribers); } innerSubscribers.add(instance.forceUpdate); const value = Reflect.get(innerTarget, innerProp, innerReceiver); // Handle nested objects/Maps/Sets if (value && typeof value === 'object') { return new Proxy(value, this); } return value; } }); return proxy; } return result; }; }; // Handle functions if (typeof target[prop] === 'function') { if (target instanceof Map && prop === 'get') { return wrapMapGetResult(Reflect.get(target, prop, receiver), target); } return Reflect.get(target, prop, receiver); } // Regular property access const propKey = getPropertyKey(target, prop); if (!instance.subscriptions.has(propKey)) { instance.subscriptions.add(propKey); } let subscribers = propertySubscriptions.get(propKey); if (!subscribers) { subscribers = new Set(); propertySubscriptions.set(propKey, subscribers); } subscribers.add(instance.forceUpdate); const prevComponent = currentComponent; if (!vGripGetCurrentTracker$1?.()) { currentComponent = instance.forceUpdate; } try { const value = Reflect.get(target, prop, receiver); if (value && typeof value === 'object' && !vGripGetCurrentTracker$1?.()) { const proxyKey = Symbol.for('__vorthain_proxy__'); if (value[proxyKey]) { return value; } const proxy = new Proxy(value, { get(innerTarget, innerProp, innerReceiver) { if (innerProp === proxyKey) return true; if (typeof innerTarget[innerProp] === 'function') { if (innerTarget instanceof Map && innerProp === 'get') { return wrapMapGetResult(Reflect.get(innerTarget, innerProp, innerReceiver), innerTarget); } return Reflect.get(innerTarget, innerProp, innerReceiver); } currentComponent = instance.forceUpdate; liveComponents.add(instance.forceUpdate); const innerPropKey = getPropertyKey(innerTarget, innerProp); if (!instance.subscriptions.has(innerPropKey)) { instance.subscriptions.add(innerPropKey); } let innerSubscribers = propertySubscriptions.get(innerPropKey); if (!innerSubscribers) { innerSubscribers = new Set(); propertySubscriptions.set(innerPropKey, innerSubscribers); } innerSubscribers.add(instance.forceUpdate); return Reflect.get(innerTarget, innerProp, innerReceiver); } }); return proxy; } return value; } finally { currentComponent = prevComponent; } } }); } function subscribeToObject(obj, visited = new WeakSet()) { if (!obj || typeof obj !== 'object' || visited.has(obj)) return; visited.add(obj); try { if (Array.isArray(obj)) { obj.length; for (let i = 0; i < obj.length; i++) { const item = obj[i]; } } else if (obj instanceof Map) { obj.size; } else if (obj instanceof Set) { obj.size; } else { Object.keys(obj).forEach((key) => { try { const descriptor = Object.getOwnPropertyDescriptor(obj, key); if (descriptor && descriptor.get) { return; } if (typeof obj[key] === 'function') { return; } obj[key]; } catch (e) { } }); } } catch (e) { } } const vGripTrackers = new Map(); const objectToTrackers = new Map(); let currentRenderingTracker = null; let insideVActionBatch = false; const vActionBatchedTrackers = new Set(); const pendingTrackerUpdates = new Set(); let updateFlushScheduled = false; let nextTrackerId = 0; let nextObjectId = 0; const objectIds = new WeakMap(); function getCurrentRenderingTracker() { return currentRenderingTracker; } function vGripGetCurrentTracker() { return currentRenderingTracker; } function getObjectId(obj) { if (!objectIds.has(obj)) { objectIds.set(obj, `obj_${++nextObjectId}`); } return objectIds.get(obj); } function createDependencyKey(obj, prop) { return `${getObjectId(obj)}::${String(prop)}`; } function vGripTrackDependency(tracker, obj, prop, value, path = '') { if (tracker !== currentRenderingTracker || !tracker.isRendering) { return; } if (typeof value === 'function') { return; } const key = createDependencyKey(obj, prop); tracker.dependencies.set(key, { object: obj, property: prop, value: value, path: path || `${getObjectId(obj)}.${String(prop)}` }); if (!objectToTrackers.has(obj)) { objectToTrackers.set(obj, new Map()); } const objTrackers = objectToTrackers.get(obj); const propKey = String(prop); if (!objTrackers.has(propKey)) {