@oscarpalmer/mora 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/batch.d.mts +4 -5
- package/dist/batch.mjs +4 -2
- package/dist/constants.d.mts +29 -18
- package/dist/constants.mjs +19 -2
- package/dist/effect.d.mts +4 -5
- package/dist/effect.mjs +2 -2
- package/dist/helpers/is.d.mts +21 -15
- package/dist/helpers/is.mjs +21 -12
- package/dist/helpers/proxy.d.mts +12 -10
- package/dist/helpers/proxy.mjs +32 -14
- package/dist/helpers/subscription.d.mts +8 -0
- package/dist/helpers/subscription.mjs +27 -0
- package/dist/helpers/value.d.mts +8 -6
- package/dist/helpers/value.mjs +30 -4
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +2 -2
- package/dist/models.d.mts +108 -84
- package/dist/mora.full.mjs +504 -247
- package/dist/value/array.d.mts +4 -5
- package/dist/value/array.mjs +25 -56
- package/dist/value/computed.d.mts +3 -4
- package/dist/value/computed.mjs +14 -14
- package/dist/value/reactive.d.mts +2 -3
- package/dist/value/reactive.mjs +0 -1
- package/dist/value/readonly.d.mts +5 -0
- package/dist/value/readonly.mjs +33 -0
- package/dist/value/signal.d.mts +4 -5
- package/dist/value/signal.mjs +10 -17
- package/dist/value/store.d.mts +4 -5
- package/dist/value/store.mjs +17 -41
- package/package.json +6 -6
- package/src/batch.ts +15 -5
- package/src/constants.ts +41 -3
- package/src/effect.ts +6 -2
- package/src/helpers/is.ts +37 -12
- package/src/helpers/proxy.ts +99 -49
- package/src/helpers/subscription.ts +78 -0
- package/src/helpers/value.ts +69 -4
- package/src/index.ts +18 -2
- package/src/models.ts +131 -86
- package/src/value/array.ts +67 -120
- package/src/value/computed.ts +36 -13
- package/src/value/reactive.ts +8 -5
- package/src/value/readonly.ts +72 -0
- package/src/value/signal.ts +22 -16
- package/src/value/store.ts +37 -70
- package/types/constants.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/value/array.d.ts +1 -1
- package/types/value/computed.d.ts +0 -3
- package/types/value/signal.d.ts +1 -1
- package/types/value/store.d.ts +1 -1
- package/dist/subscription.d.mts +0 -7
- package/dist/subscription.mjs +0 -27
- package/src/subscription.ts +0 -45
package/dist/value/array.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ import { ReactiveArray, ReactiveOptions } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Reactive array
|
|
9
9
|
*/
|
|
10
|
-
declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
10
|
+
export declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
11
11
|
/**
|
|
12
12
|
* Create a reactive array from a promise
|
|
13
13
|
*
|
|
@@ -15,7 +15,7 @@ declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: Re
|
|
|
15
15
|
* @param options Reactivity options
|
|
16
16
|
* @returns Reactive array
|
|
17
17
|
*/
|
|
18
|
-
declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
18
|
+
export declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
19
19
|
/**
|
|
20
20
|
* Create a reactive array
|
|
21
21
|
*
|
|
@@ -23,6 +23,5 @@ declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<I
|
|
|
23
23
|
* @param options Reactivity options
|
|
24
24
|
* @returns Reactive array
|
|
25
25
|
*/
|
|
26
|
-
declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { array };
|
|
26
|
+
export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
27
|
+
//#endregion
|
package/dist/value/array.mjs
CHANGED
|
@@ -1,35 +1,33 @@
|
|
|
1
1
|
import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, NAME_MORA } from "../constants.mjs";
|
|
2
|
-
import { emitValue, equalArrays
|
|
3
|
-
import {
|
|
2
|
+
import { emitValue, equalArrays } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
4
4
|
import { reactive } from "./reactive.mjs";
|
|
5
5
|
import { computed } from "./computed.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
7
|
+
import { getReadonlyInstance } from "./readonly.mjs";
|
|
7
8
|
import { signal } from "./signal.mjs";
|
|
8
9
|
import { select } from "@oscarpalmer/atoms/array";
|
|
9
10
|
import { filter } from "@oscarpalmer/atoms/array/filter";
|
|
10
|
-
import { noop } from "@oscarpalmer/atoms/function";
|
|
11
11
|
//#region src/value/array.ts
|
|
12
12
|
function array(value, options) {
|
|
13
13
|
const [rx, state] = reactive([], options);
|
|
14
|
-
const
|
|
14
|
+
const isArray = true;
|
|
15
15
|
const length = signal(0);
|
|
16
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
17
|
+
const readonlies = {};
|
|
16
18
|
state.value = new Proxy([], {
|
|
17
19
|
get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, state, length) : Reflect.get(target, property),
|
|
18
|
-
set: (target, property, value) => setValueInProxy(
|
|
19
|
-
length,
|
|
20
|
-
property,
|
|
21
|
-
state,
|
|
22
|
-
target,
|
|
23
|
-
value,
|
|
24
|
-
isArray: true
|
|
25
|
-
})
|
|
20
|
+
set: (target, property, value) => setValueInProxy(isArray, state, target, property, value, length)
|
|
26
21
|
});
|
|
27
22
|
function get(value) {
|
|
28
|
-
return
|
|
23
|
+
return value === "length" ? length.get() : getValueInProxy(isArray, instance, state, mapped, value);
|
|
24
|
+
}
|
|
25
|
+
function set(first, second) {
|
|
26
|
+
setProxyValue(true, state, setArrayValue, setAtIndex, first, second);
|
|
29
27
|
}
|
|
30
28
|
const instance = {
|
|
31
29
|
...rx,
|
|
32
|
-
|
|
30
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
33
31
|
at: (index) => get(index),
|
|
34
32
|
clear: () => {
|
|
35
33
|
state.value.length = 0;
|
|
@@ -37,63 +35,38 @@ function array(value, options) {
|
|
|
37
35
|
filter: (callback) => computed(() => filter(get(), callback)),
|
|
38
36
|
get: (value) => get(value),
|
|
39
37
|
map: (callback) => computed(() => get().map(callback)),
|
|
40
|
-
notify: () =>
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
peek: (value) => peekArrayValue(state, length, value),
|
|
38
|
+
notify: () => emitProxyValues(state, mapped),
|
|
39
|
+
peek: (first, second) => peekArrayValue(state, length, first, second),
|
|
44
40
|
pop: () => state.value.pop(),
|
|
45
41
|
push: (...items) => state.value.push(...items),
|
|
46
42
|
select: (filter, map) => computed(() => select(get(), filter, map)),
|
|
47
|
-
set: (first, second) =>
|
|
48
|
-
setProxyValue(true, state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
|
|
49
|
-
},
|
|
43
|
+
set: (first, second) => set(first, second),
|
|
50
44
|
shift: () => state.value.shift(),
|
|
51
45
|
splice: (from, to, ...items) => state.value.splice(from, to ?? state.value.length, ...items),
|
|
52
|
-
subscribe: (first, second) =>
|
|
53
|
-
if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(instance, indiced, first, true).subscribe(second);
|
|
54
|
-
return typeof first === "function" ? subscribe(state, first) : noop;
|
|
55
|
-
},
|
|
46
|
+
subscribe: (first, second, third) => subscribeToProxy(isArray, instance, state, mapped, first, second, third),
|
|
56
47
|
unshift: (...items) => state.value.unshift(...items),
|
|
57
|
-
|
|
58
|
-
if (typeof first === "number" && typeof second === "function") getReactiveValueInProxy(instance, indiced, first, true)?.unsubscribe(second);
|
|
59
|
-
else if (typeof first === "function") unsubscribe(state, first);
|
|
60
|
-
},
|
|
61
|
-
update: (callback) => updateArrayValue(instance, state, callback)
|
|
48
|
+
update: (callback) => updateProxyValue(true, state, setArrayValue, setAtIndex, callback)
|
|
62
49
|
};
|
|
63
50
|
Object.defineProperties(instance, {
|
|
64
|
-
[NAME_MORA]: {
|
|
65
|
-
enumerable: false,
|
|
66
|
-
value: NAME_ARRAY
|
|
67
|
-
},
|
|
51
|
+
[NAME_MORA]: { value: NAME_ARRAY },
|
|
68
52
|
length: {
|
|
69
53
|
enumerable: true,
|
|
70
54
|
get: () => length.get(),
|
|
71
55
|
set: (value) => setArrayLength(state, value)
|
|
72
56
|
}
|
|
73
57
|
});
|
|
74
|
-
|
|
58
|
+
set(value);
|
|
75
59
|
return Object.freeze(instance);
|
|
76
60
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
return first === "length" ? length.get() : getSimpleValue(state);
|
|
61
|
+
function peekArrayValue(state, length, first, second) {
|
|
62
|
+
return first === "length" ? length.peek() : peekValueInProxy(true, state, first, second);
|
|
80
63
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
function isArrayValue(value) {
|
|
85
|
-
return value == null || Array.isArray(value);
|
|
86
|
-
}
|
|
87
|
-
function peekArrayValue(state, length, value) {
|
|
88
|
-
if (value === "length") return length.peek();
|
|
89
|
-
return typeof value === "number" ? state.value.at(value) : state.value.slice();
|
|
64
|
+
function setArrayLength(state, value) {
|
|
65
|
+
if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== state.value.length) state.value.length = value;
|
|
90
66
|
}
|
|
91
|
-
function
|
|
67
|
+
function setArrayValue(state, value) {
|
|
92
68
|
state.value.splice(0, state.value.length, ...value ?? []);
|
|
93
69
|
}
|
|
94
|
-
function setArrayLength(state, value) {
|
|
95
|
-
if (typeof value === "number" && value >= 0 && value !== state.value.length) state.value.length = value;
|
|
96
|
-
}
|
|
97
70
|
function setAtIndex(state, index, value) {
|
|
98
71
|
const actual = index < 0 ? state.value.length + index : index;
|
|
99
72
|
if (actual > -1) state.value[actual] = value;
|
|
@@ -111,9 +84,5 @@ function updateArray(type, array, state, length) {
|
|
|
111
84
|
return result;
|
|
112
85
|
};
|
|
113
86
|
}
|
|
114
|
-
function updateArrayValue(instance, state, callback) {
|
|
115
|
-
const updated = callback(state.value);
|
|
116
|
-
if (updated == null || Array.isArray(updated)) instance.set(updated);
|
|
117
|
-
}
|
|
118
87
|
//#endregion
|
|
119
88
|
export { array };
|
|
@@ -7,7 +7,6 @@ import { Computed, ComputedEffect, ReactiveOptions } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Computed value
|
|
9
9
|
*/
|
|
10
|
-
declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
11
|
-
declare function internalComputed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): [Computed<Value>, ComputedEffect];
|
|
12
|
-
//#endregion
|
|
13
|
-
export { computed, internalComputed };
|
|
10
|
+
export declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
11
|
+
export declare function internalComputed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): [Computed<Value>, ComputedEffect];
|
|
12
|
+
//#endregion
|
package/dist/value/computed.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA } from "../constants.mjs";
|
|
1
|
+
import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY } from "../constants.mjs";
|
|
2
2
|
import { internalEffect, runEffect } from "../effect.mjs";
|
|
3
|
+
import { handleSimpleValue, peekSimpleValue } from "../helpers/value.mjs";
|
|
3
4
|
import { flushHandlers } from "../batch.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { subscribe } from "../subscription.mjs";
|
|
5
|
+
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
6
6
|
import { reactive } from "./reactive.mjs";
|
|
7
7
|
//#region src/value/computed.ts
|
|
8
8
|
/**
|
|
@@ -16,21 +16,16 @@ function computed(callback, options) {
|
|
|
16
16
|
return getComputed(callback, options)[0];
|
|
17
17
|
}
|
|
18
18
|
function getComputed(callback, options) {
|
|
19
|
+
if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
|
|
19
20
|
const [rx, state] = reactive(void 0, options);
|
|
20
21
|
let fx;
|
|
21
22
|
const instance = {
|
|
22
23
|
...rx,
|
|
23
24
|
get: () => getValue(state, fx),
|
|
24
|
-
peek: () => state.value,
|
|
25
|
-
subscribe: (callback) =>
|
|
26
|
-
unsubscribe: (callback) => {
|
|
27
|
-
state.subscriptions.delete(callback);
|
|
28
|
-
}
|
|
25
|
+
peek: (copy) => peekSimpleValue(state.value, copy === true),
|
|
26
|
+
subscribe: (callback, copy) => subscribeToSignal(state, callback, copy === true)
|
|
29
27
|
};
|
|
30
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
31
|
-
enumerable: false,
|
|
32
|
-
value: NAME_COMPUTED
|
|
33
|
-
});
|
|
28
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_COMPUTED });
|
|
34
29
|
fx = getComputedEffect(state, callback);
|
|
35
30
|
return [Object.freeze(instance), fx];
|
|
36
31
|
}
|
|
@@ -64,8 +59,13 @@ function setAndEmit(state, value) {
|
|
|
64
59
|
if (state.equal(state.value, value)) return;
|
|
65
60
|
state.value = value;
|
|
66
61
|
for (const computed of state.computeds) computed.dirty = true;
|
|
67
|
-
for (const effect of state.effects) BATCH.handlers.
|
|
68
|
-
for (const
|
|
62
|
+
for (const effect of state.effects) BATCH.handlers.set(effect, effect);
|
|
63
|
+
for (const type of SUBSCRIPTION_TYPES) {
|
|
64
|
+
if (type === "frozen") continue;
|
|
65
|
+
const copy = SUBSCRIPTION_TYPES_COPY.has(type);
|
|
66
|
+
const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
|
|
67
|
+
if (subscriptions != null) for (const [, callback] of subscriptions) callback(peekSimpleValue(state.value, copy));
|
|
68
|
+
}
|
|
69
69
|
flushHandlers();
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Reactive, ReactiveOptions, ReactiveState } from "../models.mjs";
|
|
2
2
|
//#region src/value/reactive.d.ts
|
|
3
|
-
declare function reactive<Value,
|
|
4
|
-
//#endregion
|
|
5
|
-
export { reactive };
|
|
3
|
+
export declare function reactive<Value, Item = Value>(value: Value, options?: ReactiveOptions<Item>): [Reactive<Value>, ReactiveState<Value, Item>];
|
|
4
|
+
//#endregion
|
package/dist/value/reactive.mjs
CHANGED
|
@@ -4,7 +4,6 @@ function reactive(value, options) {
|
|
|
4
4
|
computeds: /* @__PURE__ */ new Set(),
|
|
5
5
|
effects: /* @__PURE__ */ new Set(),
|
|
6
6
|
equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
|
|
7
|
-
subscriptions: /* @__PURE__ */ new Map(),
|
|
8
7
|
value
|
|
9
8
|
};
|
|
10
9
|
return [{
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ReactiveState, ReadonlyFrozenSignal, ReadonlyInstances, ReadonlySignal } from "../models.mjs";
|
|
2
|
+
//#region src/value/readonly.d.ts
|
|
3
|
+
export declare function getReadonlyInstance<Value>(state: ReactiveState<Value, never>, instances: ReadonlyInstances<Value>, frozen: boolean): ReadonlySignal<Value>;
|
|
4
|
+
export declare function getReadonlySignal<Value>(state: ReactiveState<Value, never>, frozen: boolean): ReadonlySignal<Value> | ReadonlyFrozenSignal<Value>;
|
|
5
|
+
//#endregion
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NAME_MORA, NAME_READONLY, SUBSCRIPTION_TYPE_FROZEN, SUBSCRIPTION_TYPE_READONLY } from "../constants.mjs";
|
|
2
|
+
import { getFrozenValue, getSimpleValue, peekSimpleValue } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToReactive } from "../helpers/subscription.mjs";
|
|
4
|
+
//#region src/value/readonly.ts
|
|
5
|
+
function getReadonlyInstance(state, instances, frozen) {
|
|
6
|
+
const key = frozen ? "frozen" : "original";
|
|
7
|
+
instances[key] ??= getReadonlySignal(state, frozen);
|
|
8
|
+
return instances[key];
|
|
9
|
+
}
|
|
10
|
+
function getReadonlySignal(state, frozen) {
|
|
11
|
+
const type = frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY;
|
|
12
|
+
const instance = {
|
|
13
|
+
get: () => getReadonlyValue(state, false, frozen),
|
|
14
|
+
peek: (copy) => getReadonlyValue(state, true, frozen, copy),
|
|
15
|
+
subscribe: (callback) => subscribeToReactive(type, state, callback)
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperties(instance, {
|
|
18
|
+
[NAME_MORA]: { value: NAME_READONLY },
|
|
19
|
+
frozen: {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
value: frozen
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return Object.freeze(instance);
|
|
25
|
+
}
|
|
26
|
+
function getReadonlyValue(state, peek, frozen, copy) {
|
|
27
|
+
let value;
|
|
28
|
+
if (peek) value = peekSimpleValue(state.value, copy === true);
|
|
29
|
+
else value = getSimpleValue(state);
|
|
30
|
+
return frozen ? getFrozenValue(value) : value;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { getReadonlyInstance, getReadonlySignal };
|
package/dist/value/signal.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ import { ReactiveOptions, Signal } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Reactive value
|
|
9
9
|
*/
|
|
10
|
-
declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
10
|
+
export declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
11
11
|
/**
|
|
12
12
|
* Create a reactive value from a promise
|
|
13
13
|
*
|
|
@@ -15,7 +15,7 @@ declare function signal<Value>(value: () => Value | Promise<Value>, options?: Re
|
|
|
15
15
|
* @param options Reactivity options
|
|
16
16
|
* @returns Reactive value
|
|
17
17
|
*/
|
|
18
|
-
declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
18
|
+
export declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
19
19
|
/**
|
|
20
20
|
* Create a reactive value
|
|
21
21
|
*
|
|
@@ -23,6 +23,5 @@ declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<
|
|
|
23
23
|
* @param options Reactivity options
|
|
24
24
|
* @returns Reactive value
|
|
25
25
|
*/
|
|
26
|
-
declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { signal };
|
|
26
|
+
export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
27
|
+
//#endregion
|
package/dist/value/signal.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NAME_MORA, NAME_SIGNAL } from "../constants.mjs";
|
|
2
|
-
import { emitValue, getSimpleValue, handleSimpleValue } from "../helpers/value.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { emitValue, getSimpleValue, handleSimpleValue, peekSimpleValue, updateSimpleValue } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
4
4
|
import { reactive } from "./reactive.mjs";
|
|
5
|
+
import { getReadonlyInstance } from "./readonly.mjs";
|
|
5
6
|
//#region src/value/signal.ts
|
|
6
7
|
function setAndEmit(state, value) {
|
|
7
8
|
if (!state.equal(state.value, value)) {
|
|
@@ -11,25 +12,17 @@ function setAndEmit(state, value) {
|
|
|
11
12
|
}
|
|
12
13
|
function signal(value, options) {
|
|
13
14
|
const [rx, state] = reactive(void 0, options);
|
|
15
|
+
const readonlies = {};
|
|
14
16
|
const instance = {
|
|
15
17
|
...rx,
|
|
18
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
16
19
|
get: () => getSimpleValue(state),
|
|
17
|
-
peek: () => state.value,
|
|
18
|
-
set: (value) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
update: (callback) => {
|
|
22
|
-
handleSimpleValue(state, callback(state.value), setAndEmit);
|
|
23
|
-
},
|
|
24
|
-
subscribe: (callback) => subscribe(state, callback),
|
|
25
|
-
unsubscribe: (callback) => {
|
|
26
|
-
state.subscriptions.delete(callback);
|
|
27
|
-
}
|
|
20
|
+
peek: (copy) => peekSimpleValue(state.value, copy === true),
|
|
21
|
+
set: (value) => handleSimpleValue(state, value, setAndEmit),
|
|
22
|
+
subscribe: (callback, copy) => subscribeToSignal(state, callback, copy === true),
|
|
23
|
+
update: (callback) => updateSimpleValue(state, callback, setAndEmit)
|
|
28
24
|
};
|
|
29
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
30
|
-
enumerable: false,
|
|
31
|
-
value: NAME_SIGNAL
|
|
32
|
-
});
|
|
25
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_SIGNAL });
|
|
33
26
|
handleSimpleValue(state, value, setAndEmit);
|
|
34
27
|
return Object.freeze(instance);
|
|
35
28
|
}
|
package/dist/value/store.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
|
8
8
|
* @param options Reactivity options
|
|
9
9
|
* @returns Reactive store
|
|
10
10
|
*/
|
|
11
|
-
declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
11
|
+
export declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
12
12
|
/**
|
|
13
13
|
* Create a reactive store from a promise
|
|
14
14
|
*
|
|
@@ -16,7 +16,7 @@ declare function store<Value extends PlainObject>(value: () => Value | Promise<V
|
|
|
16
16
|
* @param options Reactivity options
|
|
17
17
|
* @returns Reactive store
|
|
18
18
|
*/
|
|
19
|
-
declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
19
|
+
export declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
20
20
|
/**
|
|
21
21
|
* Create a reactive store
|
|
22
22
|
*
|
|
@@ -24,6 +24,5 @@ declare function store<Value extends PlainObject>(value: Promise<Value>, options
|
|
|
24
24
|
* @param options Reactivity options
|
|
25
25
|
* @returns Reactive store
|
|
26
26
|
*/
|
|
27
|
-
declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { store };
|
|
27
|
+
export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
28
|
+
//#endregion
|
package/dist/value/store.mjs
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { NAME_MORA, NAME_STORE } from "../constants.mjs";
|
|
2
2
|
import { startBatch, stopBatch } from "../batch.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { noop, subscribe, unsubscribe } from "../subscription.mjs";
|
|
3
|
+
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
5
4
|
import { reactive } from "./reactive.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
6
|
+
import { getReadonlyInstance } from "./readonly.mjs";
|
|
8
7
|
//#region src/value/store.ts
|
|
9
|
-
function
|
|
10
|
-
|
|
8
|
+
function setPropertyValue(state, key, value) {
|
|
9
|
+
state.value[key] = value;
|
|
11
10
|
}
|
|
12
|
-
function
|
|
11
|
+
function setStoreValue(state, value) {
|
|
13
12
|
startBatch();
|
|
14
13
|
const actual = value ?? {};
|
|
15
14
|
const proxy = state.value;
|
|
@@ -27,46 +26,23 @@ function setObject(state, value) {
|
|
|
27
26
|
}
|
|
28
27
|
stopBatch();
|
|
29
28
|
}
|
|
30
|
-
function setProperty(state, key, value) {
|
|
31
|
-
state.value[key] = value;
|
|
32
|
-
}
|
|
33
29
|
function store(value, options) {
|
|
34
30
|
const [rx, state] = reactive(void 0, options);
|
|
31
|
+
const isArray = false;
|
|
35
32
|
const keyed = /* @__PURE__ */ new Map();
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
property,
|
|
39
|
-
state,
|
|
40
|
-
value,
|
|
41
|
-
isArray: false
|
|
42
|
-
}) });
|
|
33
|
+
const readonlies = {};
|
|
34
|
+
state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy(isArray, state, target, property, value) });
|
|
43
35
|
const instance = {
|
|
44
36
|
...rx,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
},
|
|
53
|
-
subscribe: (first, second) => {
|
|
54
|
-
if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(instance, keyed, first, false).subscribe(second);
|
|
55
|
-
return typeof first === "function" ? subscribe(state, first) : noop;
|
|
56
|
-
},
|
|
57
|
-
unsubscribe: (first, second) => {
|
|
58
|
-
if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
|
|
59
|
-
else if (typeof first === "function") unsubscribe(state, first);
|
|
60
|
-
},
|
|
61
|
-
update: (callback) => {
|
|
62
|
-
const updated = callback(state.value);
|
|
63
|
-
if (updated == null || isPlainObject(updated)) setObject(state, updated);
|
|
64
|
-
}
|
|
37
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
38
|
+
get: (value) => getValueInProxy(isArray, instance, state, keyed, value),
|
|
39
|
+
notify: () => emitProxyValues(state, keyed),
|
|
40
|
+
peek: (first, second) => peekValueInProxy(isArray, state, first, second),
|
|
41
|
+
set: (first, second) => setProxyValue(isArray, state, setStoreValue, setPropertyValue, first, second),
|
|
42
|
+
subscribe: (first, second, third) => subscribeToProxy(isArray, instance, state, keyed, first, second, third),
|
|
43
|
+
update: (callback) => updateProxyValue(isArray, state, setStoreValue, setPropertyValue, callback)
|
|
65
44
|
};
|
|
66
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
67
|
-
enumerable: false,
|
|
68
|
-
value: NAME_STORE
|
|
69
|
-
});
|
|
45
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_STORE });
|
|
70
46
|
instance.set(value);
|
|
71
47
|
return Object.freeze(instance);
|
|
72
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -39,17 +39,17 @@
|
|
|
39
39
|
"test:leak": "vpx vp test run --detect-async-leaks --coverage"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oscarpalmer/atoms": "^0.
|
|
42
|
+
"@oscarpalmer/atoms": "^0.202"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/node": "^26.
|
|
46
|
-
"@vitest/coverage-istanbul": "4.1
|
|
45
|
+
"@types/node": "^26.5",
|
|
46
|
+
"@vitest/coverage-istanbul": "^4.1",
|
|
47
47
|
"jsdom": "^30",
|
|
48
|
-
"tsdown": "^0.
|
|
48
|
+
"tsdown": "^0.23",
|
|
49
49
|
"typescript": "^6",
|
|
50
50
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
|
51
51
|
"vite-plus": "latest",
|
|
52
52
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
53
53
|
},
|
|
54
|
-
"packageManager": "npm@11.
|
|
54
|
+
"packageManager": "npm@11.19.0"
|
|
55
55
|
}
|
package/src/batch.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {BATCH} from './constants';
|
|
2
2
|
import {runEffect} from './effect';
|
|
3
|
-
import
|
|
3
|
+
import {getFrozenValue, peekSimpleValue} from './helpers/value';
|
|
4
|
+
import type {EffectState, StoredSubscription} from './models';
|
|
5
|
+
|
|
6
|
+
// #region Functions
|
|
4
7
|
|
|
5
8
|
export function flushHandlers(): void {
|
|
6
9
|
if (BATCH.flushing) {
|
|
@@ -17,10 +20,15 @@ export function flushHandlers(): void {
|
|
|
17
20
|
BATCH.handlers.clear();
|
|
18
21
|
|
|
19
22
|
for (let index = 0; index < length; index += 1) {
|
|
20
|
-
const handler = handlers[index];
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const [, handler] = handlers[index];
|
|
24
|
+
const subscription = handler as StoredSubscription;
|
|
25
|
+
|
|
26
|
+
if (typeof subscription.frozen === 'boolean') {
|
|
27
|
+
subscription.callback(
|
|
28
|
+
subscription.frozen
|
|
29
|
+
? getFrozenValue(subscription.state.value)
|
|
30
|
+
: peekSimpleValue(subscription.state.value, subscription.copy),
|
|
31
|
+
);
|
|
24
32
|
} else {
|
|
25
33
|
runEffect(handler as EffectState);
|
|
26
34
|
}
|
|
@@ -50,3 +58,5 @@ export function stopBatch(): void {
|
|
|
50
58
|
|
|
51
59
|
flushHandlers();
|
|
52
60
|
}
|
|
61
|
+
|
|
62
|
+
// #endregion
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {Active, Batch,
|
|
1
|
+
import type {Active, Batch, SubscriptionType} from './models';
|
|
2
|
+
|
|
3
|
+
// #region Variables
|
|
2
4
|
|
|
3
5
|
export const ACTIVE: Active = {};
|
|
4
6
|
|
|
@@ -11,7 +13,7 @@ export const ARRAY_PEEK = 10;
|
|
|
11
13
|
export const BATCH: Batch = {
|
|
12
14
|
depth: 0,
|
|
13
15
|
flushing: false,
|
|
14
|
-
handlers: new
|
|
16
|
+
handlers: new Map(),
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export const METHODS_AFFECTING_LENGTH = new Set<string>(['pop', 'push', 'shift', 'unshift']);
|
|
@@ -33,10 +35,46 @@ export const NAME_EFFECT = 'effect';
|
|
|
33
35
|
|
|
34
36
|
export const NAME_MORA = '$mora';
|
|
35
37
|
|
|
38
|
+
export const NAME_READONLY = 'readonly';
|
|
39
|
+
|
|
36
40
|
export const NAME_SIGNAL = 'signal';
|
|
37
41
|
|
|
38
42
|
export const NAME_STORE = 'store';
|
|
39
43
|
|
|
40
|
-
export const
|
|
44
|
+
export const NAME_SUBSCRIPTION = 'subscription';
|
|
45
|
+
|
|
46
|
+
export const NAME_ALL = new Set([
|
|
47
|
+
NAME_ARRAY,
|
|
48
|
+
NAME_COMPUTED,
|
|
49
|
+
NAME_READONLY,
|
|
50
|
+
NAME_SIGNAL,
|
|
51
|
+
NAME_STORE,
|
|
52
|
+
]);
|
|
41
53
|
|
|
42
54
|
export const PROPERTY_LENGTH = 'length';
|
|
55
|
+
|
|
56
|
+
export const SUBSCRIPTION_PROPERTY = {
|
|
57
|
+
key: NAME_MORA,
|
|
58
|
+
value: NAME_SUBSCRIPTION,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const SUBSCRIPTION_TYPE_COPY: SubscriptionType = 'copy';
|
|
62
|
+
|
|
63
|
+
export const SUBSCRIPTION_TYPE_FROZEN: SubscriptionType = 'frozen';
|
|
64
|
+
|
|
65
|
+
export const SUBSCRIPTION_TYPE_ORIGINAL: SubscriptionType = 'original';
|
|
66
|
+
|
|
67
|
+
export const SUBSCRIPTION_TYPE_READONLY: SubscriptionType = 'readonly';
|
|
68
|
+
|
|
69
|
+
export const SUBSCRIPTION_TYPES_COPY = new Set<SubscriptionType>([
|
|
70
|
+
SUBSCRIPTION_TYPE_COPY,
|
|
71
|
+
SUBSCRIPTION_TYPE_READONLY,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
export const SUBSCRIPTION_TYPES: Set<SubscriptionType> = new Set([
|
|
75
|
+
...SUBSCRIPTION_TYPES_COPY,
|
|
76
|
+
SUBSCRIPTION_TYPE_FROZEN,
|
|
77
|
+
SUBSCRIPTION_TYPE_ORIGINAL,
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
// #endregion
|
package/src/effect.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {ACTIVE, NAME_EFFECT} from './constants';
|
|
2
|
+
import {ACTIVE, NAME_EFFECT, NAME_MORA} from './constants';
|
|
3
3
|
import type {Effect, EffectState} from './models';
|
|
4
4
|
|
|
5
|
+
// #region Functions
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Create an effect
|
|
7
9
|
*
|
|
@@ -22,7 +24,7 @@ function getEffect(callback: GenericCallback): [Effect, EffectState] {
|
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
const instance = Object.freeze({
|
|
25
|
-
|
|
27
|
+
[NAME_MORA]: NAME_EFFECT,
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
runEffect(state);
|
|
@@ -45,3 +47,5 @@ export function runEffect(state: EffectState): void {
|
|
|
45
47
|
ACTIVE.effect = previousEffect;
|
|
46
48
|
}
|
|
47
49
|
}
|
|
50
|
+
|
|
51
|
+
// #endregion
|