EdgeAIG's picture
download
raw
6.01 kB
/**
* Mutable reactive references for local, in-memory state.
*
* `AtomRef` provides small observable state cells that can be read, updated,
* mapped, and subscribed to without going through an `AtomRegistry`. Mutable
* refs can also create refs for nested properties. The module also provides a
* collection helper that stores item refs and notifies subscribers when items are
* inserted, removed, or changed.
*
* @since 4.0.0
*/
import * as Equal from "../../Equal.js";
import * as Hash from "../../Hash.js";
/**
* The runtime type id used to identify `AtomRef` values.
*
* @category type IDs
* @since 4.0.0
*/
export const TypeId = "~effect/reactivity/AtomRef";
/**
* Creates a mutable reactive reference initialized with the supplied value.
*
* @category constructors
* @since 4.0.0
*/
export const make = value => new AtomRefImpl(value);
/**
* Creates a reactive collection from an iterable of initial item values.
*
* **Details**
*
* Each item is wrapped in an `AtomRef`, and changes to item refs notify the
* collection subscribers.
*
* @category constructors
* @since 4.0.0
*/
export const collection = items => new CollectionImpl(items);
const keyState = {
count: 0,
generate() {
return `AtomRef-${this.count++}`;
}
};
class ReadonlyRefImpl {
[TypeId];
key = /*#__PURE__*/keyState.generate();
value;
constructor(value) {
this[TypeId] = TypeId;
this.value = value;
}
[Equal.symbol](that) {
return Equal.equals(this.value, that.value);
}
[Hash.symbol]() {
return Hash.hash(this.value);
}
listeners = null;
notify(a) {
let listener = this.listeners;
while (listener !== null) {
listener.f(a);
listener = listener.next;
}
}
subscribe(f) {
const listener = {
f,
prev: null,
next: this.listeners
};
if (this.listeners) {
this.listeners.prev = listener;
}
this.listeners = listener;
return () => {
if (this.listeners === listener) {
this.listeners = listener.next;
}
if (listener.prev) {
listener.prev.next = listener.next;
}
if (listener.next) {
listener.next.prev = listener.prev;
}
};
}
map(f) {
return new MapRefImpl(this, f);
}
}
class AtomRefImpl extends ReadonlyRefImpl {
prop(prop) {
return new PropRefImpl(this, prop);
}
set(value) {
if (Equal.equals(value, this.value)) {
return this;
}
this.value = value;
this.notify(value);
return this;
}
update(f) {
return this.set(f(this.value));
}
}
class MapRefImpl {
[TypeId];
key = /*#__PURE__*/keyState.generate();
parent;
transform;
constructor(parent, transform) {
this[TypeId] = TypeId;
this.parent = parent;
this.transform = transform;
}
[Equal.symbol](that) {
return Equal.equals(this.value, that.value);
}
[Hash.symbol]() {
return Hash.hash(this.value);
}
get value() {
return this.transform(this.parent.value);
}
subscribe(f) {
let previous = this.transform(this.parent.value);
return this.parent.subscribe(a => {
const next = this.transform(a);
if (Equal.equals(next, previous)) {
return;
}
previous = next;
f(next);
});
}
map(f) {
return new MapRefImpl(this, f);
}
}
class PropRefImpl {
[TypeId];
key = /*#__PURE__*/keyState.generate();
previous;
parent;
_prop;
constructor(parent, _prop) {
this[TypeId] = TypeId;
this.parent = parent;
this._prop = _prop;
this.previous = parent.value[_prop];
}
[Equal.symbol](that) {
return Equal.equals(this.value, that.value);
}
[Hash.symbol]() {
return Hash.hash(this.value);
}
get value() {
if (this.parent.value && this._prop in this.parent.value) {
this.previous = this.parent.value[this._prop];
}
return this.previous;
}
subscribe(f) {
let previous = this.value;
return this.parent.subscribe(a => {
if (!a || !(this._prop in a)) {
return;
}
const next = a[this._prop];
if (Equal.equals(next, previous)) {
return;
}
previous = next;
f(next);
});
}
map(f) {
return new MapRefImpl(this, f);
}
prop(prop) {
return new PropRefImpl(this, prop);
}
set(value) {
if (Array.isArray(this.parent.value)) {
const newArray = this.parent.value.slice();
newArray[this._prop] = value;
this.parent.set(newArray);
} else {
this.parent.set({
...this.parent.value,
[this._prop]: value
});
}
return this;
}
update(f) {
if (Array.isArray(this.parent.value)) {
const newArray = this.parent.value.slice();
newArray[this._prop] = f(this.parent.value[this._prop]);
this.parent.set(newArray);
} else {
this.parent.set({
...this.parent.value,
[this._prop]: f(this.parent.value[this._prop])
});
}
return this;
}
}
class CollectionImpl extends ReadonlyRefImpl {
constructor(items) {
super([]);
for (const item of items) {
this.value.push(this.makeRef(item));
}
}
makeRef(value) {
const ref = new AtomRefImpl(value);
const notify = value => {
ref.notify(value);
this.notify(this.value);
};
return new Proxy(ref, {
get(target, p, _receiver) {
if (p === "notify") {
return notify;
}
return target[p];
}
});
}
push(item) {
const ref = this.makeRef(item);
this.value.push(ref);
this.notify(this.value);
return this;
}
insertAt(index, item) {
const ref = this.makeRef(item);
this.value.splice(index, 0, ref);
this.notify(this.value);
return this;
}
remove(ref) {
const index = this.value.indexOf(ref);
if (index !== -1) {
this.value.splice(index, 1);
this.notify(this.value);
}
return this;
}
toArray() {
return this.value.map(ref => ref.value);
}
}
//# sourceMappingURL=AtomRef.js.map

Xet Storage Details

Size:
6.01 kB
·
Xet hash:
20464a1c55a6de2db8aae88d4dcb9b6afda0ccdcc51925d760c109b964ee089f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.