@oscarpalmer/mora 0.37.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 -3
- package/dist/constants.d.mts +16 -12
- package/dist/constants.mjs +12 -6
- package/dist/effect.d.mts +2 -4
- package/dist/effect.mjs +27 -7
- 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 -10
- 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 +19 -12
- package/dist/models.d.mts +39 -7
- package/dist/mora.full.mjs +565 -234
- package/dist/value/array.d.mts +1 -4
- package/dist/value/array.mjs +47 -23
- package/dist/value/computed.d.mts +1 -4
- 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 -4
- package/dist/value/signal.mjs +9 -6
- package/dist/value/store.d.mts +1 -4
- package/dist/value/store.mjs +9 -6
- package/package.json +7 -10
- package/src/batch.ts +8 -3
- package/src/constants.ts +31 -20
- package/src/effect.ts +37 -6
- package/src/helpers/is.ts +18 -8
- package/src/helpers/misc.ts +121 -2
- package/src/helpers/proxy.ts +59 -8
- package/src/helpers/subscription.ts +34 -4
- package/src/helpers/value.ts +49 -14
- package/src/models.ts +43 -4
- package/src/value/array.ts +103 -24
- package/src/value/computed.ts +30 -11
- package/src/value/readonly.ts +38 -33
- package/src/value/signal.ts +12 -6
- package/src/value/store.ts +13 -7
- 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,9 +5,17 @@ import type {
|
|
|
5
5
|
Key,
|
|
6
6
|
PlainObject,
|
|
7
7
|
} from '@oscarpalmer/atoms/models';
|
|
8
|
+
import {getNumber} from '@oscarpalmer/atoms/number';
|
|
9
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
8
10
|
import {startBatch, stopBatch} from '../batch';
|
|
9
|
-
import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
|
|
10
|
-
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';
|
|
11
19
|
import {internalComputed} from '../value/computed';
|
|
12
20
|
import {emitValue, getSignalValue, peekSignalValue} from './value';
|
|
13
21
|
|
|
@@ -21,7 +29,7 @@ export function getReactiveValueInProxy(
|
|
|
21
29
|
|
|
22
30
|
state.mapped ??= new Map();
|
|
23
31
|
|
|
24
|
-
const mapKey =
|
|
32
|
+
const mapKey = getString(key);
|
|
25
33
|
|
|
26
34
|
let item = state.mapped.get(mapKey);
|
|
27
35
|
|
|
@@ -39,9 +47,15 @@ export function getReactiveValueInProxy(
|
|
|
39
47
|
}
|
|
40
48
|
|
|
41
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
|
+
|
|
42
56
|
let signal: InternalComputed | undefined;
|
|
43
57
|
|
|
44
|
-
if (
|
|
58
|
+
if (state.isArray ? typeof first === 'number' : isKey(first)) {
|
|
45
59
|
signal = getReactiveValueInProxy(this, first as Key);
|
|
46
60
|
}
|
|
47
61
|
|
|
@@ -49,7 +63,7 @@ export function getValueInProxy(this: InternalArray | InternalStore, first?: unk
|
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
function isProxyKey(isArray: boolean, value: unknown): value is Key {
|
|
52
|
-
return isArray
|
|
66
|
+
return (isArray && typeof value === 'number') || isKey(value);
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
|
|
@@ -59,6 +73,10 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
|
|
|
59
73
|
export function notifyProxyValue(this: InternalArray | InternalStore): void {
|
|
60
74
|
const state = this[SYMBOL_STATE];
|
|
61
75
|
|
|
76
|
+
if (!state.active) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
state.mapped ??= new Map();
|
|
63
81
|
|
|
64
82
|
const values = [...state.mapped.values()];
|
|
@@ -156,6 +174,10 @@ export function setProxyValue(
|
|
|
156
174
|
): void {
|
|
157
175
|
const state = this[SYMBOL_STATE];
|
|
158
176
|
|
|
177
|
+
if (!state.active) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
159
181
|
if (state.isArray && first === PROPERTY_LENGTH) {
|
|
160
182
|
(state.value as unknown[]).length = second as number;
|
|
161
183
|
|
|
@@ -231,8 +253,12 @@ export function setValueInProxy(
|
|
|
231
253
|
): boolean {
|
|
232
254
|
const state = instance[SYMBOL_STATE];
|
|
233
255
|
|
|
256
|
+
if (!state.active) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
234
260
|
if (state.isArray) {
|
|
235
|
-
const isIndex = !Number.isNaN(
|
|
261
|
+
const isIndex = !Number.isNaN(getNumber(property));
|
|
236
262
|
const isLength = property === PROPERTY_LENGTH;
|
|
237
263
|
|
|
238
264
|
if (!(isIndex || isLength)) {
|
|
@@ -255,12 +281,37 @@ export function setValueInProxy(
|
|
|
255
281
|
return true;
|
|
256
282
|
}
|
|
257
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
|
+
|
|
258
307
|
export function updateProxyValue(this: InternalArray | InternalStore, callback: unknown): void {
|
|
259
308
|
if (typeof callback !== 'function') {
|
|
260
|
-
throw new TypeError(
|
|
309
|
+
throw new TypeError(MESSAGE_UPDATE_CALLBACK);
|
|
261
310
|
}
|
|
262
311
|
|
|
263
|
-
|
|
312
|
+
if (this[SYMBOL_STATE].active) {
|
|
313
|
+
setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
|
|
314
|
+
}
|
|
264
315
|
}
|
|
265
316
|
|
|
266
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,4 +1,5 @@
|
|
|
1
1
|
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {min, round} from '@oscarpalmer/atoms/math';
|
|
2
3
|
import {flushHandlers} from '../batch';
|
|
3
4
|
import {
|
|
4
5
|
ACTIVE,
|
|
@@ -6,13 +7,21 @@ import {
|
|
|
6
7
|
ARRAY_PEEK,
|
|
7
8
|
ARRAY_THRESHOLD,
|
|
8
9
|
BATCH,
|
|
10
|
+
MESSAGE_UPDATE_CALLBACK,
|
|
9
11
|
SUBSCRIPTION_TYPE_FROZEN,
|
|
10
12
|
SUBSCRIPTION_TYPES,
|
|
11
13
|
SUBSCRIPTION_TYPES_COPY,
|
|
12
14
|
SYMBOL_EFFECT,
|
|
15
|
+
SYMBOL_READONLY,
|
|
13
16
|
SYMBOL_STATE,
|
|
14
17
|
} from '../constants';
|
|
15
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
InternalArray,
|
|
20
|
+
InternalComputed,
|
|
21
|
+
InternalReadonly,
|
|
22
|
+
InternalStateful,
|
|
23
|
+
InternalStore,
|
|
24
|
+
} from '../models';
|
|
16
25
|
|
|
17
26
|
// #region Types
|
|
18
27
|
|
|
@@ -27,13 +36,21 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
|
|
|
27
36
|
|
|
28
37
|
if (state.computeds != null && state.computeds.size > 0) {
|
|
29
38
|
for (const computed of state.computeds) {
|
|
30
|
-
computed.
|
|
39
|
+
if (computed.instance.active) {
|
|
40
|
+
computed.dirty = true;
|
|
41
|
+
} else {
|
|
42
|
+
state.computeds.delete(computed);
|
|
43
|
+
}
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
if (state.effects != null && state.effects.size > 0) {
|
|
35
48
|
for (const effect of state.effects) {
|
|
36
|
-
|
|
49
|
+
if (effect.active) {
|
|
50
|
+
BATCH.handlers.set(effect, effect);
|
|
51
|
+
} else {
|
|
52
|
+
state.effects.delete(effect);
|
|
53
|
+
}
|
|
37
54
|
}
|
|
38
55
|
}
|
|
39
56
|
|
|
@@ -43,9 +60,9 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
|
|
|
43
60
|
const mapped = state.mapped as Map<unknown, InternalComputed>;
|
|
44
61
|
|
|
45
62
|
for (const [, item] of mapped) {
|
|
46
|
-
const
|
|
63
|
+
const {instance} = item[SYMBOL_EFFECT];
|
|
47
64
|
|
|
48
|
-
BATCH.handlers.set(
|
|
65
|
+
BATCH.handlers.set(instance, instance);
|
|
49
66
|
}
|
|
50
67
|
}
|
|
51
68
|
|
|
@@ -86,8 +103,8 @@ export function equalArrays(
|
|
|
86
103
|
let offset = 0;
|
|
87
104
|
|
|
88
105
|
if (length >= ARRAY_THRESHOLD) {
|
|
89
|
-
offset =
|
|
90
|
-
offset = offset
|
|
106
|
+
offset = round(length / ARRAY_PEEK);
|
|
107
|
+
offset = min([offset, ARRAY_OFFSET]);
|
|
91
108
|
|
|
92
109
|
for (let index = 0; index < offset; index += 1) {
|
|
93
110
|
if (
|
|
@@ -124,13 +141,21 @@ export function getFrozenValue(value: unknown): unknown {
|
|
|
124
141
|
return frozen;
|
|
125
142
|
}
|
|
126
143
|
|
|
127
|
-
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
|
+
|
|
128
149
|
return this[SYMBOL_STATE].value;
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
export function getSignalValue(this: InternalStateful): unknown {
|
|
132
153
|
const state = this[SYMBOL_STATE];
|
|
133
154
|
|
|
155
|
+
if (!state.active) {
|
|
156
|
+
return state.value;
|
|
157
|
+
}
|
|
158
|
+
|
|
134
159
|
if (ACTIVE.computed != null) {
|
|
135
160
|
state.computeds ??= new Set();
|
|
136
161
|
|
|
@@ -146,10 +171,14 @@ export function getSignalValue(this: InternalStateful): unknown {
|
|
|
146
171
|
return state.value;
|
|
147
172
|
}
|
|
148
173
|
|
|
149
|
-
export function getStringValue(this: InternalStateful, json?: boolean): string {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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);
|
|
153
182
|
}
|
|
154
183
|
|
|
155
184
|
export function handleSignal(
|
|
@@ -161,6 +190,10 @@ export function handleSignal(
|
|
|
161
190
|
): void {
|
|
162
191
|
const state = instance[SYMBOL_STATE];
|
|
163
192
|
|
|
193
|
+
if (!state.active) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
164
197
|
try {
|
|
165
198
|
let actual = typeof origin === 'function' ? (origin as () => unknown)() : origin;
|
|
166
199
|
|
|
@@ -215,10 +248,12 @@ export function updateSignal(
|
|
|
215
248
|
setValue: (instance: InternalStateful, value: unknown) => void,
|
|
216
249
|
): void {
|
|
217
250
|
if (typeof callback !== 'function') {
|
|
218
|
-
throw new TypeError(
|
|
251
|
+
throw new TypeError(MESSAGE_UPDATE_CALLBACK);
|
|
219
252
|
}
|
|
220
253
|
|
|
221
|
-
|
|
254
|
+
if (instance[SYMBOL_STATE].active) {
|
|
255
|
+
handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
|
|
256
|
+
}
|
|
222
257
|
}
|
|
223
258
|
|
|
224
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 = {
|
|
@@ -35,11 +46,19 @@ export type InternalArray = {
|
|
|
35
46
|
|
|
36
47
|
export type InternalComputed = {
|
|
37
48
|
[SYMBOL_EFFECT]: ComputedEffect;
|
|
49
|
+
} & Computed<unknown> &
|
|
50
|
+
InternalStateful;
|
|
51
|
+
|
|
52
|
+
export type InternalEffect = {
|
|
53
|
+
[SYMBOL_STATE]: EffectState;
|
|
54
|
+
} & Effect;
|
|
55
|
+
|
|
56
|
+
export type InternalReactive = {
|
|
38
57
|
[SYMBOL_STATE]: SignalState;
|
|
39
|
-
} &
|
|
58
|
+
} & Reactive<unknown>;
|
|
40
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
|