@oscarpalmer/mora 0.34.0 → 0.35.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/constants.d.mts +2 -2
- package/dist/helpers/proxy.d.mts +8 -8
- package/dist/helpers/proxy.mjs +32 -25
- package/dist/helpers/subscription.d.mts +3 -3
- package/dist/helpers/value.d.mts +9 -8
- package/dist/helpers/value.mjs +15 -11
- package/dist/index.d.mts +2 -2
- package/dist/models.d.mts +40 -37
- package/dist/mora.full.mjs +127 -111
- package/dist/value/array.mjs +53 -41
- package/dist/value/computed.d.mts +2 -2
- package/dist/value/computed.mjs +3 -5
- package/dist/value/readonly.d.mts +2 -2
- package/dist/value/readonly.mjs +16 -19
- package/dist/value/signal.mjs +13 -13
- package/dist/value/store.mjs +4 -6
- package/package.json +1 -1
- package/src/batch.ts +2 -2
- package/src/constants.ts +7 -2
- package/src/helpers/is.ts +1 -3
- package/src/helpers/proxy.ts +68 -57
- package/src/helpers/subscription.ts +7 -6
- package/src/helpers/value.ts +30 -20
- package/src/index.ts +1 -0
- package/src/models.ts +47 -43
- package/src/value/array.ts +81 -64
- package/src/value/computed.ts +12 -16
- package/src/value/readonly.ts +38 -29
- package/src/value/signal.ts +20 -20
- package/src/value/store.ts +4 -7
package/src/models.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type Batch = {
|
|
|
15
15
|
handlers: Map<EffectState | Subscription, EffectState | StoredSubscription>;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export type Computed<Value> = Reactive<Value
|
|
18
|
+
export type Computed<Value> = Reactive<Value>;
|
|
19
19
|
|
|
20
20
|
export type ComputedEffect = {
|
|
21
21
|
dirty: boolean;
|
|
@@ -28,23 +28,46 @@ export type EffectState = {
|
|
|
28
28
|
callback: GenericCallback;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
export type InternalArray = {
|
|
32
|
+
[SYMBOL_STATE]: ReactiveProxyState;
|
|
33
|
+
} & ReactiveArray<unknown>;
|
|
34
|
+
|
|
31
35
|
export type InternalComputed = {
|
|
32
36
|
[SYMBOL_EFFECT]: ComputedEffect;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export type InternalProxy = {
|
|
36
|
-
[SYMBOL_STATE]: ReactiveProxyState;
|
|
37
|
-
};
|
|
37
|
+
[SYMBOL_STATE]: SignalState;
|
|
38
|
+
} & Computed<unknown>;
|
|
38
39
|
|
|
39
40
|
export type InternalReadonly = {
|
|
40
41
|
frozen: boolean;
|
|
41
|
-
} &
|
|
42
|
+
} & InternalStateful &
|
|
43
|
+
ReadonlySignal<unknown>;
|
|
42
44
|
|
|
43
|
-
export type InternalSignal =
|
|
45
|
+
export type InternalSignal = InternalStateful & Signal<unknown>;
|
|
46
|
+
|
|
47
|
+
export type InternalStateful = {
|
|
44
48
|
[SYMBOL_STATE]: SignalState;
|
|
45
49
|
};
|
|
46
50
|
|
|
51
|
+
export type InternalStore = {
|
|
52
|
+
[SYMBOL_STATE]: ReactiveProxyState;
|
|
53
|
+
} & ReactiveStore<PlainObject>;
|
|
54
|
+
|
|
47
55
|
export type Reactive<Value> = {
|
|
56
|
+
/**
|
|
57
|
+
* Get the value
|
|
58
|
+
*
|
|
59
|
+
* @returns Current value
|
|
60
|
+
*/
|
|
61
|
+
get(): Value;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get the value _(without reactivity)_
|
|
65
|
+
*
|
|
66
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
67
|
+
* @returns Current value
|
|
68
|
+
*/
|
|
69
|
+
peek(copy?: boolean): Value;
|
|
70
|
+
|
|
48
71
|
/**
|
|
49
72
|
* _JSON_ representation of the value
|
|
50
73
|
*
|
|
@@ -59,6 +82,15 @@ export type Reactive<Value> = {
|
|
|
59
82
|
* @returns Value as string
|
|
60
83
|
*/
|
|
61
84
|
toString(json?: boolean): string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Subscribe to changes
|
|
88
|
+
*
|
|
89
|
+
* @param subscriber Callback for changes
|
|
90
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
91
|
+
* @returns Subscription
|
|
92
|
+
*/
|
|
93
|
+
subscribe(subscriber: Subscriber<Value>, copy?: boolean): Subscription;
|
|
62
94
|
};
|
|
63
95
|
|
|
64
96
|
export type ReactiveArray<Item> = {
|
|
@@ -292,17 +324,17 @@ export type ReactiveOptions<Value> = {
|
|
|
292
324
|
export type ReactiveProxyState = {
|
|
293
325
|
isArray: boolean;
|
|
294
326
|
length?: Signal<number>;
|
|
295
|
-
mapped?: Map<string, [
|
|
327
|
+
mapped?: Map<string, [InternalComputed, ComputedEffect]>;
|
|
296
328
|
} & SignalState;
|
|
297
329
|
|
|
298
|
-
export type ReactiveState = {
|
|
330
|
+
export type ReactiveState<Value = unknown, Item = Value> = {
|
|
299
331
|
computeds?: Set<ComputedEffect>;
|
|
300
332
|
effects?: Set<EffectState>;
|
|
301
|
-
equal?: (first:
|
|
333
|
+
equal?: (first: Item, second: Item) => boolean;
|
|
302
334
|
promise?: Promise<unknown>;
|
|
303
335
|
promises?: Map<Key, Promise<never>>;
|
|
304
336
|
subscriptions?: Subscriptions<GenericCallback>;
|
|
305
|
-
value:
|
|
337
|
+
value: Value;
|
|
306
338
|
};
|
|
307
339
|
|
|
308
340
|
export type ReactiveStore<Store> = {
|
|
@@ -465,8 +497,7 @@ export type ReadonlySignal<Value> = {
|
|
|
465
497
|
* Is the signal frozen?
|
|
466
498
|
*/
|
|
467
499
|
get frozen(): boolean;
|
|
468
|
-
} & Reactive<Value
|
|
469
|
-
SimpleReactive<Value>;
|
|
500
|
+
} & Reactive<Value>;
|
|
470
501
|
|
|
471
502
|
export type ReadonlySignalValue<Value> = Value extends unknown[]
|
|
472
503
|
? Readonly<Value>
|
|
@@ -506,44 +537,17 @@ export type Signal<Value> = {
|
|
|
506
537
|
* @param callback Callback to update the value
|
|
507
538
|
*/
|
|
508
539
|
update(callback: (value: Value) => Value): void;
|
|
509
|
-
} & Reactive<Value
|
|
510
|
-
SimpleReactive<Value>;
|
|
540
|
+
} & Reactive<Value>;
|
|
511
541
|
|
|
512
542
|
export type SignalState = {
|
|
513
543
|
readonlies?: ReadonlyInstances<unknown>;
|
|
514
544
|
} & ReactiveState;
|
|
515
545
|
|
|
516
|
-
type SimpleReactive<Value> = {
|
|
517
|
-
/**
|
|
518
|
-
* Get the value
|
|
519
|
-
*
|
|
520
|
-
* @returns Current value
|
|
521
|
-
*/
|
|
522
|
-
get(): Value;
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Get the value _(without reactivity)_
|
|
526
|
-
*
|
|
527
|
-
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
528
|
-
* @returns Current value
|
|
529
|
-
*/
|
|
530
|
-
peek(copy?: boolean): Value;
|
|
531
|
-
|
|
532
|
-
/**
|
|
533
|
-
* Subscribe to changes
|
|
534
|
-
*
|
|
535
|
-
* @param subscriber Callback for changes
|
|
536
|
-
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
537
|
-
* @returns Subscription
|
|
538
|
-
*/
|
|
539
|
-
subscribe(subscriber: Subscriber<Value>, copy?: boolean): Subscription;
|
|
540
|
-
};
|
|
541
|
-
|
|
542
546
|
export type StoredSubscription = {
|
|
543
547
|
callback: GenericCallback;
|
|
544
548
|
copy: boolean;
|
|
545
549
|
frozen: boolean;
|
|
546
|
-
instance:
|
|
550
|
+
instance: InternalStateful;
|
|
547
551
|
state: SignalState;
|
|
548
552
|
};
|
|
549
553
|
|
package/src/value/array.ts
CHANGED
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
updateProxyValue,
|
|
19
19
|
} from '../helpers/proxy';
|
|
20
20
|
import {subscribeToProxy} from '../helpers/subscription';
|
|
21
|
-
import {emitValue, equalArrays, getStringValue} from '../helpers/value';
|
|
22
|
-
import type {
|
|
21
|
+
import {emitValue, equalArrays, getJsonValue, getStringValue} from '../helpers/value';
|
|
22
|
+
import type {Computed, InternalArray, ReactiveArray, ReactiveOptions} from '../models';
|
|
23
23
|
import {computed} from './computed';
|
|
24
|
-
import {
|
|
24
|
+
import {getReadonlySignal} from './readonly';
|
|
25
25
|
import {signal} from './signal';
|
|
26
26
|
|
|
27
27
|
// #region Instance
|
|
@@ -35,73 +35,43 @@ function ReactiveArray(this: any, value: unknown, options?: ReactiveOptions<unkn
|
|
|
35
35
|
|
|
36
36
|
this[SYMBOL_STATE].value = new Proxy([], {
|
|
37
37
|
get: (target, property) =>
|
|
38
|
-
METHODS_UPDATE.has(property
|
|
39
|
-
? updateArray(this, property
|
|
38
|
+
METHODS_UPDATE.has(property)
|
|
39
|
+
? updateArray(this, property, target)
|
|
40
40
|
: Reflect.get(target, property),
|
|
41
41
|
set: (target, property, value) => setValueInProxy(this, target, property, value),
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
Object.defineProperty(this, PROPERTY_LENGTH, {
|
|
45
|
-
enumerable: true,
|
|
46
|
-
get: () => this[SYMBOL_STATE].length.get(),
|
|
47
|
-
set: (value: number) => setArrayLength(this[SYMBOL_STATE], value),
|
|
48
|
-
});
|
|
49
|
-
|
|
50
44
|
setProxyValue.call(this, value);
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
ReactiveArray.prototype[NAME_MORA] = NAME_ARRAY;
|
|
54
48
|
|
|
55
|
-
ReactiveArray.prototype
|
|
49
|
+
Object.defineProperty(ReactiveArray.prototype, PROPERTY_LENGTH, {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: getArrayLength,
|
|
52
|
+
set: setArrayLength,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
ReactiveArray.prototype.asReadonly = getReadonlySignal;
|
|
56
56
|
ReactiveArray.prototype.at = getArrayValues;
|
|
57
|
+
ReactiveArray.prototype.clear = clearArrayValues;
|
|
58
|
+
ReactiveArray.prototype.filter = filterArrayValues;
|
|
57
59
|
ReactiveArray.prototype.get = getArrayValues;
|
|
60
|
+
ReactiveArray.prototype.map = mapArrayValues;
|
|
58
61
|
ReactiveArray.prototype.notify = emitProxyValues;
|
|
59
62
|
ReactiveArray.prototype.peek = peekArrayValue;
|
|
63
|
+
ReactiveArray.prototype.pop = popArrayValue;
|
|
64
|
+
ReactiveArray.prototype.push = pushArrayValues;
|
|
65
|
+
ReactiveArray.prototype.select = selectArrayValues;
|
|
66
|
+
ReactiveArray.prototype.shift = shiftArrayValue;
|
|
60
67
|
ReactiveArray.prototype.set = setProxyValue;
|
|
68
|
+
ReactiveArray.prototype.splice = spliceArrayValues;
|
|
61
69
|
ReactiveArray.prototype.subscribe = subscribeToProxy;
|
|
62
70
|
ReactiveArray.prototype.toString = getStringValue;
|
|
71
|
+
ReactiveArray.prototype.toJSON = getJsonValue;
|
|
72
|
+
ReactiveArray.prototype.unshift = unshiftArrayValues;
|
|
63
73
|
ReactiveArray.prototype.update = updateProxyValue;
|
|
64
74
|
|
|
65
|
-
ReactiveArray.prototype.clear = function () {
|
|
66
|
-
this[SYMBOL_STATE].value.length = 0;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
ReactiveArray.prototype.filter = function (callback: never) {
|
|
70
|
-
return computed(() => filter(getArrayValues.call(this) as never, callback) as never);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
ReactiveArray.prototype.map = function (callback: never) {
|
|
74
|
-
return computed(() => (getArrayValues.call(this) as unknown[]).map(callback));
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
ReactiveArray.prototype.pop = function () {
|
|
78
|
-
return this[SYMBOL_STATE].value.pop();
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
ReactiveArray.prototype.push = function (...items: unknown[]) {
|
|
82
|
-
return this[SYMBOL_STATE].value.push(...items);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
ReactiveArray.prototype.select = function (filter: never, map: never) {
|
|
86
|
-
return computed(() => select(getArrayValues.call(this) as unknown[], filter, map));
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
ReactiveArray.prototype.shift = function () {
|
|
90
|
-
return this[SYMBOL_STATE].value.shift();
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
ReactiveArray.prototype.splice = function (from: never, to?: never, ...items: unknown[]) {
|
|
94
|
-
return this[SYMBOL_STATE].value.splice(from, to ?? this[SYMBOL_STATE].value.length, ...items);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
ReactiveArray.prototype.toJSON = function () {
|
|
98
|
-
return this[SYMBOL_STATE].value;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
ReactiveArray.prototype.unshift = function (...items: unknown[]) {
|
|
102
|
-
return this[SYMBOL_STATE].value.unshift(...items);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
75
|
// #endregion
|
|
106
76
|
|
|
107
77
|
// #region Functions
|
|
@@ -144,30 +114,75 @@ export function array(value: unknown, options?: ReactiveOptions<unknown>): React
|
|
|
144
114
|
return new ReactiveArray(value, options);
|
|
145
115
|
}
|
|
146
116
|
|
|
147
|
-
function
|
|
117
|
+
function clearArrayValues(this: InternalArray): void {
|
|
118
|
+
(this[SYMBOL_STATE].value as unknown[]).length = 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function filterArrayValues(this: InternalArray, callback: never): Computed<unknown[]> {
|
|
122
|
+
return computed(() => filter(getArrayValues.call(this) as never, callback) as never);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getArrayLength(this: InternalArray): number {
|
|
126
|
+
return this[SYMBOL_STATE].length!.get();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getArrayValues(this: InternalArray, value?: unknown): unknown {
|
|
148
130
|
return value === PROPERTY_LENGTH
|
|
149
131
|
? this[SYMBOL_STATE].length!.get()
|
|
150
132
|
: getValueInProxy.call(this, value);
|
|
151
133
|
}
|
|
152
134
|
|
|
153
|
-
function
|
|
135
|
+
function mapArrayValues(this: InternalArray, callback: never): Computed<unknown[]> {
|
|
136
|
+
return computed(() => (getArrayValues.call(this) as unknown[]).map(callback));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function peekArrayValue(this: InternalArray, first?: unknown, second?: boolean): unknown {
|
|
154
140
|
return first === PROPERTY_LENGTH
|
|
155
141
|
? this[SYMBOL_STATE].length!.peek()
|
|
156
142
|
: peekValueInProxy.call(this, first, second);
|
|
157
143
|
}
|
|
158
144
|
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
145
|
+
function popArrayValue(this: InternalArray): unknown {
|
|
146
|
+
return (this[SYMBOL_STATE].value as unknown[]).pop();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function pushArrayValues(this: InternalArray, ...items: unknown[]): number {
|
|
150
|
+
return (this[SYMBOL_STATE].value as unknown[]).push(...items);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function selectArrayValues(this: InternalArray, filter: never, map: never): Computed<unknown[]> {
|
|
154
|
+
return computed(() => select(getArrayValues.call(this) as unknown[], filter, map));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function setArrayLength(this: InternalArray, value: number): void {
|
|
158
|
+
const state = this[SYMBOL_STATE];
|
|
159
|
+
const values = state.value as unknown[];
|
|
160
|
+
|
|
161
|
+
if (typeof value === 'number' && !Number.isNaN(value) && value >= 0 && value !== values.length) {
|
|
162
|
+
values.length = value;
|
|
167
163
|
}
|
|
168
164
|
}
|
|
169
165
|
|
|
170
|
-
function
|
|
166
|
+
function shiftArrayValue(this: InternalArray): unknown {
|
|
167
|
+
return (this[SYMBOL_STATE].value as unknown[]).shift();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function spliceArrayValues(
|
|
171
|
+
this: InternalArray,
|
|
172
|
+
from: never,
|
|
173
|
+
to?: never,
|
|
174
|
+
...items: unknown[]
|
|
175
|
+
): unknown[] {
|
|
176
|
+
const values = this[SYMBOL_STATE].value as unknown[];
|
|
177
|
+
|
|
178
|
+
return values.splice(from, to ?? values.length, ...items);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function unshiftArrayValues(this: InternalArray, ...items: unknown[]): number {
|
|
182
|
+
return (this[SYMBOL_STATE].value as unknown[]).unshift(...items);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function updateArray(instance: InternalArray, type: string | symbol, array: unknown[]): unknown {
|
|
171
186
|
const state = instance[SYMBOL_STATE];
|
|
172
187
|
|
|
173
188
|
const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
|
|
@@ -178,7 +193,9 @@ function updateArray(instance: InternalProxy, type: string, array: unknown[]): u
|
|
|
178
193
|
const result = (array[type as never] as (...args: unknown[]) => unknown)(...args);
|
|
179
194
|
|
|
180
195
|
if (
|
|
181
|
-
affectsLength
|
|
196
|
+
affectsLength
|
|
197
|
+
? array.length !== previousLength
|
|
198
|
+
: !equalArrays(previousArray, array, state.equal)
|
|
182
199
|
) {
|
|
183
200
|
emitValue(instance);
|
|
184
201
|
|
package/src/value/computed.ts
CHANGED
|
@@ -14,20 +14,19 @@ import {
|
|
|
14
14
|
import {internalEffect, runEffect} from '../effect';
|
|
15
15
|
import {getState} from '../helpers/misc';
|
|
16
16
|
import {subscribeToSignal} from '../helpers/subscription';
|
|
17
|
-
import {getStringValue,
|
|
17
|
+
import {getJsonValue, getStringValue, handleSignal, peekSignalValue} from '../helpers/value';
|
|
18
18
|
import type {
|
|
19
19
|
Computed,
|
|
20
20
|
ComputedEffect,
|
|
21
|
-
ReactiveOptions,
|
|
22
21
|
InternalComputed,
|
|
23
|
-
|
|
22
|
+
InternalStateful,
|
|
23
|
+
ReactiveOptions,
|
|
24
24
|
} from '../models';
|
|
25
25
|
|
|
26
26
|
// #region Instance
|
|
27
27
|
|
|
28
28
|
function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>) {
|
|
29
29
|
this[SYMBOL_STATE] = getState(undefined, options);
|
|
30
|
-
|
|
31
30
|
this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -36,12 +35,9 @@ Computed.prototype[NAME_MORA] = NAME_COMPUTED;
|
|
|
36
35
|
Computed.prototype.get = getComputedValue;
|
|
37
36
|
Computed.prototype.peek = peekSignalValue;
|
|
38
37
|
Computed.prototype.subscribe = subscribeToSignal;
|
|
38
|
+
Computed.prototype.toJSON = getJsonValue;
|
|
39
39
|
Computed.prototype.toString = getStringValue;
|
|
40
40
|
|
|
41
|
-
Computed.prototype.toJSON = function () {
|
|
42
|
-
return this[SYMBOL_STATE].value;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
41
|
// #endregion
|
|
46
42
|
|
|
47
43
|
// #region Functions
|
|
@@ -57,13 +53,13 @@ export function computed<Value>(
|
|
|
57
53
|
callback: () => Value | Promise<Value>,
|
|
58
54
|
options?: ReactiveOptions<Value>,
|
|
59
55
|
): Computed<Value> {
|
|
60
|
-
return getComputed(callback, options)[0]
|
|
56
|
+
return getComputed(callback, options)[0] as Computed<Value>;
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
function getComputed<Value>(
|
|
64
60
|
callback: GenericCallback,
|
|
65
61
|
options?: ReactiveOptions<Value>,
|
|
66
|
-
): [
|
|
62
|
+
): [InternalComputed, ComputedEffect] {
|
|
67
63
|
if (typeof callback !== 'function') {
|
|
68
64
|
throw new TypeError('Computed callback must be a function');
|
|
69
65
|
}
|
|
@@ -71,11 +67,11 @@ function getComputed<Value>(
|
|
|
71
67
|
// @ts-expect-error All good, no worries :-)
|
|
72
68
|
const instance = new Computed(callback, options);
|
|
73
69
|
|
|
74
|
-
return [instance
|
|
70
|
+
return [instance, instance[SYMBOL_EFFECT]];
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
function getComputedEffect(
|
|
78
|
-
instance:
|
|
74
|
+
instance: InternalStateful,
|
|
79
75
|
callback: GenericAsyncCallback,
|
|
80
76
|
): ComputedEffect {
|
|
81
77
|
const fx: ComputedEffect = {
|
|
@@ -89,7 +85,7 @@ function getComputedEffect(
|
|
|
89
85
|
|
|
90
86
|
ACTIVE.computed = fx;
|
|
91
87
|
|
|
92
|
-
|
|
88
|
+
handleSignal(instance, callback, setAndEmit, () => {
|
|
93
89
|
ACTIVE.computed = previousComputed;
|
|
94
90
|
});
|
|
95
91
|
|
|
@@ -126,14 +122,14 @@ function getComputedValue(this: InternalComputed): unknown {
|
|
|
126
122
|
export function internalComputed(
|
|
127
123
|
callback: GenericCallback,
|
|
128
124
|
options?: ReactiveOptions<unknown>,
|
|
129
|
-
): [
|
|
125
|
+
): [InternalComputed, ComputedEffect] {
|
|
130
126
|
return getComputed(callback, options);
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
function setAndEmit(instance:
|
|
129
|
+
function setAndEmit(instance: InternalStateful, value: unknown): void {
|
|
134
130
|
const state = instance[SYMBOL_STATE];
|
|
135
131
|
|
|
136
|
-
if ((state.equal ?? Object.is)(state.value
|
|
132
|
+
if ((state.equal ?? Object.is)(state.value, value)) {
|
|
137
133
|
return;
|
|
138
134
|
}
|
|
139
135
|
|
package/src/value/readonly.ts
CHANGED
|
@@ -6,42 +6,51 @@ import {
|
|
|
6
6
|
SYMBOL_STATE,
|
|
7
7
|
} from '../constants';
|
|
8
8
|
import {subscribeToReadonly} from '../helpers/subscription';
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
getFrozenValue,
|
|
11
|
+
getJsonValue,
|
|
12
|
+
getSignalValue,
|
|
13
|
+
getStringValue,
|
|
14
|
+
peekSignalValue,
|
|
15
|
+
} from '../helpers/value';
|
|
16
|
+
import type {InternalSignal, ReadonlyFrozenSignal, ReadonlySignal, SignalState} from '../models';
|
|
17
|
+
|
|
18
|
+
// #region Types
|
|
19
|
+
|
|
20
|
+
type InternalReadonly = {
|
|
21
|
+
[SUBSCRIPTION_TYPE_FROZEN]: boolean;
|
|
22
|
+
} & InternalSignal;
|
|
23
|
+
|
|
24
|
+
// #endregion
|
|
11
25
|
|
|
12
26
|
// #region Instance
|
|
13
27
|
|
|
14
28
|
function Readonly(this: any, state: SignalState, frozen: boolean) {
|
|
29
|
+
this[SUBSCRIPTION_TYPE_FROZEN] = frozen;
|
|
15
30
|
this[SYMBOL_STATE] = state;
|
|
16
|
-
|
|
17
|
-
Object.defineProperty(this, SUBSCRIPTION_TYPE_FROZEN, {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
value: frozen,
|
|
20
|
-
});
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
Readonly.prototype[NAME_MORA] = NAME_READONLY;
|
|
24
34
|
|
|
35
|
+
Readonly.prototype.get = getReadonlyValue;
|
|
36
|
+
Readonly.prototype.peek = peekReadonlyValue;
|
|
25
37
|
Readonly.prototype.subscribe = subscribeToReadonly;
|
|
38
|
+
Readonly.prototype.toJSON = getJsonValue;
|
|
26
39
|
Readonly.prototype.toString = getStringValue;
|
|
27
40
|
|
|
28
|
-
Readonly.prototype.get = function () {
|
|
29
|
-
return getReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
Readonly.prototype.peek = function (copy?: boolean) {
|
|
33
|
-
return getReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
Readonly.prototype.toJSON = function () {
|
|
37
|
-
return this[SYMBOL_STATE].value;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
41
|
// #endregion
|
|
41
42
|
|
|
42
43
|
// #region Functions
|
|
43
44
|
|
|
44
|
-
export function getReadonlyInstance
|
|
45
|
+
export function getReadonlyInstance(
|
|
46
|
+
state: SignalState,
|
|
47
|
+
frozen: boolean,
|
|
48
|
+
): ReadonlySignal<unknown> | ReadonlyFrozenSignal<unknown> {
|
|
49
|
+
// @ts-expect-error All good, no worries :-)
|
|
50
|
+
return new Readonly(state, frozen);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getReadonlySignal<Value>(
|
|
45
54
|
this: InternalSignal,
|
|
46
55
|
frozen?: never,
|
|
47
56
|
): ReadonlySignal<Value> {
|
|
@@ -49,7 +58,7 @@ export function getReadonlyInstance<Value>(
|
|
|
49
58
|
|
|
50
59
|
this[SYMBOL_STATE].readonlies ??= {};
|
|
51
60
|
|
|
52
|
-
this[SYMBOL_STATE].readonlies[key] ??=
|
|
61
|
+
this[SYMBOL_STATE].readonlies[key] ??= getReadonlyInstance(
|
|
53
62
|
this[SYMBOL_STATE],
|
|
54
63
|
frozen === true,
|
|
55
64
|
) as never;
|
|
@@ -57,16 +66,12 @@ export function getReadonlyInstance<Value>(
|
|
|
57
66
|
return this[SYMBOL_STATE].readonlies[key] as never;
|
|
58
67
|
}
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
frozen: boolean,
|
|
63
|
-
): ReadonlySignal<unknown> | ReadonlyFrozenSignal<unknown> {
|
|
64
|
-
// @ts-expect-error All good, no worries :-)
|
|
65
|
-
return new Readonly(state, frozen);
|
|
69
|
+
function getReadonlyValue(this: InternalReadonly) {
|
|
70
|
+
return handleReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
function
|
|
69
|
-
instance:
|
|
73
|
+
function handleReadonlyValue(
|
|
74
|
+
instance: InternalReadonly,
|
|
70
75
|
peek: boolean,
|
|
71
76
|
frozen: boolean,
|
|
72
77
|
copy?: boolean,
|
|
@@ -82,4 +87,8 @@ function getReadonlyValue(
|
|
|
82
87
|
return frozen ? getFrozenValue(value) : value;
|
|
83
88
|
}
|
|
84
89
|
|
|
90
|
+
function peekReadonlyValue(this: InternalReadonly, copy?: boolean) {
|
|
91
|
+
return handleReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
// #endregion
|
package/src/value/signal.ts
CHANGED
|
@@ -3,57 +3,53 @@ import {getState} from '../helpers/misc';
|
|
|
3
3
|
import {subscribeToSignal} from '../helpers/subscription';
|
|
4
4
|
import {
|
|
5
5
|
emitValue,
|
|
6
|
+
getJsonValue,
|
|
6
7
|
getSignalValue,
|
|
7
8
|
getStringValue,
|
|
8
|
-
|
|
9
|
+
handleSignal,
|
|
9
10
|
peekSignalValue,
|
|
10
|
-
|
|
11
|
+
updateSignal,
|
|
11
12
|
} from '../helpers/value';
|
|
12
|
-
import type {ReactiveOptions, Signal
|
|
13
|
-
import {
|
|
13
|
+
import type {InternalSignal, InternalStateful, ReactiveOptions, Signal} from '../models';
|
|
14
|
+
import {getReadonlySignal} from './readonly';
|
|
14
15
|
|
|
15
16
|
// #region Instance
|
|
16
17
|
|
|
17
18
|
function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>) {
|
|
18
19
|
this[SYMBOL_STATE] = getState(undefined, options);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
handleSignal(this, value, setAndEmit);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
Signal.prototype[NAME_MORA] = NAME_SIGNAL;
|
|
24
25
|
|
|
25
|
-
Signal.prototype.asReadonly =
|
|
26
|
+
Signal.prototype.asReadonly = getReadonlySignal;
|
|
26
27
|
Signal.prototype.get = getSignalValue;
|
|
27
28
|
Signal.prototype.peek = peekSignalValue;
|
|
29
|
+
Signal.prototype.set = setSignalValue;
|
|
28
30
|
Signal.prototype.subscribe = subscribeToSignal;
|
|
29
31
|
Signal.prototype.toString = getStringValue;
|
|
30
|
-
|
|
31
|
-
Signal.prototype.
|
|
32
|
-
return handleSignalValue(this, value, setAndEmit);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
Signal.prototype.toJSON = function () {
|
|
36
|
-
return this[SYMBOL_STATE].value;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
Signal.prototype.update = function (callback: never) {
|
|
40
|
-
return updateSignalValue(this, callback, setAndEmit);
|
|
41
|
-
};
|
|
32
|
+
Signal.prototype.toJSON = getJsonValue;
|
|
33
|
+
Signal.prototype.update = updateSignalValue;
|
|
42
34
|
|
|
43
35
|
// #endregion
|
|
44
36
|
|
|
45
37
|
// #region Functions
|
|
46
38
|
|
|
47
|
-
function setAndEmit(instance:
|
|
39
|
+
function setAndEmit(instance: InternalStateful, value: unknown): void {
|
|
48
40
|
const state = instance[SYMBOL_STATE];
|
|
49
41
|
|
|
50
|
-
if (!(state.equal ?? Object.is)(state.value
|
|
42
|
+
if (!(state.equal ?? Object.is)(state.value, value)) {
|
|
51
43
|
state.value = value;
|
|
52
44
|
|
|
53
45
|
emitValue(instance);
|
|
54
46
|
}
|
|
55
47
|
}
|
|
56
48
|
|
|
49
|
+
function setSignalValue(this: InternalSignal, value: unknown): void {
|
|
50
|
+
handleSignal(this, value, setAndEmit);
|
|
51
|
+
}
|
|
52
|
+
|
|
57
53
|
/**
|
|
58
54
|
* Create a reactive value from a function result
|
|
59
55
|
*
|
|
@@ -92,4 +88,8 @@ export function signal(value: unknown, options?: ReactiveOptions<unknown>): Sign
|
|
|
92
88
|
return new Signal(value, options);
|
|
93
89
|
}
|
|
94
90
|
|
|
91
|
+
function updateSignalValue(this: InternalSignal, callback: never): void {
|
|
92
|
+
updateSignal(this, callback, setAndEmit);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
95
|
// #endregion
|
package/src/value/store.ts
CHANGED
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
updateProxyValue,
|
|
11
11
|
} from '../helpers/proxy';
|
|
12
12
|
import {subscribeToProxy} from '../helpers/subscription';
|
|
13
|
-
import {getStringValue} from '../helpers/value';
|
|
13
|
+
import {getJsonValue, getStringValue} from '../helpers/value';
|
|
14
14
|
import type {ReactiveOptions, ReactiveStore} from '../models';
|
|
15
|
-
import {
|
|
15
|
+
import {getReadonlySignal} from './readonly';
|
|
16
16
|
|
|
17
17
|
// #region Instance
|
|
18
18
|
|
|
@@ -34,19 +34,16 @@ function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknow
|
|
|
34
34
|
|
|
35
35
|
ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
|
|
36
36
|
|
|
37
|
-
ReactiveStore.prototype.asReadonly =
|
|
37
|
+
ReactiveStore.prototype.asReadonly = getReadonlySignal;
|
|
38
38
|
ReactiveStore.prototype.get = getValueInProxy;
|
|
39
39
|
ReactiveStore.prototype.notify = emitProxyValues;
|
|
40
40
|
ReactiveStore.prototype.peek = peekValueInProxy;
|
|
41
41
|
ReactiveStore.prototype.set = setProxyValue;
|
|
42
42
|
ReactiveStore.prototype.subscribe = subscribeToProxy;
|
|
43
|
+
ReactiveStore.prototype.toJSON = getJsonValue;
|
|
43
44
|
ReactiveStore.prototype.toString = getStringValue;
|
|
44
45
|
ReactiveStore.prototype.update = updateProxyValue;
|
|
45
46
|
|
|
46
|
-
ReactiveStore.prototype.toJSON = function () {
|
|
47
|
-
return this[SYMBOL_STATE].value;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
47
|
// #endregion
|
|
51
48
|
|
|
52
49
|
// #region Functions
|