solid-atom
Version:
Simple two way reactive bindings
128 lines (127 loc) • 4.7 kB
JavaScript
(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" });
});