UNPKG

solid-atom

Version:
128 lines (127 loc) 4.7 kB
(function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("solid-js")) : typeof define === "function" && define.amd ? define(["exports", "solid-js"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.solidAtom = {}, global.solidJs)); })(this, function(exports2, solidJs) { "use strict"; const PROXY = /* @__PURE__ */ new Proxy({}, { get: (_, k) => k }); const nameOf = (f) => f(PROXY); const NO_OP = () => { }; const IDENTITY = function(x) { return x; }; const THROW = () => { throw new ReferenceError(`No setter was defined for the current ${JSON.stringify(Atom.name)}`); }; class Atom { constructor(get, set) { this.get = get; this.set = set; } get value() { return this.get(); } set value(v) { this.set(v); } /** * Creates a new {@link Atom} with the setter of the current one and a memoized version of its getter * @param opts The memo's settings */ memo(opts) { return new Atom(solidJs.createMemo(this.get, void 0, opts), this.set); } /** * Creates a new {@link Atom} that applies a conversion to the current one * @param to Conversion function from {@link S} to {@link D} * @param from Conversion function from {@link D} to {@link S} */ convert(to, from) { return new Atom(() => to(this.value), (v) => this.value = from(v)); } /** * Allows you to execute {@link set} on the current {@link Atom} based on its current value. * The current value gets read through {@link untrack} to mimic the {@link Setter} behaviour. * If {@link f} is not provided, it will set the current value again * @param f Function that creates a new value based on the current one * @returns Whatever {@link f} returned */ update(f = IDENTITY) { const out = f(solidJs.untrack(this.get)); return this.set(out), out; } /** * Creates a new {@link Atom} that defers the setter of the current one. * When the setter is called, it will schedule the value to be set using {@link scheduler}. * If the setter gets called again, the previous operation will be cancelled, unless it has already finished * @param scheduler Function that schedules an operation and provides another function to cancel it */ defer(scheduler) { var clear = NO_OP; return new Atom(this.get, async (v) => { clear(); await new Promise((t) => clear = scheduler(t)); clear = NO_OP; this.value = v; }); } /** * Two way version of {@link createSelector} * @param comp The comparer function * @returns A boolean {@link Atom} factory */ selector(comp = solidJs.equalFn) { const isSelected = solidJs.createSelector(this.get, comp); return (f, def) => { return new Atom(() => isSelected(f()), (v) => { const value = f(); if (v) return this.value = value; if (!comp(value, this.value)) return; this.value = def; }); }; } /** * Creates a new {@link Atom} that throws an error when trying to set it * @param f The getter for the new {@link Atom} */ static readOnly(f) { return new this(f, THROW); } /** * Creates an {@link Atom} that forwards an {@link Accessor} to another {@link Atom} * @param f The reactive {@link Accessor} to the {@link Atom} to forward */ static unwrap(f) { return new this(() => f().value, (v) => f().value = v); } /** * Creates an {@link Atom} based on a {@link Signal} * @param param0 The {@link Signal} to forward */ static from([get, set]) { return new this(get, (v) => set(() => v)); } /** * Creates an {@link Atom} based on an object property * @param obj The object containing the property * @param k A function that returns the key of the property and will be passed to {@link nameOf} */ static prop(obj, k) { const temp = () => nameOf(k); return new this(() => obj()[temp()], (v) => obj()[temp()] = v); } static value(v, opts) { return this.from(solidJs.createSignal(v, opts)); } static source(bind, f = solidJs.createSignal) { return this.unwrap(solidJs.createMemo(solidJs.on(bind, (x) => x ?? this.from(f())))); } } exports2.Atom = Atom; exports2.IDENTITY = IDENTITY; exports2.NO_OP = NO_OP; exports2.nameOf = nameOf; Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); });