@oscarpalmer/mora 0.38.0 → 0.39.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 +1 -3
- package/dist/batch.mjs +3 -4
- package/dist/constants.d.mts +16 -10
- package/dist/constants.mjs +12 -6
- package/dist/effect.d.mts +2 -3
- package/dist/effect.mjs +27 -8
- package/dist/helpers/is.d.mts +1 -3
- package/dist/helpers/is.mjs +8 -5
- package/dist/helpers/misc.d.mts +8 -4
- package/dist/helpers/misc.mjs +66 -4
- package/dist/helpers/proxy.d.mts +3 -4
- package/dist/helpers/proxy.mjs +26 -11
- package/dist/helpers/subscription.d.mts +1 -3
- package/dist/helpers/subscription.mjs +15 -7
- package/dist/helpers/value.d.mts +4 -5
- package/dist/helpers/value.mjs +18 -13
- package/dist/models.d.mts +38 -5
- package/dist/mora.full.mjs +555 -276
- package/dist/value/array.d.mts +1 -3
- package/dist/value/array.mjs +46 -22
- package/dist/value/computed.d.mts +1 -3
- package/dist/value/computed.mjs +17 -11
- package/dist/value/readonly.d.mts +2 -5
- package/dist/value/readonly.mjs +24 -16
- package/dist/value/signal.d.mts +1 -3
- package/dist/value/signal.mjs +9 -6
- package/dist/value/store.d.mts +1 -3
- package/dist/value/store.mjs +9 -6
- package/package.json +5 -12
- package/src/batch.ts +8 -4
- package/src/constants.ts +26 -16
- package/src/effect.ts +37 -7
- package/src/helpers/is.ts +18 -8
- package/src/helpers/misc.ts +121 -2
- package/src/helpers/proxy.ts +59 -9
- package/src/helpers/subscription.ts +34 -4
- package/src/helpers/value.ts +48 -15
- package/src/models.ts +42 -3
- package/src/value/array.ts +100 -21
- package/src/value/computed.ts +29 -10
- package/src/value/readonly.ts +38 -33
- package/src/value/signal.ts +11 -5
- package/src/value/store.ts +11 -5
- package/types/batch.d.ts +0 -11
- package/types/constants.d.ts +0 -16
- package/types/effect.d.ts +0 -13
- package/types/helpers/is.d.ts +0 -43
- package/types/helpers/proxy.d.ts +0 -11
- package/types/helpers/value.d.ts +0 -4
- package/types/index.d.ts +0 -9
- package/types/models.d.ts +0 -56
- package/types/subscription.d.ts +0 -11
- package/types/value/array.d.ts +0 -137
- package/types/value/computed.d.ts +0 -14
- package/types/value/reactive.d.ts +0 -36
- package/types/value/signal.d.ts +0 -26
- package/types/value/store.d.ts +0 -94
package/dist/value/array.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ReactiveArray, ReactiveOptions } from "../models.mjs";
|
|
2
|
-
//#region src/value/array.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Create a reactive array from a function result
|
|
5
4
|
*
|
|
@@ -23,5 +22,4 @@ export declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOp
|
|
|
23
22
|
* @param options Reactivity options
|
|
24
23
|
* @returns Reactive array
|
|
25
24
|
*/
|
|
26
|
-
export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
27
|
-
//#endregion
|
|
25
|
+
export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
package/dist/value/array.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY,
|
|
1
|
+
import { MESSAGE_DEACTIVATED_ARRAY_FILTER, MESSAGE_DEACTIVATED_ARRAY_MAP, MESSAGE_DEACTIVATED_ARRAY_SELECT, METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, PROPERTY_LENGTH, SYMBOL_STATE } from "../constants.mjs";
|
|
2
2
|
import { emitValue, equalArrays, getJsonValue, getStringValue } from "../helpers/value.mjs";
|
|
3
|
-
import { getState } from "../helpers/misc.mjs";
|
|
3
|
+
import { deactivateProxy, getReactiveActive, getState } from "../helpers/misc.mjs";
|
|
4
4
|
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
5
5
|
import { computed } from "./computed.mjs";
|
|
6
|
-
import { getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
6
|
+
import { getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyDerivations, updateProxyValue } from "../helpers/proxy.mjs";
|
|
7
7
|
import { getReadonlySignal } from "./readonly.mjs";
|
|
8
8
|
import { signal } from "./signal.mjs";
|
|
9
9
|
import { filter } from "@oscarpalmer/atoms/array/filter";
|
|
10
10
|
import { select } from "@oscarpalmer/atoms/array/select";
|
|
11
|
-
|
|
11
|
+
// src/value/array.ts
|
|
12
12
|
function ReactiveArray(value, options) {
|
|
13
13
|
this[SYMBOL_STATE] = {
|
|
14
|
-
...getState(void 0, options),
|
|
14
|
+
...getState(NAME_ARRAY, void 0, options),
|
|
15
15
|
isArray: true,
|
|
16
16
|
length: signal(0)
|
|
17
17
|
};
|
|
@@ -21,15 +21,10 @@ function ReactiveArray(value, options) {
|
|
|
21
21
|
});
|
|
22
22
|
setProxyValue.call(this, value);
|
|
23
23
|
}
|
|
24
|
-
ReactiveArray.prototype[NAME_MORA] = NAME_ARRAY;
|
|
25
|
-
Object.defineProperty(ReactiveArray.prototype, PROPERTY_LENGTH, {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
get: getArrayLength,
|
|
28
|
-
set: setArrayLength
|
|
29
|
-
});
|
|
30
24
|
ReactiveArray.prototype.asReadonly = getReadonlySignal;
|
|
31
25
|
ReactiveArray.prototype.at = getArrayValues;
|
|
32
26
|
ReactiveArray.prototype.clear = clearArrayValues;
|
|
27
|
+
ReactiveArray.prototype.deactivate = deactivateArray;
|
|
33
28
|
ReactiveArray.prototype.filter = filterArrayValues;
|
|
34
29
|
ReactiveArray.prototype.get = getArrayValues;
|
|
35
30
|
ReactiveArray.prototype.map = mapArrayValues;
|
|
@@ -46,14 +41,33 @@ ReactiveArray.prototype.toString = getStringValue;
|
|
|
46
41
|
ReactiveArray.prototype.toJSON = getJsonValue;
|
|
47
42
|
ReactiveArray.prototype.unshift = unshiftArrayValues;
|
|
48
43
|
ReactiveArray.prototype.update = updateProxyValue;
|
|
44
|
+
Object.defineProperties(ReactiveArray.prototype, {
|
|
45
|
+
[PROPERTY_LENGTH]: {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: getArrayLength,
|
|
48
|
+
set: setArrayLength
|
|
49
|
+
},
|
|
50
|
+
active: {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
get: getReactiveActive
|
|
53
|
+
}
|
|
54
|
+
});
|
|
49
55
|
function array(value, options) {
|
|
50
56
|
return new ReactiveArray(value, options);
|
|
51
57
|
}
|
|
52
58
|
function clearArrayValues() {
|
|
53
|
-
this[SYMBOL_STATE]
|
|
59
|
+
const state = this[SYMBOL_STATE];
|
|
60
|
+
if (state.active) state.value.length = 0;
|
|
61
|
+
}
|
|
62
|
+
function deactivateArray() {
|
|
63
|
+
const state = this[SYMBOL_STATE];
|
|
64
|
+
if (!state.active) return;
|
|
65
|
+
state.length?.deactivate?.();
|
|
66
|
+
deactivateProxy.call(this);
|
|
54
67
|
}
|
|
55
68
|
function filterArrayValues(callback) {
|
|
56
|
-
|
|
69
|
+
if (!this[SYMBOL_STATE].active) throw new Error(MESSAGE_DEACTIVATED_ARRAY_FILTER);
|
|
70
|
+
return updateProxyDerivations(this, computed(() => filter(getArrayValues.call(this), callback)));
|
|
57
71
|
}
|
|
58
72
|
function getArrayLength() {
|
|
59
73
|
return this[SYMBOL_STATE].length.get();
|
|
@@ -62,36 +76,47 @@ function getArrayValues(value) {
|
|
|
62
76
|
return value === "length" ? this[SYMBOL_STATE].length.get() : getValueInProxy.call(this, value);
|
|
63
77
|
}
|
|
64
78
|
function mapArrayValues(callback) {
|
|
65
|
-
|
|
79
|
+
if (!this[SYMBOL_STATE].active) throw new Error(MESSAGE_DEACTIVATED_ARRAY_MAP);
|
|
80
|
+
return updateProxyDerivations(this, computed(() => getArrayValues.call(this).map((item, index, array) => callback(item, index, array))));
|
|
66
81
|
}
|
|
67
82
|
function peekArrayValue(first, second) {
|
|
68
83
|
return first === "length" ? this[SYMBOL_STATE].length.peek() : peekValueInProxy.call(this, first, second);
|
|
69
84
|
}
|
|
70
85
|
function popArrayValue() {
|
|
71
|
-
|
|
86
|
+
const state = this[SYMBOL_STATE];
|
|
87
|
+
return state.active ? state.value.pop() : void 0;
|
|
72
88
|
}
|
|
73
89
|
function pushArrayValues(...items) {
|
|
74
|
-
|
|
90
|
+
const state = this[SYMBOL_STATE];
|
|
91
|
+
return state.active ? state.value.push(...items) : state.value.length;
|
|
75
92
|
}
|
|
76
93
|
function selectArrayValues(filter, map) {
|
|
77
|
-
|
|
94
|
+
if (!this[SYMBOL_STATE].active) throw new Error(MESSAGE_DEACTIVATED_ARRAY_SELECT);
|
|
95
|
+
return updateProxyDerivations(this, computed(() => select(getArrayValues.call(this), filter, map)));
|
|
78
96
|
}
|
|
79
97
|
function setArrayLength(value) {
|
|
80
|
-
const
|
|
98
|
+
const state = this[SYMBOL_STATE];
|
|
99
|
+
if (!state.active) return;
|
|
100
|
+
const values = state.value;
|
|
81
101
|
if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== values.length) values.length = value;
|
|
82
102
|
}
|
|
83
103
|
function shiftArrayValue() {
|
|
84
|
-
|
|
104
|
+
const state = this[SYMBOL_STATE];
|
|
105
|
+
return state.active ? state.value.shift() : void 0;
|
|
85
106
|
}
|
|
86
107
|
function spliceArrayValues(from, to, ...items) {
|
|
87
|
-
const
|
|
108
|
+
const state = this[SYMBOL_STATE];
|
|
109
|
+
if (!state.active) return [];
|
|
110
|
+
const values = state.value;
|
|
88
111
|
return values.splice(from, to ?? values.length, ...items);
|
|
89
112
|
}
|
|
90
113
|
function unshiftArrayValues(...items) {
|
|
91
|
-
|
|
114
|
+
const state = this[SYMBOL_STATE];
|
|
115
|
+
return state.active ? state.value.unshift(...items) : state.value.length;
|
|
92
116
|
}
|
|
93
117
|
function updateArray(instance, type, array) {
|
|
94
118
|
const state = instance[SYMBOL_STATE];
|
|
119
|
+
if (!state.active) return () => void 0;
|
|
95
120
|
const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
|
|
96
121
|
const previousArray = affectsLength ? [] : array.slice();
|
|
97
122
|
const previousLength = array.length;
|
|
@@ -104,5 +129,4 @@ function updateArray(instance, type, array) {
|
|
|
104
129
|
return result;
|
|
105
130
|
};
|
|
106
131
|
}
|
|
107
|
-
//#endregion
|
|
108
132
|
export { array };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Computed, InternalComputed, ReactiveOptions } from "../models.mjs";
|
|
2
2
|
import { GenericCallback } from "@oscarpalmer/atoms/models";
|
|
3
|
-
//#region src/value/computed.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Create a computed value
|
|
6
5
|
*
|
|
@@ -9,5 +8,4 @@ import { GenericCallback } from "@oscarpalmer/atoms/models";
|
|
|
9
8
|
* @returns Computed value
|
|
10
9
|
*/
|
|
11
10
|
export declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
12
|
-
export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): InternalComputed;
|
|
13
|
-
//#endregion
|
|
11
|
+
export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): InternalComputed;
|
package/dist/value/computed.mjs
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import { ACTIVE, BATCH,
|
|
1
|
+
import { ACTIVE, BATCH, MESSAGE_COMPUTED_CALLBACK, NAME_COMPUTED, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY, SYMBOL_EFFECT, SYMBOL_STATE } from "../constants.mjs";
|
|
2
2
|
import { internalEffect, runEffect } from "../effect.mjs";
|
|
3
3
|
import { getJsonValue, getStringValue, handleSignal, peekSignalValue } from "../helpers/value.mjs";
|
|
4
4
|
import { flushHandlers } from "../batch.mjs";
|
|
5
|
-
import { getState } from "../helpers/misc.mjs";
|
|
5
|
+
import { deactivateComputed, getReactiveActive, getState } from "../helpers/misc.mjs";
|
|
6
6
|
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
7
|
-
|
|
7
|
+
// src/value/computed.ts
|
|
8
8
|
function Computed(callback, options) {
|
|
9
|
-
this[SYMBOL_STATE] = getState(void 0, options);
|
|
9
|
+
this[SYMBOL_STATE] = getState(NAME_COMPUTED, void 0, options);
|
|
10
10
|
this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
|
|
11
11
|
}
|
|
12
|
-
Computed.prototype
|
|
12
|
+
Computed.prototype.deactivate = deactivateComputed;
|
|
13
13
|
Computed.prototype.get = getComputedValue;
|
|
14
14
|
Computed.prototype.peek = peekSignalValue;
|
|
15
15
|
Computed.prototype.subscribe = subscribeToSignal;
|
|
16
16
|
Computed.prototype.toJSON = getJsonValue;
|
|
17
17
|
Computed.prototype.toString = getStringValue;
|
|
18
|
+
Object.defineProperties(Computed.prototype, { active: {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: getReactiveActive
|
|
21
|
+
} });
|
|
18
22
|
/**
|
|
19
23
|
* Create a computed value
|
|
20
24
|
*
|
|
@@ -26,7 +30,7 @@ function computed(callback, options) {
|
|
|
26
30
|
return getComputed(callback, options);
|
|
27
31
|
}
|
|
28
32
|
function getComputed(callback, options) {
|
|
29
|
-
if (typeof callback !== "function") throw new TypeError(
|
|
33
|
+
if (typeof callback !== "function") throw new TypeError(MESSAGE_COMPUTED_CALLBACK);
|
|
30
34
|
return new Computed(callback, options);
|
|
31
35
|
}
|
|
32
36
|
function getComputedEffect(instance, callback) {
|
|
@@ -49,8 +53,9 @@ function getComputedEffect(instance, callback) {
|
|
|
49
53
|
return fx;
|
|
50
54
|
}
|
|
51
55
|
function getComputedValue() {
|
|
52
|
-
const fx = this[SYMBOL_EFFECT];
|
|
53
56
|
const state = this[SYMBOL_STATE];
|
|
57
|
+
if (!state.active) return state.value;
|
|
58
|
+
const fx = this[SYMBOL_EFFECT];
|
|
54
59
|
if (ACTIVE.computed != null && fx !== ACTIVE.computed) {
|
|
55
60
|
state.computeds ??= /* @__PURE__ */ new Set();
|
|
56
61
|
state.computeds.add(ACTIVE.computed);
|
|
@@ -67,10 +72,12 @@ function internalComputed(callback, options) {
|
|
|
67
72
|
}
|
|
68
73
|
function setAndEmit(instance, value, notify) {
|
|
69
74
|
const state = instance[SYMBOL_STATE];
|
|
70
|
-
if (!notify && (state.equal ?? Object.is)(state.value, value)) return;
|
|
75
|
+
if (!state.active || !notify && (state.equal ?? Object.is)(state.value, value)) return;
|
|
71
76
|
state.value = value;
|
|
72
|
-
if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
|
|
73
|
-
|
|
77
|
+
if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) if (computed.instance.active) computed.dirty = true;
|
|
78
|
+
else state.computeds.delete(computed);
|
|
79
|
+
if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) if (effect.active) BATCH.handlers.set(effect, effect);
|
|
80
|
+
else state.effects.delete(effect);
|
|
74
81
|
for (const type of SUBSCRIPTION_TYPES) {
|
|
75
82
|
if (type === "frozen") continue;
|
|
76
83
|
const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
|
|
@@ -81,5 +88,4 @@ function setAndEmit(instance, value, notify) {
|
|
|
81
88
|
}
|
|
82
89
|
flushHandlers();
|
|
83
90
|
}
|
|
84
|
-
//#endregion
|
|
85
91
|
export { computed, internalComputed };
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import { InternalSignal,
|
|
2
|
-
|
|
3
|
-
export declare function getReadonlyInstance(state: SignalState, frozen: boolean): ReadonlySignal<unknown> | ReadonlyFrozenSignal<unknown>;
|
|
4
|
-
export declare function getReadonlySignal<Value>(this: InternalSignal, frozen?: never): ReadonlySignal<Value>;
|
|
5
|
-
//#endregion
|
|
1
|
+
import { InternalSignal, ReadonlySignal } from "../models.mjs";
|
|
2
|
+
export declare function getReadonlySignal<Value>(this: InternalSignal, frozen?: never): ReadonlySignal<Value>;
|
package/dist/value/readonly.mjs
CHANGED
|
@@ -1,37 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MESSAGE_DEACTIVATED_READONLY, SUBSCRIPTION_TYPE_FROZEN, SUBSCRIPTION_TYPE_ORIGINAL, SYMBOL_READONLY, SYMBOL_STATE } from "../constants.mjs";
|
|
2
2
|
import { getFrozenValue, getJsonValue, getSignalValue, getStringValue, peekSignalValue } from "../helpers/value.mjs";
|
|
3
|
+
import { deactivateReadonly, getReadonlyActive } from "../helpers/misc.mjs";
|
|
3
4
|
import { subscribeToReadonly } from "../helpers/subscription.mjs";
|
|
4
|
-
|
|
5
|
+
// src/value/readonly.ts
|
|
5
6
|
function Readonly(state, frozen) {
|
|
6
|
-
this[SUBSCRIPTION_TYPE_FROZEN] = frozen;
|
|
7
7
|
this[SYMBOL_STATE] = state;
|
|
8
|
+
this[SYMBOL_READONLY] = {
|
|
9
|
+
active: true,
|
|
10
|
+
name: frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(this, SUBSCRIPTION_TYPE_FROZEN, { value: frozen });
|
|
8
13
|
}
|
|
9
|
-
Readonly.prototype
|
|
14
|
+
Readonly.prototype.deactivate = deactivateReadonly;
|
|
10
15
|
Readonly.prototype.get = getReadonlyValue;
|
|
11
16
|
Readonly.prototype.peek = peekReadonlyValue;
|
|
12
17
|
Readonly.prototype.subscribe = subscribeToReadonly;
|
|
13
18
|
Readonly.prototype.toJSON = getJsonValue;
|
|
14
19
|
Readonly.prototype.toString = getStringValue;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
Object.defineProperties(Readonly.prototype, { active: {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: getReadonlyActive
|
|
23
|
+
} });
|
|
18
24
|
function getReadonlySignal(frozen) {
|
|
25
|
+
const state = this[SYMBOL_STATE];
|
|
26
|
+
if (!state.active) throw new Error(MESSAGE_DEACTIVATED_READONLY);
|
|
19
27
|
const key = frozen === true ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
28
|
+
state.readonlies ??= {};
|
|
29
|
+
state.readonlies[key] ??= new Readonly(state, frozen === true);
|
|
30
|
+
return state.readonlies[key];
|
|
23
31
|
}
|
|
24
32
|
function getReadonlyValue() {
|
|
25
|
-
return handleReadonlyValue(this, false, this
|
|
33
|
+
return handleReadonlyValue(this, false, this.frozen);
|
|
26
34
|
}
|
|
27
35
|
function handleReadonlyValue(instance, peek, frozen, copy) {
|
|
36
|
+
const state = instance[SYMBOL_READONLY];
|
|
28
37
|
let value;
|
|
29
|
-
if (peek) value = peekSignalValue.call(instance, copy === true);
|
|
30
|
-
else value = getSignalValue.call(instance);
|
|
38
|
+
if (peek) value = peekSignalValue.call(state.active ? instance : [instance, state.value], copy === true);
|
|
39
|
+
else value = state.active ? getSignalValue.call(instance) : state.value;
|
|
31
40
|
return frozen ? getFrozenValue(value) : value;
|
|
32
41
|
}
|
|
33
42
|
function peekReadonlyValue(copy) {
|
|
34
|
-
return handleReadonlyValue(this, true, this
|
|
43
|
+
return handleReadonlyValue(this, true, this.frozen, copy);
|
|
35
44
|
}
|
|
36
|
-
|
|
37
|
-
export { getReadonlyInstance, getReadonlySignal };
|
|
45
|
+
export { getReadonlySignal };
|
package/dist/value/signal.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ReactiveOptions, Signal } from "../models.mjs";
|
|
2
|
-
//#region src/value/signal.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Create a reactive value from a function result
|
|
5
4
|
*
|
|
@@ -23,5 +22,4 @@ export declare function signal<Value>(value: Promise<Value>, options?: ReactiveO
|
|
|
23
22
|
* @param options Reactivity options
|
|
24
23
|
* @returns Reactive value
|
|
25
24
|
*/
|
|
26
|
-
export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
27
|
-
//#endregion
|
|
25
|
+
export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
package/dist/value/signal.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NAME_SIGNAL, SYMBOL_STATE } from "../constants.mjs";
|
|
2
2
|
import { emitValue, getJsonValue, getSignalValue, getStringValue, handleSignal, peekSignalValue, updateSignal } from "../helpers/value.mjs";
|
|
3
|
-
import { getState } from "../helpers/misc.mjs";
|
|
3
|
+
import { deactivateReactive, getReactiveActive, getState } from "../helpers/misc.mjs";
|
|
4
4
|
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
5
5
|
import { getReadonlySignal } from "./readonly.mjs";
|
|
6
|
-
|
|
6
|
+
// src/value/signal.ts
|
|
7
7
|
function Signal(value, options) {
|
|
8
|
-
this[SYMBOL_STATE] = getState(void 0, options);
|
|
8
|
+
this[SYMBOL_STATE] = getState(NAME_SIGNAL, void 0, options);
|
|
9
9
|
handleSignal(this, value, setAndEmit);
|
|
10
10
|
}
|
|
11
|
-
Signal.prototype[NAME_MORA] = NAME_SIGNAL;
|
|
12
11
|
Signal.prototype.asReadonly = getReadonlySignal;
|
|
12
|
+
Signal.prototype.deactivate = deactivateReactive;
|
|
13
13
|
Signal.prototype.get = getSignalValue;
|
|
14
14
|
Signal.prototype.peek = peekSignalValue;
|
|
15
15
|
Signal.prototype.set = setSignalValue;
|
|
@@ -17,6 +17,10 @@ Signal.prototype.subscribe = subscribeToSignal;
|
|
|
17
17
|
Signal.prototype.toString = getStringValue;
|
|
18
18
|
Signal.prototype.toJSON = getJsonValue;
|
|
19
19
|
Signal.prototype.update = updateSignalValue;
|
|
20
|
+
Object.defineProperties(Signal.prototype, { active: {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: getReactiveActive
|
|
23
|
+
} });
|
|
20
24
|
function setAndEmit(instance, value) {
|
|
21
25
|
const state = instance[SYMBOL_STATE];
|
|
22
26
|
if (!(state.equal ?? Object.is)(state.value, value)) {
|
|
@@ -33,5 +37,4 @@ function signal(value, options) {
|
|
|
33
37
|
function updateSignalValue(callback) {
|
|
34
38
|
updateSignal(this, callback, setAndEmit);
|
|
35
39
|
}
|
|
36
|
-
//#endregion
|
|
37
40
|
export { signal };
|
package/dist/value/store.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ReactiveOptions, ReactiveStore } from "../models.mjs";
|
|
2
2
|
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
3
|
-
//#region src/value/store.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Create a reactive store from a function result
|
|
6
5
|
*
|
|
@@ -24,5 +23,4 @@ export declare function store<Value extends PlainObject>(value: Promise<Value>,
|
|
|
24
23
|
* @param options Reactivity options
|
|
25
24
|
* @returns Reactive store
|
|
26
25
|
*/
|
|
27
|
-
export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
28
|
-
//#endregion
|
|
26
|
+
export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
package/dist/value/store.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NAME_STORE, SYMBOL_STATE } from "../constants.mjs";
|
|
2
2
|
import { getJsonValue, getStringValue } from "../helpers/value.mjs";
|
|
3
|
-
import { getState } from "../helpers/misc.mjs";
|
|
3
|
+
import { deactivateProxy, getReactiveActive, getState } from "../helpers/misc.mjs";
|
|
4
4
|
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
5
5
|
import { getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
6
6
|
import { getReadonlySignal } from "./readonly.mjs";
|
|
7
|
-
|
|
7
|
+
// src/value/store.ts
|
|
8
8
|
function ReactiveStore(value, options) {
|
|
9
9
|
this[SYMBOL_STATE] = {
|
|
10
|
-
...getState(void 0, options),
|
|
10
|
+
...getState(NAME_STORE, void 0, options),
|
|
11
11
|
isArray: false
|
|
12
12
|
};
|
|
13
13
|
this[SYMBOL_STATE].value = new Proxy({}, { set: (target, property, value) => setValueInProxy(this, target, property, value) });
|
|
14
14
|
setProxyValue.call(this, value);
|
|
15
15
|
}
|
|
16
|
-
ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
|
|
17
16
|
ReactiveStore.prototype.asReadonly = getReadonlySignal;
|
|
17
|
+
ReactiveStore.prototype.deactivate = deactivateProxy;
|
|
18
18
|
ReactiveStore.prototype.get = getValueInProxy;
|
|
19
19
|
ReactiveStore.prototype.notify = notifyProxyValue;
|
|
20
20
|
ReactiveStore.prototype.peek = peekValueInProxy;
|
|
@@ -23,8 +23,11 @@ ReactiveStore.prototype.subscribe = subscribeToProxy;
|
|
|
23
23
|
ReactiveStore.prototype.toJSON = getJsonValue;
|
|
24
24
|
ReactiveStore.prototype.toString = getStringValue;
|
|
25
25
|
ReactiveStore.prototype.update = updateProxyValue;
|
|
26
|
+
Object.defineProperties(ReactiveStore.prototype, { active: {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: getReactiveActive
|
|
29
|
+
} });
|
|
26
30
|
function store(value, options) {
|
|
27
31
|
return new ReactiveStore(value, options);
|
|
28
32
|
}
|
|
29
|
-
//#endregion
|
|
30
33
|
export { store };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -39,21 +39,14 @@
|
|
|
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.222"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^26.6",
|
|
46
|
-
"@vitest/coverage-istanbul": "5
|
|
46
|
+
"@vitest/coverage-istanbul": "^5",
|
|
47
47
|
"jsdom": "^30.1",
|
|
48
48
|
"tsdown": "^0.23",
|
|
49
49
|
"typescript": "^7",
|
|
50
|
-
"vite": "
|
|
51
|
-
|
|
52
|
-
"vitest": "5.0.1"
|
|
53
|
-
},
|
|
54
|
-
"overrides": {
|
|
55
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
|
|
56
|
-
"vitest": "5.0.1"
|
|
57
|
-
},
|
|
58
|
-
"packageManager": "npm@11.19.0"
|
|
50
|
+
"vite-plus": "^1.4"
|
|
51
|
+
}
|
|
59
52
|
}
|
package/src/batch.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {attempt} from '@oscarpalmer/atoms/result';
|
|
2
1
|
import {BATCH} from './constants';
|
|
3
2
|
import {runEffect} from './effect';
|
|
4
3
|
import {getFrozenValue, peekSignalValue} from './helpers/value';
|
|
5
|
-
import type {StoredSubscription} from './models';
|
|
4
|
+
import type {EffectState, StoredSubscription} from './models';
|
|
6
5
|
|
|
7
6
|
// #region Functions
|
|
8
7
|
|
|
@@ -21,7 +20,12 @@ export function flushHandlers(): void {
|
|
|
21
20
|
BATCH.handlers.clear();
|
|
22
21
|
|
|
23
22
|
for (let index = 0; index < length; index += 1) {
|
|
24
|
-
const [, handler] = handlers[index];
|
|
23
|
+
const [owner, handler] = handlers[index];
|
|
24
|
+
|
|
25
|
+
if (!owner.active) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
const subscription = handler as StoredSubscription;
|
|
26
30
|
|
|
27
31
|
if (typeof subscription.frozen === 'boolean') {
|
|
@@ -31,7 +35,7 @@ export function flushHandlers(): void {
|
|
|
31
35
|
: peekSignalValue.call(subscription.instance, subscription.copy),
|
|
32
36
|
);
|
|
33
37
|
} else {
|
|
34
|
-
runEffect(handler);
|
|
38
|
+
runEffect(handler as EffectState);
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
}
|
package/src/constants.ts
CHANGED
|
@@ -17,6 +17,22 @@ export const BATCH: Batch = {
|
|
|
17
17
|
handlers: new Map(),
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export const MESSAGE_COMPUTED_CALLBACK = 'Computed callback must be a function';
|
|
21
|
+
|
|
22
|
+
export const MESSAGE_DEACTIVATED_ARRAY_FILTER = 'Cannot filter an inactive reactive array';
|
|
23
|
+
|
|
24
|
+
export const MESSAGE_DEACTIVATED_ARRAY_MAP = 'Cannot map an inactive reactive array';
|
|
25
|
+
|
|
26
|
+
export const MESSAGE_DEACTIVATED_ARRAY_SELECT = 'Cannot select from an inactive reactive array';
|
|
27
|
+
|
|
28
|
+
export const MESSAGE_DEACTIVATED_READONLY = 'Cannot create readonly variant of inactive signal';
|
|
29
|
+
|
|
30
|
+
export const MESSAGE_DEACTIVATED_SUBSCRIPTION = 'Cannot subscribe to inactive signal';
|
|
31
|
+
|
|
32
|
+
export const MESSAGE_EFFECT_CALLBACK = 'Effect callback must be a function';
|
|
33
|
+
|
|
34
|
+
export const MESSAGE_UPDATE_CALLBACK = 'Update callback must be a function';
|
|
35
|
+
|
|
20
36
|
export const METHODS_AFFECTING_LENGTH: Set<string | symbol> = new Set([
|
|
21
37
|
'pop',
|
|
22
38
|
'push',
|
|
@@ -39,8 +55,6 @@ export const NAME_COMPUTED = 'computed';
|
|
|
39
55
|
|
|
40
56
|
export const NAME_EFFECT = 'effect';
|
|
41
57
|
|
|
42
|
-
export const NAME_MORA = '$mora';
|
|
43
|
-
|
|
44
58
|
export const NAME_READONLY = 'readonly';
|
|
45
59
|
|
|
46
60
|
export const NAME_SIGNAL = 'signal';
|
|
@@ -49,32 +63,28 @@ export const NAME_STORE = 'store';
|
|
|
49
63
|
|
|
50
64
|
export const NAME_SUBSCRIPTION = 'subscription';
|
|
51
65
|
|
|
52
|
-
export const NAME_ALL: Set<string> = new Set([
|
|
53
|
-
NAME_ARRAY,
|
|
54
|
-
NAME_COMPUTED,
|
|
55
|
-
NAME_READONLY,
|
|
56
|
-
NAME_SIGNAL,
|
|
57
|
-
NAME_STORE,
|
|
58
|
-
]);
|
|
66
|
+
export const NAME_ALL: Set<string> = new Set([NAME_ARRAY, NAME_COMPUTED, NAME_SIGNAL, NAME_STORE]);
|
|
59
67
|
|
|
60
68
|
export const PROPERTY_LENGTH = 'length';
|
|
61
69
|
|
|
62
|
-
export const SYMBOL_EFFECT: symbol = Symbol('effect');
|
|
70
|
+
export const SYMBOL_EFFECT: unique symbol = Symbol('effect');
|
|
71
|
+
|
|
72
|
+
export const SYMBOL_READONLY: unique symbol = Symbol('readonly');
|
|
63
73
|
|
|
64
|
-
export const SYMBOL_STATE: symbol = Symbol('state');
|
|
74
|
+
export const SYMBOL_STATE: unique symbol = Symbol('state');
|
|
65
75
|
|
|
66
76
|
export const SUBSCRIPTION_PROPERTY: SubscriptionProperty = {
|
|
67
|
-
key:
|
|
77
|
+
key: '$mora',
|
|
68
78
|
value: NAME_SUBSCRIPTION,
|
|
69
79
|
};
|
|
70
80
|
|
|
71
|
-
export const SUBSCRIPTION_TYPE_COPY
|
|
81
|
+
export const SUBSCRIPTION_TYPE_COPY = 'copy' as const;
|
|
72
82
|
|
|
73
|
-
export const SUBSCRIPTION_TYPE_FROZEN
|
|
83
|
+
export const SUBSCRIPTION_TYPE_FROZEN = 'frozen' as const;
|
|
74
84
|
|
|
75
|
-
export const SUBSCRIPTION_TYPE_ORIGINAL
|
|
85
|
+
export const SUBSCRIPTION_TYPE_ORIGINAL = 'original' as const;
|
|
76
86
|
|
|
77
|
-
export const SUBSCRIPTION_TYPE_READONLY
|
|
87
|
+
export const SUBSCRIPTION_TYPE_READONLY = 'readonly' as const;
|
|
78
88
|
|
|
79
89
|
export const SUBSCRIPTION_TYPES_COPY: Set<SubscriptionType> = new Set([
|
|
80
90
|
SUBSCRIPTION_TYPE_COPY,
|
package/src/effect.ts
CHANGED
|
@@ -1,22 +1,40 @@
|
|
|
1
|
+
import {noop} from '@oscarpalmer/atoms/function';
|
|
1
2
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import type {Effect, EffectState} from './models';
|
|
3
|
+
import {ACTIVE, BATCH, MESSAGE_EFFECT_CALLBACK, NAME_EFFECT, SYMBOL_STATE} from './constants';
|
|
4
|
+
import type {Effect, EffectState, InternalEffect} from './models';
|
|
5
5
|
|
|
6
6
|
// #region Instance
|
|
7
7
|
|
|
8
|
-
function Effect(this:
|
|
9
|
-
this[SYMBOL_STATE] = {
|
|
8
|
+
function Effect(this: InternalEffect, callback: GenericCallback): void {
|
|
9
|
+
this[SYMBOL_STATE] = {
|
|
10
|
+
callback,
|
|
11
|
+
active: true,
|
|
12
|
+
name: NAME_EFFECT,
|
|
13
|
+
};
|
|
10
14
|
|
|
11
15
|
runEffect(this[SYMBOL_STATE]);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
|
-
Effect.prototype
|
|
18
|
+
Effect.prototype.stop = stopEffect;
|
|
19
|
+
|
|
20
|
+
Object.defineProperties(Effect.prototype, {
|
|
21
|
+
active: {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: getActive,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
15
26
|
|
|
16
27
|
// #endregion
|
|
17
28
|
|
|
18
29
|
// #region Functions
|
|
19
30
|
|
|
31
|
+
export function deactivateEffect(state: EffectState): void {
|
|
32
|
+
state.active = false;
|
|
33
|
+
state.callback = noop;
|
|
34
|
+
|
|
35
|
+
BATCH.handlers.delete(state);
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
/**
|
|
21
39
|
* Create an effect
|
|
22
40
|
*
|
|
@@ -25,12 +43,16 @@ Effect.prototype[NAME_MORA] = NAME_EFFECT;
|
|
|
25
43
|
*/
|
|
26
44
|
export function effect(callback: GenericCallback): Effect {
|
|
27
45
|
if (typeof callback !== 'function') {
|
|
28
|
-
throw new TypeError(
|
|
46
|
+
throw new TypeError(MESSAGE_EFFECT_CALLBACK);
|
|
29
47
|
}
|
|
30
48
|
|
|
31
49
|
return getEffect(callback)[0];
|
|
32
50
|
}
|
|
33
51
|
|
|
52
|
+
function getActive(this: InternalEffect): boolean {
|
|
53
|
+
return this[SYMBOL_STATE].active;
|
|
54
|
+
}
|
|
55
|
+
|
|
34
56
|
function getEffect(callback: GenericCallback): [Effect, EffectState] {
|
|
35
57
|
// @ts-expect-error All good, no worries :-)
|
|
36
58
|
const instance = new Effect(callback);
|
|
@@ -54,4 +76,12 @@ export function runEffect(state: EffectState): void {
|
|
|
54
76
|
}
|
|
55
77
|
}
|
|
56
78
|
|
|
79
|
+
function stopEffect(this: InternalEffect): void {
|
|
80
|
+
const state = this[SYMBOL_STATE];
|
|
81
|
+
|
|
82
|
+
if (state.active) {
|
|
83
|
+
deactivateEffect(state);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
57
87
|
// #endregion
|