@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/src/helpers/is.ts
CHANGED
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
NAME_ARRAY,
|
|
5
5
|
NAME_COMPUTED,
|
|
6
6
|
NAME_EFFECT,
|
|
7
|
-
NAME_MORA,
|
|
8
7
|
NAME_READONLY,
|
|
9
8
|
NAME_SIGNAL,
|
|
10
9
|
NAME_STORE,
|
|
10
|
+
SYMBOL_READONLY,
|
|
11
|
+
SYMBOL_STATE,
|
|
11
12
|
} from '../constants';
|
|
12
13
|
import type {
|
|
13
14
|
Computed,
|
|
@@ -41,13 +42,22 @@ export function isEffect(value: unknown): value is Effect {
|
|
|
41
42
|
return isMora<Effect>(value, NAME_EFFECT);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
function isMora<Instance>(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
function isMora<Instance>(input: unknown, value: string | Set<string>): input is Instance {
|
|
46
|
+
if (typeof input !== 'object' || input === null) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (value === NAME_READONLY) {
|
|
51
|
+
return SYMBOL_READONLY in input;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!(SYMBOL_STATE in input)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const state = (input as PlainObject)[SYMBOL_STATE] as PlainObject;
|
|
59
|
+
|
|
60
|
+
return typeof value === 'string' ? state.name === value : value.has(state.name as never);
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
/**
|
package/src/helpers/misc.ts
CHANGED
|
@@ -1,10 +1,129 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {noop} from '@oscarpalmer/atoms/function';
|
|
2
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {SYMBOL_EFFECT, SYMBOL_READONLY, SYMBOL_STATE} from '../constants';
|
|
4
|
+
import {deactivateEffect} from '../effect';
|
|
5
|
+
import type {
|
|
6
|
+
InternalArray,
|
|
7
|
+
InternalComputed,
|
|
8
|
+
InternalReactive,
|
|
9
|
+
InternalReadonly,
|
|
10
|
+
InternalStore,
|
|
11
|
+
ReactiveOptions,
|
|
12
|
+
ReactiveState,
|
|
13
|
+
} from '../models';
|
|
14
|
+
import {peekSignalValue} from './value';
|
|
2
15
|
|
|
3
16
|
// #region Functions
|
|
4
17
|
|
|
5
|
-
export function
|
|
18
|
+
export function deactivateComputed(this: InternalComputed): void {
|
|
19
|
+
const state = this[SYMBOL_STATE];
|
|
20
|
+
|
|
21
|
+
if (!state.active) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
deactivateEffect(this[SYMBOL_EFFECT].instance);
|
|
26
|
+
|
|
27
|
+
deactivateReactive.call(this);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function deactivateProxy(this: InternalArray | InternalStore): void {
|
|
31
|
+
const state = this[SYMBOL_STATE];
|
|
32
|
+
|
|
33
|
+
if (!state.active) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (state.derived != null) {
|
|
38
|
+
for (const computed of state.derived) {
|
|
39
|
+
computed.deactivate();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
state.derived.clear();
|
|
43
|
+
|
|
44
|
+
state.derived = undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (state.mapped != null) {
|
|
48
|
+
for (const [, computed] of state.mapped) {
|
|
49
|
+
computed.deactivate();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
state.mapped.clear();
|
|
53
|
+
|
|
54
|
+
state.mapped = undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
deactivateReactive.call(this);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function deactivateReactive(this: InternalReactive): void {
|
|
61
|
+
const state = this[SYMBOL_STATE];
|
|
62
|
+
|
|
63
|
+
if (!state.active) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
state.active = false;
|
|
68
|
+
|
|
69
|
+
state.computeds?.clear();
|
|
70
|
+
state.effects?.clear();
|
|
71
|
+
state.promises?.clear();
|
|
72
|
+
state.readonlies?.frozen?.deactivate();
|
|
73
|
+
state.readonlies?.original?.deactivate();
|
|
74
|
+
state.subscriptions?.clear();
|
|
75
|
+
|
|
76
|
+
state.equal = noop as never;
|
|
77
|
+
state.promise = undefined;
|
|
78
|
+
|
|
79
|
+
state.computeds = undefined;
|
|
80
|
+
state.effects = undefined;
|
|
81
|
+
state.promises = undefined;
|
|
82
|
+
state.readonlies = undefined;
|
|
83
|
+
state.subscriptions = undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function deactivateReadonly(this: InternalReadonly): void {
|
|
87
|
+
const readonly = this[SYMBOL_READONLY];
|
|
88
|
+
const signal = this[SYMBOL_STATE];
|
|
89
|
+
|
|
90
|
+
if (!readonly.active) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
(signal.readonlies as PlainObject)![readonly.name] = undefined;
|
|
95
|
+
|
|
96
|
+
if (readonly.subscriptions != null) {
|
|
97
|
+
for (const subscription of readonly.subscriptions) {
|
|
98
|
+
subscription.unsubscribe();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
readonly.subscriptions.clear();
|
|
102
|
+
|
|
103
|
+
readonly.subscriptions = undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
readonly.active = false;
|
|
107
|
+
readonly.value = peekSignalValue.call(this, true);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getReactiveActive(this: InternalReactive): boolean {
|
|
111
|
+
return this[SYMBOL_STATE].active;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function getReadonlyActive(this: InternalReadonly): boolean {
|
|
115
|
+
return this[SYMBOL_READONLY].active;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getState(
|
|
119
|
+
name: string,
|
|
120
|
+
value: unknown,
|
|
121
|
+
options?: ReactiveOptions<unknown>,
|
|
122
|
+
): ReactiveState {
|
|
6
123
|
return {
|
|
124
|
+
name,
|
|
7
125
|
value,
|
|
126
|
+
active: true,
|
|
8
127
|
equal:
|
|
9
128
|
typeof options === 'object' && typeof options?.equal === 'function'
|
|
10
129
|
? options.equal
|
package/src/helpers/proxy.ts
CHANGED
|
@@ -5,10 +5,17 @@ import type {
|
|
|
5
5
|
Key,
|
|
6
6
|
PlainObject,
|
|
7
7
|
} from '@oscarpalmer/atoms/models';
|
|
8
|
-
import {
|
|
8
|
+
import {getNumber} from '@oscarpalmer/atoms/number';
|
|
9
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
9
10
|
import {startBatch, stopBatch} from '../batch';
|
|
10
|
-
import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
|
|
11
|
-
import type {
|
|
11
|
+
import {MESSAGE_UPDATE_CALLBACK, PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
|
|
12
|
+
import type {
|
|
13
|
+
Computed,
|
|
14
|
+
InternalArray,
|
|
15
|
+
InternalComputed,
|
|
16
|
+
InternalStore,
|
|
17
|
+
ReactiveProxyState,
|
|
18
|
+
} from '../models';
|
|
12
19
|
import {internalComputed} from '../value/computed';
|
|
13
20
|
import {emitValue, getSignalValue, peekSignalValue} from './value';
|
|
14
21
|
|
|
@@ -22,7 +29,7 @@ export function getReactiveValueInProxy(
|
|
|
22
29
|
|
|
23
30
|
state.mapped ??= new Map();
|
|
24
31
|
|
|
25
|
-
const mapKey =
|
|
32
|
+
const mapKey = getString(key);
|
|
26
33
|
|
|
27
34
|
let item = state.mapped.get(mapKey);
|
|
28
35
|
|
|
@@ -40,9 +47,15 @@ export function getReactiveValueInProxy(
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export function getValueInProxy(this: InternalArray | InternalStore, first?: unknown): unknown {
|
|
50
|
+
const state = this[SYMBOL_STATE];
|
|
51
|
+
|
|
52
|
+
if (!state.active) {
|
|
53
|
+
return peekValueInProxy.call(this, first);
|
|
54
|
+
}
|
|
55
|
+
|
|
43
56
|
let signal: InternalComputed | undefined;
|
|
44
57
|
|
|
45
|
-
if (
|
|
58
|
+
if (state.isArray ? typeof first === 'number' : isKey(first)) {
|
|
46
59
|
signal = getReactiveValueInProxy(this, first as Key);
|
|
47
60
|
}
|
|
48
61
|
|
|
@@ -50,7 +63,7 @@ export function getValueInProxy(this: InternalArray | InternalStore, first?: unk
|
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
function isProxyKey(isArray: boolean, value: unknown): value is Key {
|
|
53
|
-
return isArray
|
|
66
|
+
return (isArray && typeof value === 'number') || isKey(value);
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
|
|
@@ -60,6 +73,10 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
|
|
|
60
73
|
export function notifyProxyValue(this: InternalArray | InternalStore): void {
|
|
61
74
|
const state = this[SYMBOL_STATE];
|
|
62
75
|
|
|
76
|
+
if (!state.active) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
63
80
|
state.mapped ??= new Map();
|
|
64
81
|
|
|
65
82
|
const values = [...state.mapped.values()];
|
|
@@ -157,6 +174,10 @@ export function setProxyValue(
|
|
|
157
174
|
): void {
|
|
158
175
|
const state = this[SYMBOL_STATE];
|
|
159
176
|
|
|
177
|
+
if (!state.active) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
160
181
|
if (state.isArray && first === PROPERTY_LENGTH) {
|
|
161
182
|
(state.value as unknown[]).length = second as number;
|
|
162
183
|
|
|
@@ -232,8 +253,12 @@ export function setValueInProxy(
|
|
|
232
253
|
): boolean {
|
|
233
254
|
const state = instance[SYMBOL_STATE];
|
|
234
255
|
|
|
256
|
+
if (!state.active) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
235
260
|
if (state.isArray) {
|
|
236
|
-
const isIndex = !Number.isNaN(
|
|
261
|
+
const isIndex = !Number.isNaN(getNumber(property));
|
|
237
262
|
const isLength = property === PROPERTY_LENGTH;
|
|
238
263
|
|
|
239
264
|
if (!(isIndex || isLength)) {
|
|
@@ -256,12 +281,37 @@ export function setValueInProxy(
|
|
|
256
281
|
return true;
|
|
257
282
|
}
|
|
258
283
|
|
|
284
|
+
export function updateProxyDerivations(
|
|
285
|
+
instance: InternalArray | InternalStore,
|
|
286
|
+
value: Computed<unknown[]>,
|
|
287
|
+
): Computed<unknown[]> {
|
|
288
|
+
const state = instance[SYMBOL_STATE];
|
|
289
|
+
|
|
290
|
+
if (state.derived == null) {
|
|
291
|
+
state.derived = new Set([value]);
|
|
292
|
+
|
|
293
|
+
return value;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
for (const computed of state.derived) {
|
|
297
|
+
if (!computed.active) {
|
|
298
|
+
state.derived.delete(computed);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
state.derived.add(value);
|
|
303
|
+
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
|
|
259
307
|
export function updateProxyValue(this: InternalArray | InternalStore, callback: unknown): void {
|
|
260
308
|
if (typeof callback !== 'function') {
|
|
261
|
-
throw new TypeError(
|
|
309
|
+
throw new TypeError(MESSAGE_UPDATE_CALLBACK);
|
|
262
310
|
}
|
|
263
311
|
|
|
264
|
-
|
|
312
|
+
if (this[SYMBOL_STATE].active) {
|
|
313
|
+
setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
|
|
314
|
+
}
|
|
265
315
|
}
|
|
266
316
|
|
|
267
317
|
// #endregion
|
|
@@ -2,6 +2,7 @@ import {isKey} from '@oscarpalmer/atoms/is';
|
|
|
2
2
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {subscriptions, type Subscription} from '@oscarpalmer/atoms/subscription';
|
|
4
4
|
import {
|
|
5
|
+
MESSAGE_DEACTIVATED_SUBSCRIPTION,
|
|
5
6
|
SUBSCRIPTION_PROPERTY,
|
|
6
7
|
SUBSCRIPTION_TYPE_COPY,
|
|
7
8
|
SUBSCRIPTION_TYPE_FROZEN,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
SUBSCRIPTION_TYPE_READONLY,
|
|
10
11
|
SUBSCRIPTION_TYPES,
|
|
11
12
|
SUBSCRIPTION_TYPES_COPY,
|
|
13
|
+
SYMBOL_READONLY,
|
|
12
14
|
SYMBOL_STATE,
|
|
13
15
|
} from '../constants';
|
|
14
16
|
import type {
|
|
@@ -30,6 +32,10 @@ export function subscribeToProxy(
|
|
|
30
32
|
second?: Subscriber<unknown> | boolean,
|
|
31
33
|
third?: boolean,
|
|
32
34
|
): Subscription {
|
|
35
|
+
if (!this[SYMBOL_STATE].active) {
|
|
36
|
+
throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
if (isKey(first)) {
|
|
34
40
|
return getReactiveValueInProxy(this, first).subscribe(second as Subscriber<unknown>, third);
|
|
35
41
|
}
|
|
@@ -42,12 +48,18 @@ function subscribeToReactive(
|
|
|
42
48
|
type: SubscriptionType,
|
|
43
49
|
subscriber: Subscriber<unknown>,
|
|
44
50
|
): Subscription {
|
|
45
|
-
this[SYMBOL_STATE]
|
|
51
|
+
const state = this[SYMBOL_STATE];
|
|
52
|
+
|
|
53
|
+
if (!state.active) {
|
|
54
|
+
throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
state.subscriptions ??= subscriptions({
|
|
46
58
|
keys: SUBSCRIPTION_TYPES,
|
|
47
59
|
property: SUBSCRIPTION_PROPERTY,
|
|
48
60
|
});
|
|
49
61
|
|
|
50
|
-
const [subscription, existing] =
|
|
62
|
+
const [subscription, existing] = state.subscriptions.create({
|
|
51
63
|
key: type,
|
|
52
64
|
value: subscriber,
|
|
53
65
|
});
|
|
@@ -55,7 +67,7 @@ function subscribeToReactive(
|
|
|
55
67
|
if (!existing) {
|
|
56
68
|
subscriber(
|
|
57
69
|
type === SUBSCRIPTION_TYPE_FROZEN
|
|
58
|
-
? getFrozenValue(
|
|
70
|
+
? getFrozenValue(state.value)
|
|
59
71
|
: peekSignalValue.call(this, SUBSCRIPTION_TYPES_COPY.has(type)),
|
|
60
72
|
subscription,
|
|
61
73
|
);
|
|
@@ -68,11 +80,29 @@ export function subscribeToReadonly(
|
|
|
68
80
|
this: InternalReadonly,
|
|
69
81
|
subscriber: Subscriber<unknown>,
|
|
70
82
|
): Subscription {
|
|
71
|
-
|
|
83
|
+
const state = this[SYMBOL_READONLY];
|
|
84
|
+
|
|
85
|
+
if (!state.active) {
|
|
86
|
+
throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const subscription = subscribeToReactive.call(
|
|
72
90
|
this,
|
|
73
91
|
this.frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY,
|
|
74
92
|
subscriber,
|
|
75
93
|
);
|
|
94
|
+
|
|
95
|
+
state.subscriptions ??= new Set();
|
|
96
|
+
|
|
97
|
+
for (const existing of state.subscriptions) {
|
|
98
|
+
if (!existing.active) {
|
|
99
|
+
state.subscriptions.delete(existing);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
state.subscriptions.add(subscription);
|
|
104
|
+
|
|
105
|
+
return subscription;
|
|
76
106
|
}
|
|
77
107
|
|
|
78
108
|
export function subscribeToSignal(
|
package/src/helpers/value.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import {round} from '@oscarpalmer/atoms/math';
|
|
3
|
-
import {attempt} from '@oscarpalmer/atoms/result';
|
|
2
|
+
import {min, round} from '@oscarpalmer/atoms/math';
|
|
4
3
|
import {flushHandlers} from '../batch';
|
|
5
4
|
import {
|
|
6
5
|
ACTIVE,
|
|
@@ -8,13 +7,21 @@ import {
|
|
|
8
7
|
ARRAY_PEEK,
|
|
9
8
|
ARRAY_THRESHOLD,
|
|
10
9
|
BATCH,
|
|
10
|
+
MESSAGE_UPDATE_CALLBACK,
|
|
11
11
|
SUBSCRIPTION_TYPE_FROZEN,
|
|
12
12
|
SUBSCRIPTION_TYPES,
|
|
13
13
|
SUBSCRIPTION_TYPES_COPY,
|
|
14
14
|
SYMBOL_EFFECT,
|
|
15
|
+
SYMBOL_READONLY,
|
|
15
16
|
SYMBOL_STATE,
|
|
16
17
|
} from '../constants';
|
|
17
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
InternalArray,
|
|
20
|
+
InternalComputed,
|
|
21
|
+
InternalReadonly,
|
|
22
|
+
InternalStateful,
|
|
23
|
+
InternalStore,
|
|
24
|
+
} from '../models';
|
|
18
25
|
|
|
19
26
|
// #region Types
|
|
20
27
|
|
|
@@ -29,13 +36,21 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
|
|
|
29
36
|
|
|
30
37
|
if (state.computeds != null && state.computeds.size > 0) {
|
|
31
38
|
for (const computed of state.computeds) {
|
|
32
|
-
computed.
|
|
39
|
+
if (computed.instance.active) {
|
|
40
|
+
computed.dirty = true;
|
|
41
|
+
} else {
|
|
42
|
+
state.computeds.delete(computed);
|
|
43
|
+
}
|
|
33
44
|
}
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
if (state.effects != null && state.effects.size > 0) {
|
|
37
48
|
for (const effect of state.effects) {
|
|
38
|
-
|
|
49
|
+
if (effect.active) {
|
|
50
|
+
BATCH.handlers.set(effect, effect);
|
|
51
|
+
} else {
|
|
52
|
+
state.effects.delete(effect);
|
|
53
|
+
}
|
|
39
54
|
}
|
|
40
55
|
}
|
|
41
56
|
|
|
@@ -45,9 +60,9 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
|
|
|
45
60
|
const mapped = state.mapped as Map<unknown, InternalComputed>;
|
|
46
61
|
|
|
47
62
|
for (const [, item] of mapped) {
|
|
48
|
-
const
|
|
63
|
+
const {instance} = item[SYMBOL_EFFECT];
|
|
49
64
|
|
|
50
|
-
BATCH.handlers.set(
|
|
65
|
+
BATCH.handlers.set(instance, instance);
|
|
51
66
|
}
|
|
52
67
|
}
|
|
53
68
|
|
|
@@ -89,7 +104,7 @@ export function equalArrays(
|
|
|
89
104
|
|
|
90
105
|
if (length >= ARRAY_THRESHOLD) {
|
|
91
106
|
offset = round(length / ARRAY_PEEK);
|
|
92
|
-
offset = offset
|
|
107
|
+
offset = min([offset, ARRAY_OFFSET]);
|
|
93
108
|
|
|
94
109
|
for (let index = 0; index < offset; index += 1) {
|
|
95
110
|
if (
|
|
@@ -126,13 +141,21 @@ export function getFrozenValue(value: unknown): unknown {
|
|
|
126
141
|
return frozen;
|
|
127
142
|
}
|
|
128
143
|
|
|
129
|
-
export function getJsonValue(this: InternalStateful): unknown {
|
|
144
|
+
export function getJsonValue(this: InternalReadonly | InternalStateful): unknown {
|
|
145
|
+
if (SYMBOL_READONLY in this && !this[SYMBOL_READONLY].active) {
|
|
146
|
+
return this[SYMBOL_READONLY].value;
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
return this[SYMBOL_STATE].value;
|
|
131
150
|
}
|
|
132
151
|
|
|
133
152
|
export function getSignalValue(this: InternalStateful): unknown {
|
|
134
153
|
const state = this[SYMBOL_STATE];
|
|
135
154
|
|
|
155
|
+
if (!state.active) {
|
|
156
|
+
return state.value;
|
|
157
|
+
}
|
|
158
|
+
|
|
136
159
|
if (ACTIVE.computed != null) {
|
|
137
160
|
state.computeds ??= new Set();
|
|
138
161
|
|
|
@@ -148,10 +171,14 @@ export function getSignalValue(this: InternalStateful): unknown {
|
|
|
148
171
|
return state.value;
|
|
149
172
|
}
|
|
150
173
|
|
|
151
|
-
export function getStringValue(this: InternalStateful, json?: boolean): string {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
174
|
+
export function getStringValue(this: InternalReadonly | InternalStateful, json?: boolean): string {
|
|
175
|
+
let {value} = this[SYMBOL_STATE];
|
|
176
|
+
|
|
177
|
+
if (SYMBOL_READONLY in this && !this[SYMBOL_READONLY].active) {
|
|
178
|
+
value = this[SYMBOL_READONLY].value;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return json === true ? JSON.stringify(value) : String(value);
|
|
155
182
|
}
|
|
156
183
|
|
|
157
184
|
export function handleSignal(
|
|
@@ -163,6 +190,10 @@ export function handleSignal(
|
|
|
163
190
|
): void {
|
|
164
191
|
const state = instance[SYMBOL_STATE];
|
|
165
192
|
|
|
193
|
+
if (!state.active) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
166
197
|
try {
|
|
167
198
|
let actual = typeof origin === 'function' ? (origin as () => unknown)() : origin;
|
|
168
199
|
|
|
@@ -217,10 +248,12 @@ export function updateSignal(
|
|
|
217
248
|
setValue: (instance: InternalStateful, value: unknown) => void,
|
|
218
249
|
): void {
|
|
219
250
|
if (typeof callback !== 'function') {
|
|
220
|
-
throw new TypeError(
|
|
251
|
+
throw new TypeError(MESSAGE_UPDATE_CALLBACK);
|
|
221
252
|
}
|
|
222
253
|
|
|
223
|
-
|
|
254
|
+
if (instance[SYMBOL_STATE].active) {
|
|
255
|
+
handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
|
|
256
|
+
}
|
|
224
257
|
}
|
|
225
258
|
|
|
226
259
|
// #endregion
|
package/src/models.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {GenericCallback, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import type {Subscription, Subscriptions} from '@oscarpalmer/atoms/subscription';
|
|
3
|
-
import {SYMBOL_EFFECT, SYMBOL_STATE, type PROPERTY_LENGTH} from './constants';
|
|
3
|
+
import {SYMBOL_EFFECT, SYMBOL_READONLY, SYMBOL_STATE, type PROPERTY_LENGTH} from './constants';
|
|
4
4
|
|
|
5
5
|
// #region Types
|
|
6
6
|
|
|
@@ -23,10 +23,21 @@ export type ComputedEffect = {
|
|
|
23
23
|
notify: boolean;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
export type Effect = {
|
|
26
|
+
export type Effect = {
|
|
27
|
+
/**
|
|
28
|
+
* Is the effect active?
|
|
29
|
+
*/
|
|
30
|
+
get active(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Stop the effect
|
|
33
|
+
*/
|
|
34
|
+
stop(): void;
|
|
35
|
+
};
|
|
27
36
|
|
|
28
37
|
export type EffectState = {
|
|
38
|
+
active: boolean;
|
|
29
39
|
callback: GenericCallback;
|
|
40
|
+
name: string;
|
|
30
41
|
};
|
|
31
42
|
|
|
32
43
|
export type InternalArray = {
|
|
@@ -38,8 +49,16 @@ export type InternalComputed = {
|
|
|
38
49
|
} & Computed<unknown> &
|
|
39
50
|
InternalStateful;
|
|
40
51
|
|
|
52
|
+
export type InternalEffect = {
|
|
53
|
+
[SYMBOL_STATE]: EffectState;
|
|
54
|
+
} & Effect;
|
|
55
|
+
|
|
56
|
+
export type InternalReactive = {
|
|
57
|
+
[SYMBOL_STATE]: SignalState;
|
|
58
|
+
} & Reactive<unknown>;
|
|
59
|
+
|
|
41
60
|
export type InternalReadonly = {
|
|
42
|
-
|
|
61
|
+
[SYMBOL_READONLY]: ReadonlyState;
|
|
43
62
|
} & InternalStateful &
|
|
44
63
|
ReadonlySignal<unknown>;
|
|
45
64
|
|
|
@@ -54,6 +73,16 @@ export type InternalStore = {
|
|
|
54
73
|
} & ReactiveStore<PlainObject>;
|
|
55
74
|
|
|
56
75
|
export type Reactive<Value> = {
|
|
76
|
+
/**
|
|
77
|
+
* Is the signal active?
|
|
78
|
+
*/
|
|
79
|
+
get active(): boolean;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Deactivate the signal, preventing further updates
|
|
83
|
+
*/
|
|
84
|
+
deactivate(): void;
|
|
85
|
+
|
|
57
86
|
/**
|
|
58
87
|
* Get the value
|
|
59
88
|
*
|
|
@@ -323,15 +352,18 @@ export type ReactiveOptions<Value> = {
|
|
|
323
352
|
};
|
|
324
353
|
|
|
325
354
|
export type ReactiveProxyState = {
|
|
355
|
+
derived?: Set<Computed<unknown>>;
|
|
326
356
|
isArray: boolean;
|
|
327
357
|
length?: Signal<number>;
|
|
328
358
|
mapped?: Map<string, InternalComputed>;
|
|
329
359
|
} & SignalState;
|
|
330
360
|
|
|
331
361
|
export type ReactiveState<Value = unknown, Item = Value> = {
|
|
362
|
+
active: boolean;
|
|
332
363
|
computeds?: Set<ComputedEffect>;
|
|
333
364
|
effects?: Set<EffectState>;
|
|
334
365
|
equal?: (first: Item, second: Item) => boolean;
|
|
366
|
+
name: string;
|
|
335
367
|
promise?: Promise<unknown>;
|
|
336
368
|
promises?: Map<Key, Promise<never>>;
|
|
337
369
|
subscriptions?: Subscriptions<GenericCallback>;
|
|
@@ -506,6 +538,13 @@ export type ReadonlySignalValue<Value> = Value extends unknown[]
|
|
|
506
538
|
? Readonly<Value>
|
|
507
539
|
: Value;
|
|
508
540
|
|
|
541
|
+
export type ReadonlyState = {
|
|
542
|
+
active: boolean;
|
|
543
|
+
name: string;
|
|
544
|
+
subscriptions?: Set<Subscription>;
|
|
545
|
+
value?: unknown;
|
|
546
|
+
};
|
|
547
|
+
|
|
509
548
|
export type Signal<Value> = {
|
|
510
549
|
/**
|
|
511
550
|
* Get a readonly version of the signal
|