fluidstate
Version:
Library for fine-grained reactivity state management
195 lines (194 loc) • 7.54 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createReactiveObject = void 0;
var _reactiveNames = require("../extras/reactive-names");
var _reactivePlugin = require("../extras/reactive-plugin");
var _reactivePluginObject = require("../extras/reactive-plugin-object");
var _reactiveAction = require("../primitives/reactive-action");
var _reactiveAtom = require("../primitives/reactive-atom");
var _reactiveComputed = require("../primitives/reactive-computed");
var _reactiveOptions = require("../primitives/reactive-options");
var _reactiveTracking = require("../primitives/reactive-tracking");
var _reactiveChildren = require("./reactive-children");
var _reactiveProxy = require("./reactive-proxy");
var _reactiveUtils = require("./reactive-utils");
var ValueType;
(function (ValueType) {
ValueType[ValueType["atom"] = 0] = "atom";
ValueType[ValueType["computed"] = 1] = "computed";
})(ValueType || (ValueType = {}));
const createReactiveObject = (inertObject, reactiveOptions, nameOptions) => {
const atomName = (0, _reactiveNames.createAtomNameFromOptions)(nameOptions);
const proxy = new Proxy(inertObject, new ReactiveObjectProxyHandler(atomName, {
values: {},
keys: (0, _reactiveAtom.createAtom)((0, _reactiveNames.createObjectKeysAtomName)(atomName))
}, () => proxy, reactiveOptions));
return proxy;
};
exports.createReactiveObject = createReactiveObject;
class ReactiveObjectProxyHandler {
#atomName;
#reactive;
#getProxy;
#options;
constructor(atomName, reactive, getProxy, reactiveOptions) {
this.#atomName = atomName;
this.#reactive = reactive;
this.#getProxy = getProxy;
this.#options = {
reactiveOptions
};
}
get(inertObject, p, receiver) {
const isReactive = this.#isReactiveProperty(p);
if (!isReactive) {
return (0, _reactiveTracking.untrack)(() => {
return Reflect.get(inertObject, p, receiver);
});
}
const {
descriptor
} = (0, _reactiveUtils.getDescriptor)(inertObject, p);
if (descriptor?.get) {
const result = this.#readComputedValue(p, descriptor.get);
return (0, _reactiveChildren.getChild)(this.#options, result, () => (0, _reactiveProxy.createProxy)(result, (0, _reactiveChildren.getChildOptions)(this.#options), {
parentAtomName: this.#atomName,
createAtomName: _reactiveNames.createObjectComputedValueAtomName,
childIndex: p.toString()
}));
}
this.#readAtomValue(p);
const result = Reflect.get(inertObject, p, receiver);
if (typeof result === "function") {
return (0, _reactiveAction.createAction)(result);
}
return (0, _reactiveChildren.getChild)(this.#options, result, () => (0, _reactiveProxy.createProxy)(result, (0, _reactiveChildren.getChildOptions)(this.#options), {
parentAtomName: this.#atomName,
createAtomName: _reactiveNames.createObjectValueAtomName,
childIndex: p.toString()
}));
}
set(inertObject, p, newValue, receiver) {
const isReactive = this.#isReactiveProperty(p);
const newStoredValue = !isReactive || this.#options.reactiveOptions?.deep === false ? newValue : (0, _reactiveProxy.ensureInert)(newValue);
const {
descriptor
} = (0, _reactiveUtils.getDescriptor)(inertObject, p);
if (descriptor?.get || descriptor?.set) {
return (0, _reactiveAction.runAction)(() => {
return Reflect.set(inertObject, p, newStoredValue, receiver);
});
}
const hasProperty = inertObject.hasOwnProperty(p);
const currentValue = Reflect.get(inertObject, p, receiver);
const isChanged = !(0, _reactiveOptions.reactiveValueEquals)(currentValue, newStoredValue);
const changes = !this.#hasPlugins() || !isChanged ? null : (0, _reactivePluginObject.getObjectSetChanges)(this.#getProxy(), p, currentValue, newStoredValue);
if (changes) {
(0, _reactivePlugin.beforeChange)(changes, this.#options.reactiveOptions?.plugins);
}
const result = Reflect.set(inertObject, p, newStoredValue, receiver);
if (result && isReactive) {
(0, _reactiveAction.runTransaction)(() => {
if (isChanged) {
this.#notifyValue(p);
}
if (!hasProperty) {
this.#reactive.keys.reportChanged();
}
});
}
if (changes) {
(0, _reactivePlugin.afterChange)(changes, this.#options.reactiveOptions?.plugins);
}
return result;
}
deleteProperty(inertObject, p) {
const isReactive = this.#isReactiveProperty(p);
const {
descriptor
} = (0, _reactiveUtils.getDescriptor)(inertObject, p);
const hasProperty = inertObject.hasOwnProperty(p);
const currentValue = Reflect.get(inertObject, p);
const isChanged = descriptor?.get || descriptor?.set || !(0, _reactiveOptions.reactiveValueEquals)(currentValue, undefined);
const changes = !this.#hasPlugins() || !isChanged ? null : (0, _reactivePluginObject.getObjectDeleteChanges)(this.#getProxy(), p, currentValue);
if (changes) {
(0, _reactivePlugin.beforeChange)(changes, this.#options.reactiveOptions?.plugins);
}
const result = Reflect.deleteProperty(inertObject, p);
if (result && isReactive) {
(0, _reactiveAction.runTransaction)(() => {
if (isChanged) {
this.#notifyValue(p);
}
if (hasProperty) {
this.#reactive.keys.reportChanged();
}
});
}
if (changes) {
(0, _reactivePlugin.afterChange)(changes, this.#options.reactiveOptions?.plugins);
}
return result;
}
ownKeys(inertObject) {
this.#reactive.keys.reportObserved();
return Reflect.ownKeys(inertObject);
}
#isReactiveProperty(p) {
return (!this.#options.reactiveOptions?.reactiveList || this.#options.reactiveOptions.reactiveList.indexOf(p) >= 0) && (!this.#options.reactiveOptions?.nonReactiveList || this.#options.reactiveOptions.nonReactiveList.indexOf(p) < 0);
}
#notifyValue(p) {
const node = this.#reactive.values[p];
if (node && node.type === ValueType.atom) {
node.value.reportChanged();
}
}
#readAtomValue(p) {
let node = this.#reactive.values[p];
if (!node || node.type !== ValueType.atom) {
if (!(0, _reactiveTracking.isTracking)()) {
return;
}
const value = (0, _reactiveAtom.createAtom)((0, _reactiveNames.createObjectValueAtomName)(this.#atomName, p.toString()), {
onBecomeUnobservedListener: () => {
this.#cleanupValue(p);
}
});
node = {
type: ValueType.atom,
value
};
this.#reactive.values[p] = node;
}
node.value.reportObserved();
}
#cleanupValue(p) {
delete this.#reactive.values[p];
}
#readComputedValue(p, calculate) {
let node = this.#reactive.values[p];
if (!node || node.type !== ValueType.computed) {
const proxy = this.#getProxy();
if (!(0, _reactiveTracking.isTracking)()) {
return calculate.call(proxy);
}
const value = (0, _reactiveComputed.createComputedAtom)((0, _reactiveNames.createObjectComputedValueAtomName)(this.#atomName, p.toString()), calculate.bind(proxy), {
onBecomeUnobservedListener: () => {
this.#cleanupValue(p);
}
});
node = {
type: ValueType.computed,
value
};
this.#reactive.values[p] = node;
}
return node.value.get();
}
#hasPlugins() {
return (this.#options.reactiveOptions?.plugins?.length ?? 0) > 0;
}
}
//# sourceMappingURL=reactive-object.js.map