UNPKG

signal-utils

Version:

Utils for use with the Signals Proposal: https://github.com/proposal-signals/proposal-signals

101 lines (97 loc) 2.98 kB
import { createStorage } from './-private/util.ts.js'; /** * Implementation based of tracked-built-ins' TrackedObject * https://github.com/tracked-tools/tracked-built-ins/blob/master/addon/src/-private/object.js */ class SignalObjectImpl { static fromEntries(entries) { return new SignalObjectImpl(Object.fromEntries(entries)); } #storages = new Map(); #collection = createStorage(); constructor(obj = {}) { let proto = Object.getPrototypeOf(obj); let descs = Object.getOwnPropertyDescriptors(obj); let clone = Object.create(proto); for (let prop in descs) { // SAFETY: we just iterated over the property, so having to do an // existence check here is a little silly Object.defineProperty(clone, prop, descs[prop]); } let self = this; return new Proxy(clone, { get(target, prop, receiver) { // we don't use the signals directly // because we don't know (nor care!) what the value would be // and the value could be replaced // (this is also important for supporting getters) self.#readStorageFor(prop); return Reflect.get(target, prop, receiver); }, has(target, prop) { self.#readStorageFor(prop); return prop in target; }, ownKeys(target) { self.#collection.get(); return Reflect.ownKeys(target); }, set(target, prop, value, receiver) { let result = Reflect.set(target, prop, value, receiver); self.#dirtyStorageFor(prop); self.#dirtyCollection(); return result; }, deleteProperty(target, prop) { if (prop in target) { delete target[prop]; self.#dirtyStorageFor(prop); self.#dirtyCollection(); } return true; }, getPrototypeOf() { return SignalObjectImpl.prototype; } }); } #readStorageFor(key) { let storage = this.#storages.get(key); if (storage === undefined) { storage = createStorage(); this.#storages.set(key, storage); } storage.get(); } #dirtyStorageFor(key) { const storage = this.#storages.get(key); if (storage) { storage.set(null); } } #dirtyCollection() { this.#collection.set(null); } } // Types are too hard in proxy-implementation // we want TS to think the SignalObject is Object-like /** * Create a reactive Object, backed by Signals, using a Proxy. * This allows dynamic creation and deletion of signals using the object primitive * APIs that most folks are familiar with -- the only difference is instantiation. * ```js * const obj = new SignalObject({ foo: 123 }); * * obj.foo // 123 * obj.foo = 456 * obj.foo // 456 * obj.bar = 2 * obj.bar // 2 * ``` */ const SignalObject = SignalObjectImpl; function signalObject(obj) { return new SignalObject(obj); } export { SignalObject, SignalObjectImpl, signalObject }; //# sourceMappingURL=object.ts.js.map