UNPKG

fluidstate

Version:

Library for fine-grained reactivity state management

272 lines (271 loc) 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createReactiveMap = void 0; var _reactiveNames = require("../extras/reactive-names"); var _reactivePlugin = require("../extras/reactive-plugin"); var _reactivePluginMap = require("../extras/reactive-plugin-map"); var _reactiveAction = require("../primitives/reactive-action"); var _reactiveAtom = require("../primitives/reactive-atom"); var _reactiveLayer = require("../primitives/reactive-layer"); var _reactiveOptions = require("../primitives/reactive-options"); var _reactiveTracking = require("../primitives/reactive-tracking"); var _reactiveChildren = require("./reactive-children"); var _reactiveProxy = require("./reactive-proxy"); const createReactiveMap = (inertMap, reactiveOptions, nameOptions) => { const atomName = (0, _reactiveNames.createAtomNameFromOptions)(nameOptions); const proxy = new Proxy(inertMap, new ReactiveMapProxyHandler(new ReactiveMapOverrides(atomName, inertMap, { items: new Map(), size: (0, _reactiveAtom.createAtom)((0, _reactiveNames.createMapSizeAtomName)(atomName)) }, () => proxy, reactiveOptions))); return proxy; }; exports.createReactiveMap = createReactiveMap; class ReactiveMapProxyHandler { constructor(mapOverrides) { this.mapOverrides = mapOverrides; } get(inertMap, property, receiver) { const ownPropertyDescriptor = Reflect.getOwnPropertyDescriptor(inertMap, property); const isInherited = Reflect.has(inertMap, property) && !ownPropertyDescriptor; if (isInherited && property in this.mapOverrides) { return this.mapOverrides[property]; } return Reflect.get(inertMap, property, receiver); } } class ReactiveMapOverrides { #atomName; #inertMap; #reactive; #getProxy; #options; constructor(atomName, inertMap, reactive, getProxy, reactiveOptions) { this.#atomName = atomName; this.#inertMap = inertMap; this.#reactive = reactive; this.#getProxy = getProxy; this.#options = { reactiveOptions }; } [Symbol.iterator] = () => { return this.#getMapEntries(); }; entries = () => { return this.#getMapEntries(); }; keys = () => { return this.#keys(); }; values = () => { return this.#values(); }; get [Symbol.toStringTag]() { return Map.prototype[Symbol.toStringTag]; } get size() { this.#reactive.size.reportObserved(); return this.#inertMap.size; } has = key => { const storedKey = this.#getStored(key); const result = this.#hasStoredKey(storedKey); this.#readItem(storedKey); return result; }; get = key => { const storedKey = this.#getStored(key); const result = this.#getStoredValueByKey(storedKey); this.#readItem(storedKey); return (0, _reactiveChildren.getChild)(this.#options, result, () => (0, _reactiveProxy.createProxy)(result, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapValueAtomName, childIndex: this.#getChildIndex(storedKey) })); }; set = (key, value) => { const storedKey = this.#getStored(key); const storedValue = this.#getStored(value); const itemAlreadyExists = this.#hasStoredKey(storedKey); const currentStoredValue = this.#getStoredValueByKey(storedKey); const isValueChanged = !(0, _reactiveOptions.reactiveValueEquals)(currentStoredValue, storedValue); const changes = !this.#hasPlugins() || itemAlreadyExists && !isValueChanged ? null : (0, _reactivePluginMap.getMapSetChanges)(this.#getProxy(), storedKey, !itemAlreadyExists, currentStoredValue, storedValue); if (changes) { (0, _reactivePlugin.beforeChange)(changes, this.#options.reactiveOptions?.plugins); } Map.prototype.set.call(this.#inertMap, storedKey, storedValue); (0, _reactiveAction.runTransaction)(() => { if (!itemAlreadyExists || isValueChanged) { this.#notifyItem(storedKey); } if (!itemAlreadyExists) { this.#reactive.size.reportChanged(); } }); if (changes) { (0, _reactivePlugin.afterChange)(changes, this.#options.reactiveOptions?.plugins); } return this; }; delete = key => { const storedKey = this.#getStored(key); const itemAlreadyExists = this.#hasStoredKey(storedKey); const changes = !this.#hasPlugins() || !itemAlreadyExists ? null : (0, _reactivePluginMap.getMapDeleteChanges)(this.#getProxy(), storedKey, this.#getStoredValueByKey(storedKey)); if (changes) { (0, _reactivePlugin.beforeChange)(changes, this.#options.reactiveOptions?.plugins); } const resultStored = Map.prototype.delete.call(this.#inertMap, storedKey); const reactive = (0, _reactiveProxy.getReactive)(storedKey); const resultReactive = !!(reactive && Map.prototype.delete.call(this.#inertMap, reactive)); const result = resultStored || resultReactive; if (result) { (0, _reactiveAction.runTransaction)(() => { this.#notifyItem(storedKey); this.#reactive.size.reportChanged(); }); } if (changes) { (0, _reactivePlugin.afterChange)(changes, this.#options.reactiveOptions?.plugins); } return result; }; clear = () => { const isAlreadyEmpty = this.#inertMap.size === 0; const changes = !this.#hasPlugins() || isAlreadyEmpty ? null : (0, _reactivePluginMap.getMapClearChanges)(this.#getProxy(), Array.from(this.#inertMap.entries())); if (changes) { (0, _reactivePlugin.beforeChange)(changes, this.#options.reactiveOptions?.plugins); } (0, _reactiveAction.runTransaction)(() => { Map.prototype.forEach.call(this.#inertMap, (_value, key) => { Map.prototype.delete.call(this.#inertMap, key); this.#notifyItem(key); }); if (!isAlreadyEmpty) { this.#reactive.size.reportChanged(); } }); if (changes) { (0, _reactivePlugin.afterChange)(changes, this.#options.reactiveOptions?.plugins); } }; forEach = (callbackfn, thisArg) => { this.#reactive.size.reportObserved(); const result = Map.prototype.forEach.call(this.#inertMap, (value, key, map) => { this.#readItem(key); const childIndex = this.#getChildIndex(key); return callbackfn.call(this, (0, _reactiveChildren.getChild)(this.#options, value, () => (0, _reactiveProxy.createProxy)(value, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapValueAtomName, childIndex })), (0, _reactiveChildren.getChild)(this.#options, key, () => (0, _reactiveProxy.createProxy)(key, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapKeyAtomName, childIndex })), map); }, thisArg); return result; }; *#keys() { const result = Map.prototype.entries.call(this.#inertMap); this.#reactive.size.reportObserved(); for (const [key] of result) { this.#readItem(key); yield (0, _reactiveChildren.getChild)(this.#options, key, () => (0, _reactiveProxy.createProxy)(key, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapKeyAtomName, childIndex: this.#getChildIndex(key) })); } } *#values() { const result = Map.prototype.entries.call(this.#inertMap); this.#reactive.size.reportObserved(); for (const [key, value] of result) { this.#readItem(key); yield (0, _reactiveChildren.getChild)(this.#options, value, () => (0, _reactiveProxy.createProxy)(value, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapValueAtomName, childIndex: this.#getChildIndex(key) })); } } #getStored(value) { return this.#options.reactiveOptions?.deep === false ? value : (0, _reactiveProxy.ensureInert)(value); } #getStoredValueByKey(storedKey) { const hasStoredValueDirectly = Map.prototype.has.call(this.#inertMap, storedKey); if (hasStoredValueDirectly || this.#options.reactiveOptions?.deep === false) { return Map.prototype.get.call(this.#inertMap, storedKey); } const reactiveKey = (0, _reactiveProxy.getReactive)(storedKey); return reactiveKey ? Map.prototype.get.call(this.#inertMap, reactiveKey) : undefined; } #hasStoredKey(storedKey) { const hasStoredValueDirectly = Map.prototype.has.call(this.#inertMap, storedKey); if (hasStoredValueDirectly || this.#options.reactiveOptions?.deep === false) { return hasStoredValueDirectly; } const reactiveKey = (0, _reactiveProxy.getReactive)(storedKey); return reactiveKey && Map.prototype.has.call(this.#inertMap, reactiveKey) || false; } #cleanupItem(key) { this.#reactive.items.delete(key); } #notifyItem(key) { const atom = this.#reactive.items.get(key); if (atom) { atom.reportChanged(); } } #getChildIndex(key) { switch (typeof key) { case "string": case "number": case "bigint": case "boolean": case "symbol": case "undefined": return String(key); default: return undefined; } } #readItem(key) { let atom = this.#reactive.items.get(key); if (!atom) { if (!(0, _reactiveTracking.isTracking)()) { return; } atom = (0, _reactiveLayer.getReactiveLayer)().createAtom((0, _reactiveNames.createMapItemAtomName)(this.#atomName, this.#getChildIndex(key)), { onBecomeUnobservedListener: () => { this.#cleanupItem(key); } }); this.#reactive.items.set(key, atom); } atom.reportObserved(); } *#getMapEntries() { const result = Map.prototype.entries.call(this.#inertMap); this.#reactive.size.reportObserved(); for (const [key, value] of result) { this.#readItem(key); const childIndex = this.#getChildIndex(key); yield [(0, _reactiveChildren.getChild)(this.#options, key, () => (0, _reactiveProxy.createProxy)(key, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapKeyAtomName, childIndex })), (0, _reactiveChildren.getChild)(this.#options, value, () => (0, _reactiveProxy.createProxy)(value, (0, _reactiveChildren.getChildOptions)(this.#options), { parentAtomName: this.#atomName, createAtomName: _reactiveNames.createMapValueAtomName, childIndex }))]; } } #hasPlugins() { return (this.#options.reactiveOptions?.plugins?.length ?? 0) > 0; } } //# sourceMappingURL=reactive-map.js.map