@oscarpalmer/mora 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/batch.d.mts +4 -5
- package/dist/batch.mjs +4 -2
- package/dist/constants.d.mts +29 -19
- package/dist/constants.mjs +17 -2
- package/dist/effect.d.mts +4 -5
- package/dist/effect.mjs +2 -2
- package/dist/helpers/is.d.mts +14 -9
- package/dist/helpers/is.mjs +6 -0
- package/dist/helpers/proxy.d.mts +12 -10
- package/dist/helpers/proxy.mjs +32 -14
- package/dist/helpers/subscription.d.mts +8 -0
- package/dist/helpers/subscription.mjs +27 -0
- package/dist/helpers/value.d.mts +8 -6
- package/dist/helpers/value.mjs +30 -4
- package/dist/index.d.mts +3 -2
- package/dist/models.d.mts +45 -87
- package/dist/mora.full.mjs +461 -285
- package/dist/value/array.d.mts +4 -5
- package/dist/value/array.mjs +22 -69
- package/dist/value/computed.d.mts +3 -4
- package/dist/value/computed.mjs +14 -14
- package/dist/value/reactive.d.mts +2 -3
- package/dist/value/reactive.mjs +0 -1
- package/dist/value/readonly.d.mts +3 -5
- package/dist/value/readonly.mjs +15 -19
- package/dist/value/signal.d.mts +4 -5
- package/dist/value/signal.mjs +9 -22
- package/dist/value/store.d.mts +4 -5
- package/dist/value/store.mjs +16 -56
- package/package.json +6 -6
- package/src/batch.ts +15 -5
- package/src/constants.ts +32 -2
- package/src/effect.ts +6 -2
- package/src/helpers/is.ts +10 -0
- package/src/helpers/proxy.ts +99 -49
- package/src/helpers/subscription.ts +78 -0
- package/src/helpers/value.ts +69 -4
- package/src/index.ts +1 -1
- package/src/models.ts +38 -81
- package/src/value/array.ts +61 -150
- package/src/value/computed.ts +36 -13
- package/src/value/reactive.ts +8 -5
- package/src/value/readonly.ts +26 -25
- package/src/value/signal.ts +19 -22
- package/src/value/store.ts +35 -114
- package/types/constants.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/value/array.d.ts +1 -1
- package/types/value/computed.d.ts +0 -3
- package/types/value/signal.d.ts +1 -1
- package/types/value/store.d.ts +1 -1
- package/dist/subscription.d.mts +0 -7
- package/dist/subscription.mjs +0 -27
- package/src/subscription.ts +0 -45
package/src/effect.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {ACTIVE, NAME_EFFECT} from './constants';
|
|
2
|
+
import {ACTIVE, NAME_EFFECT, NAME_MORA} from './constants';
|
|
3
3
|
import type {Effect, EffectState} from './models';
|
|
4
4
|
|
|
5
|
+
// #region Functions
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Create an effect
|
|
7
9
|
*
|
|
@@ -22,7 +24,7 @@ function getEffect(callback: GenericCallback): [Effect, EffectState] {
|
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
const instance = Object.freeze({
|
|
25
|
-
|
|
27
|
+
[NAME_MORA]: NAME_EFFECT,
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
runEffect(state);
|
|
@@ -45,3 +47,5 @@ export function runEffect(state: EffectState): void {
|
|
|
45
47
|
ACTIVE.effect = previousEffect;
|
|
46
48
|
}
|
|
47
49
|
}
|
|
50
|
+
|
|
51
|
+
// #endregion
|
package/src/helpers/is.ts
CHANGED
|
@@ -19,6 +19,8 @@ import type {
|
|
|
19
19
|
Signal,
|
|
20
20
|
} from '../models';
|
|
21
21
|
|
|
22
|
+
// #region Functions
|
|
23
|
+
|
|
22
24
|
/**
|
|
23
25
|
* Is the value a computed signal?
|
|
24
26
|
*
|
|
@@ -92,6 +94,14 @@ export function isReactiveStore<Value extends PlainObject>(
|
|
|
92
94
|
return isMora<ReactiveStore<Value>>(value, NAME_STORE);
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Is the value a readonly signal?
|
|
99
|
+
*
|
|
100
|
+
* @param value Value to check
|
|
101
|
+
* @returns True if value is a {@link ReadonlySignal}
|
|
102
|
+
*/
|
|
95
103
|
export function isReadonlySignal<Value>(value: unknown): value is ReadonlySignal<Value> {
|
|
96
104
|
return isMora<ReadonlySignal<Value>>(value, NAME_READONLY);
|
|
97
105
|
}
|
|
106
|
+
|
|
107
|
+
// #endregion
|
package/src/helpers/proxy.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {isKey, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
1
2
|
import type {ArrayOrPlainObject, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
3
|
import {PROPERTY_LENGTH} from '../constants';
|
|
3
4
|
import type {
|
|
@@ -6,23 +7,30 @@ import type {
|
|
|
6
7
|
ReactiveArray,
|
|
7
8
|
ReactiveState,
|
|
8
9
|
ReactiveStore,
|
|
9
|
-
|
|
10
|
+
Signal,
|
|
10
11
|
} from '../models';
|
|
11
12
|
import {internalComputed} from '../value/computed';
|
|
12
|
-
import {emitValue} from './value';
|
|
13
|
+
import {emitValue, getSimpleValue, peekSimpleValue} from './value';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
state: ReactiveState<Value, Value>,
|
|
16
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
17
|
-
): void;
|
|
15
|
+
// #region Types
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
state: ReactiveState<Value
|
|
21
|
-
|
|
22
|
-
)
|
|
17
|
+
type SetObjectCallback<Value, Item> = (
|
|
18
|
+
state: ReactiveState<Value, Item>,
|
|
19
|
+
value: Value | undefined,
|
|
20
|
+
) => void;
|
|
21
|
+
|
|
22
|
+
type SetPropertyCallback<Value, Item> = (
|
|
23
|
+
state: ReactiveState<Value, Item>,
|
|
24
|
+
property: unknown,
|
|
25
|
+
value: Item,
|
|
26
|
+
) => void;
|
|
27
|
+
|
|
28
|
+
// #endregion
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
// #region Functions
|
|
31
|
+
|
|
32
|
+
export function emitProxyValues<Value, Item = Value>(
|
|
33
|
+
state: ReactiveState<Value, Item>,
|
|
26
34
|
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
27
35
|
): void {
|
|
28
36
|
const values = [...mapped.values()];
|
|
@@ -35,27 +43,15 @@ export function emityProxyValues(
|
|
|
35
43
|
emitValue(state);
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
export function getReactiveValueInProxy<Value
|
|
39
|
-
|
|
40
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
41
|
-
index: number,
|
|
42
|
-
isArray: true,
|
|
43
|
-
): Computed<Result>;
|
|
44
|
-
|
|
45
|
-
export function getReactiveValueInProxy<Value extends PlainObject>(
|
|
46
|
-
store: ReactiveStore<Value>,
|
|
47
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
48
|
-
key: Key,
|
|
49
|
-
isArray: false,
|
|
50
|
-
): Computed<unknown>;
|
|
51
|
-
|
|
52
|
-
export function getReactiveValueInProxy(
|
|
53
|
-
reactive: ReactiveArray<unknown> | ReactiveStore<PlainObject>,
|
|
46
|
+
export function getReactiveValueInProxy<Value>(
|
|
47
|
+
reactive: ReactiveArray<Value> | ReactiveStore<Value>,
|
|
54
48
|
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
55
49
|
key: Key,
|
|
56
50
|
isArray: boolean,
|
|
57
51
|
): Computed<unknown> {
|
|
58
|
-
|
|
52
|
+
const mapKey = String(key);
|
|
53
|
+
|
|
54
|
+
let item = mapped.get(mapKey);
|
|
59
55
|
|
|
60
56
|
if (item == null) {
|
|
61
57
|
item = internalComputed(() =>
|
|
@@ -64,37 +60,72 @@ export function getReactiveValueInProxy(
|
|
|
64
60
|
: (reactive.get() as PlainObject)[key],
|
|
65
61
|
);
|
|
66
62
|
|
|
67
|
-
mapped.set(
|
|
63
|
+
mapped.set(mapKey, item);
|
|
68
64
|
}
|
|
69
65
|
|
|
70
66
|
return item[0];
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
export function getValueInProxy<Value, Item = Value>(
|
|
70
|
+
isArray: boolean,
|
|
71
|
+
instance: ReactiveArray<Value> | ReactiveStore<Value>,
|
|
72
|
+
state: ReactiveState<Value, Item>,
|
|
73
|
+
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
74
|
+
first?: unknown,
|
|
75
|
+
): unknown {
|
|
76
|
+
if (isArray ? typeof first === 'number' : isKey(first)) {
|
|
77
|
+
return getReactiveValueInProxy(instance, mapped, first as Key, isArray).get();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return getSimpleValue(state);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
|
|
84
|
+
return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function peekValueInProxy<Value, Item = Value>(
|
|
88
|
+
isArray: boolean,
|
|
89
|
+
state: ReactiveState<Value, Item>,
|
|
90
|
+
first?: unknown,
|
|
91
|
+
second?: boolean,
|
|
92
|
+
): unknown {
|
|
93
|
+
let value: unknown;
|
|
94
|
+
|
|
95
|
+
if (isArray ? typeof first === 'number' : isKey(first)) {
|
|
96
|
+
value = isArray
|
|
97
|
+
? (state.value as unknown[]).at(first as number)
|
|
98
|
+
: (state.value as PlainObject)[first as Key];
|
|
99
|
+
} else {
|
|
100
|
+
value = state.value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return peekSimpleValue(value, first === true || second === true);
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
export function setProxyValue<Value, Item = Value>(
|
|
74
|
-
|
|
107
|
+
isArray: boolean,
|
|
75
108
|
state: ReactiveState<Value, Item>,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
setObject: (state: ReactiveState<Value, Item>, value: Value | undefined) => void,
|
|
79
|
-
setProperty: (state: ReactiveState<Value, Item>, property: unknown, value: Item) => void,
|
|
109
|
+
setObject: SetObjectCallback<Value, Item>,
|
|
110
|
+
setProperty: SetPropertyCallback<Value, Item>,
|
|
80
111
|
first?: unknown,
|
|
81
112
|
second?: unknown,
|
|
82
113
|
): void {
|
|
83
|
-
if (
|
|
114
|
+
if (isArray && first === PROPERTY_LENGTH) {
|
|
84
115
|
(state.value as unknown[]).length = second as number;
|
|
85
116
|
|
|
86
117
|
return;
|
|
87
118
|
}
|
|
88
119
|
|
|
89
|
-
if (
|
|
90
|
-
setObject(state, first);
|
|
120
|
+
if (isProxyObject(isArray, first)) {
|
|
121
|
+
setObject(state, first as Value);
|
|
91
122
|
|
|
92
123
|
return;
|
|
93
124
|
}
|
|
94
125
|
|
|
95
|
-
const property =
|
|
126
|
+
const property = isArray ? typeof first === 'number' : isKey(first);
|
|
96
127
|
|
|
97
|
-
if (
|
|
128
|
+
if (isArray && property && Number.isNaN(first)) {
|
|
98
129
|
return;
|
|
99
130
|
}
|
|
100
131
|
|
|
@@ -127,10 +158,10 @@ export function setProxyValue<Value, Item = Value>(
|
|
|
127
158
|
return;
|
|
128
159
|
}
|
|
129
160
|
|
|
130
|
-
if (!property &&
|
|
161
|
+
if (!property && isProxyObject(isArray, value) && state.promise === actual) {
|
|
131
162
|
state.promise = undefined;
|
|
132
163
|
|
|
133
|
-
setObject(state, value);
|
|
164
|
+
setObject(state, value as Value);
|
|
134
165
|
}
|
|
135
166
|
})
|
|
136
167
|
.catch(() => {
|
|
@@ -142,16 +173,19 @@ export function setProxyValue<Value, Item = Value>(
|
|
|
142
173
|
});
|
|
143
174
|
} else if (property) {
|
|
144
175
|
setProperty(state, first, actual as Item);
|
|
145
|
-
} else if (
|
|
146
|
-
setObject(state, actual);
|
|
176
|
+
} else if (isProxyObject(isArray, actual)) {
|
|
177
|
+
setObject(state, actual as Value);
|
|
147
178
|
}
|
|
148
179
|
}
|
|
149
180
|
|
|
150
|
-
export function setValueInProxy<Value
|
|
151
|
-
|
|
181
|
+
export function setValueInProxy<Value, Item = Value>(
|
|
182
|
+
isArray: boolean,
|
|
183
|
+
state: ReactiveState<Value, Item>,
|
|
184
|
+
target: object,
|
|
185
|
+
property: PropertyKey,
|
|
186
|
+
value: unknown,
|
|
187
|
+
length?: Signal<number>,
|
|
152
188
|
): boolean {
|
|
153
|
-
const {isArray, length, property, state, target, value} = parameters;
|
|
154
|
-
|
|
155
189
|
if (isArray) {
|
|
156
190
|
const isIndex = !Number.isNaN(Number(property));
|
|
157
191
|
const isLength = property === PROPERTY_LENGTH;
|
|
@@ -161,7 +195,7 @@ export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
|
|
|
161
195
|
}
|
|
162
196
|
}
|
|
163
197
|
|
|
164
|
-
const previous = Reflect.get(target, property);
|
|
198
|
+
const previous = Reflect.get(target as object, property);
|
|
165
199
|
|
|
166
200
|
if (!state.equal(previous as never, value as never)) {
|
|
167
201
|
Reflect.set(target, property, value);
|
|
@@ -175,3 +209,19 @@ export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
|
|
|
175
209
|
|
|
176
210
|
return true;
|
|
177
211
|
}
|
|
212
|
+
|
|
213
|
+
export function updateProxyValue<Value, Item = Value>(
|
|
214
|
+
isArray: boolean,
|
|
215
|
+
state: ReactiveState<Value, Item>,
|
|
216
|
+
setObject: SetObjectCallback<Value, Item>,
|
|
217
|
+
setProperty: SetPropertyCallback<Value, Item>,
|
|
218
|
+
callback: unknown,
|
|
219
|
+
): void {
|
|
220
|
+
if (typeof callback !== 'function') {
|
|
221
|
+
throw new TypeError('Callback must be a function');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
setProxyValue(isArray, state, setObject, setProperty, callback(state.value));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// #endregion
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {isKey} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {subscriptions, type Subscription} from '@oscarpalmer/atoms/subscription';
|
|
4
|
+
import {
|
|
5
|
+
SUBSCRIPTION_PROPERTY,
|
|
6
|
+
SUBSCRIPTION_TYPE_COPY,
|
|
7
|
+
SUBSCRIPTION_TYPE_FROZEN,
|
|
8
|
+
SUBSCRIPTION_TYPE_ORIGINAL,
|
|
9
|
+
SUBSCRIPTION_TYPES,
|
|
10
|
+
SUBSCRIPTION_TYPES_COPY,
|
|
11
|
+
} from '../constants';
|
|
12
|
+
import type {
|
|
13
|
+
Computed,
|
|
14
|
+
ComputedEffect,
|
|
15
|
+
ReactiveArray,
|
|
16
|
+
ReactiveState,
|
|
17
|
+
ReactiveStore,
|
|
18
|
+
SubscriptionType,
|
|
19
|
+
} from '../models';
|
|
20
|
+
import {getReactiveValueInProxy} from './proxy';
|
|
21
|
+
import {getFrozenValue, peekSimpleValue} from './value';
|
|
22
|
+
|
|
23
|
+
export function subscribeToProxy<Value, Item = Value>(
|
|
24
|
+
isArray: boolean,
|
|
25
|
+
instance: ReactiveArray<Value> | ReactiveStore<Value>,
|
|
26
|
+
state: ReactiveState<Value, Item>,
|
|
27
|
+
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
28
|
+
first: Key | ((value: unknown) => unknown),
|
|
29
|
+
second?: ((value: unknown) => unknown) | boolean,
|
|
30
|
+
third?: boolean,
|
|
31
|
+
): Subscription {
|
|
32
|
+
if (isKey(first)) {
|
|
33
|
+
return getReactiveValueInProxy(instance as never, mapped, first, isArray).subscribe(
|
|
34
|
+
second as never,
|
|
35
|
+
third as never,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return subscribeToSignal(state, first, second === true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function subscribeToReactive<Value, Item = Value>(
|
|
43
|
+
type: SubscriptionType,
|
|
44
|
+
state: ReactiveState<Value, Item>,
|
|
45
|
+
callback: (value: unknown) => unknown,
|
|
46
|
+
): Subscription {
|
|
47
|
+
state.subscriptions ??= subscriptions({
|
|
48
|
+
keys: SUBSCRIPTION_TYPES,
|
|
49
|
+
property: SUBSCRIPTION_PROPERTY,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const [subscription, existing] = state.subscriptions.create({
|
|
53
|
+
key: type,
|
|
54
|
+
value: callback,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!existing) {
|
|
58
|
+
callback(
|
|
59
|
+
type === SUBSCRIPTION_TYPE_FROZEN
|
|
60
|
+
? getFrozenValue(state.value)
|
|
61
|
+
: peekSimpleValue(state.value, SUBSCRIPTION_TYPES_COPY.has(type)),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return subscription;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function subscribeToSignal<Value, Item = Value>(
|
|
69
|
+
state: ReactiveState<Value, Item>,
|
|
70
|
+
callback: (value: unknown) => unknown,
|
|
71
|
+
copy: boolean,
|
|
72
|
+
): Subscription {
|
|
73
|
+
return subscribeToReactive(
|
|
74
|
+
copy ? SUBSCRIPTION_TYPE_COPY : SUBSCRIPTION_TYPE_ORIGINAL,
|
|
75
|
+
state,
|
|
76
|
+
callback,
|
|
77
|
+
);
|
|
78
|
+
}
|
package/src/helpers/value.ts
CHANGED
|
@@ -1,18 +1,41 @@
|
|
|
1
|
+
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
1
2
|
import {flushHandlers} from '../batch';
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ACTIVE,
|
|
5
|
+
ARRAY_OFFSET,
|
|
6
|
+
ARRAY_PEEK,
|
|
7
|
+
ARRAY_THRESHOLD,
|
|
8
|
+
BATCH,
|
|
9
|
+
SUBSCRIPTION_TYPES_COPY,
|
|
10
|
+
SUBSCRIPTION_TYPE_FROZEN,
|
|
11
|
+
SUBSCRIPTION_TYPES,
|
|
12
|
+
} from '../constants';
|
|
3
13
|
import type {ReactiveState} from '../models';
|
|
4
14
|
|
|
15
|
+
// #region Functions
|
|
16
|
+
|
|
5
17
|
export function emitValue<Value>(state: ReactiveState<Value, never>): void {
|
|
6
18
|
for (const computed of state.computeds) {
|
|
7
19
|
computed.dirty = true;
|
|
8
20
|
}
|
|
9
21
|
|
|
10
22
|
for (const effect of state.effects) {
|
|
11
|
-
BATCH.handlers.
|
|
23
|
+
BATCH.handlers.set(effect, effect);
|
|
12
24
|
}
|
|
13
25
|
|
|
14
|
-
for (const
|
|
15
|
-
|
|
26
|
+
for (const type of SUBSCRIPTION_TYPES) {
|
|
27
|
+
const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
|
|
28
|
+
|
|
29
|
+
if (subscriptions != null) {
|
|
30
|
+
for (const [subscription, callback] of subscriptions) {
|
|
31
|
+
BATCH.handlers.set(subscription, {
|
|
32
|
+
callback,
|
|
33
|
+
state,
|
|
34
|
+
frozen: type === SUBSCRIPTION_TYPE_FROZEN,
|
|
35
|
+
copy: SUBSCRIPTION_TYPES_COPY.has(type),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
16
39
|
}
|
|
17
40
|
|
|
18
41
|
if (BATCH.depth === 0) {
|
|
@@ -55,6 +78,18 @@ export function equalArrays<Value>(
|
|
|
55
78
|
return true;
|
|
56
79
|
}
|
|
57
80
|
|
|
81
|
+
export function getFrozenValue(value: unknown): unknown {
|
|
82
|
+
let frozen = value;
|
|
83
|
+
|
|
84
|
+
if (Array.isArray(frozen)) {
|
|
85
|
+
frozen = Object.freeze(frozen.slice());
|
|
86
|
+
} else if (isPlainObject(frozen)) {
|
|
87
|
+
frozen = Object.freeze({...frozen});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return frozen;
|
|
91
|
+
}
|
|
92
|
+
|
|
58
93
|
export function getSimpleValue<Value>(state: ReactiveState<Value, never>): Value {
|
|
59
94
|
if (ACTIVE.computed != null) {
|
|
60
95
|
state.computeds.add(ACTIVE.computed);
|
|
@@ -101,3 +136,33 @@ export function handleSimpleValue<Value>(
|
|
|
101
136
|
onAfter?.();
|
|
102
137
|
}
|
|
103
138
|
}
|
|
139
|
+
|
|
140
|
+
export function peekSimpleValue(value: unknown, copy: boolean): unknown {
|
|
141
|
+
let peeked: unknown = value;
|
|
142
|
+
|
|
143
|
+
if (!copy) {
|
|
144
|
+
return peeked;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (Array.isArray(peeked)) {
|
|
148
|
+
peeked = peeked.slice();
|
|
149
|
+
} else if (isPlainObject(peeked)) {
|
|
150
|
+
peeked = {...peeked};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return peeked;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function updateSimpleValue<Value>(
|
|
157
|
+
state: ReactiveState<Value, Value>,
|
|
158
|
+
callback: (value: Value) => Value,
|
|
159
|
+
setValue: (state: ReactiveState<Value, Value>, value: Value) => void,
|
|
160
|
+
): void {
|
|
161
|
+
if (typeof callback !== 'function') {
|
|
162
|
+
throw new TypeError('Callback must be a function');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
handleSimpleValue(state, callback(state.value), setValue);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// #endregion
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type {Subscription} from '@oscarpalmer/atoms/subscription';
|
|
1
2
|
export {startBatch, stopBatch} from './batch';
|
|
2
3
|
export {effect} from './effect';
|
|
3
4
|
export {
|
|
@@ -16,7 +17,6 @@ export type {
|
|
|
16
17
|
ReactiveStore,
|
|
17
18
|
ReadonlySignal,
|
|
18
19
|
Signal,
|
|
19
|
-
Unsubscribe,
|
|
20
20
|
} from './models';
|
|
21
21
|
export {array} from './value/array';
|
|
22
22
|
export {computed} from './value/computed';
|
package/src/models.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type {GenericCallback, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import type {Subscription, Subscriptions} from '@oscarpalmer/atoms/subscription';
|
|
2
3
|
import type {PROPERTY_LENGTH} from './constants';
|
|
3
4
|
|
|
5
|
+
// #region Types
|
|
6
|
+
|
|
4
7
|
export type Active = {
|
|
5
8
|
computed?: ComputedEffect;
|
|
6
9
|
effect?: EffectState;
|
|
@@ -9,7 +12,7 @@ export type Active = {
|
|
|
9
12
|
export type Batch = {
|
|
10
13
|
depth: number;
|
|
11
14
|
flushing: boolean;
|
|
12
|
-
handlers:
|
|
15
|
+
handlers: Map<EffectState | Subscription, EffectState | StoredSubscription>;
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
export type Computed<Value> = Reactive<Value> & SimpleReactive<Value>;
|
|
@@ -228,18 +231,24 @@ export type ReactiveArray<Item> = {
|
|
|
228
231
|
* Subscribe to changes
|
|
229
232
|
*
|
|
230
233
|
* @param callback Callback for changes
|
|
231
|
-
* @
|
|
234
|
+
* @param copy Copy the array? _(defaults to `false`)_
|
|
235
|
+
* @returns Subscription
|
|
232
236
|
*/
|
|
233
|
-
subscribe(callback: (value: Item[]) => void):
|
|
237
|
+
subscribe(callback: (value: Item[]) => void, copy?: boolean): Subscription;
|
|
234
238
|
|
|
235
239
|
/**
|
|
236
240
|
* Subscribe to changes at a specific index
|
|
237
241
|
*
|
|
238
242
|
* @param index Index of item to subscribe to
|
|
239
243
|
* @param callback Callback for changes
|
|
240
|
-
* @
|
|
244
|
+
* @param copy If the item is an array or record, should it be copied? _(defaults to `false`)_
|
|
245
|
+
* @returns Subscription
|
|
241
246
|
*/
|
|
242
|
-
subscribe(
|
|
247
|
+
subscribe(
|
|
248
|
+
index: number,
|
|
249
|
+
callback: (value: Item | undefined) => void,
|
|
250
|
+
copy?: boolean,
|
|
251
|
+
): Subscription;
|
|
243
252
|
|
|
244
253
|
/**
|
|
245
254
|
* Add items to the beginning of the array
|
|
@@ -248,21 +257,6 @@ export type ReactiveArray<Item> = {
|
|
|
248
257
|
*/
|
|
249
258
|
unshift(...items: Item[]): number;
|
|
250
259
|
|
|
251
|
-
/**
|
|
252
|
-
* Unsubscribe from changes for a specific index
|
|
253
|
-
*
|
|
254
|
-
* @param index Index of the value to unsubscribe from
|
|
255
|
-
* @param callback Callback to unsubscribe
|
|
256
|
-
*/
|
|
257
|
-
unsubscribe(index: number, callback: (item: Item | undefined) => void): void;
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Unsubscribe from changes
|
|
261
|
-
*
|
|
262
|
-
* @param callback Callback to unsubscribe
|
|
263
|
-
*/
|
|
264
|
-
unsubscribe(callback: (array: Item[]) => void): void;
|
|
265
|
-
|
|
266
260
|
/**
|
|
267
261
|
* Update the value _(based on the current value)_
|
|
268
262
|
*
|
|
@@ -282,13 +276,13 @@ export type ReactiveOptions<Value> = {
|
|
|
282
276
|
equal?: (first: Value, second: Value) => boolean;
|
|
283
277
|
};
|
|
284
278
|
|
|
285
|
-
export type ReactiveState<Value,
|
|
279
|
+
export type ReactiveState<Value, Item = Value> = {
|
|
286
280
|
computeds: Set<ComputedEffect>;
|
|
287
281
|
effects: Set<EffectState>;
|
|
288
|
-
equal: (first:
|
|
282
|
+
equal: (first: Item, second: Item) => boolean;
|
|
289
283
|
promise?: Promise<Value>;
|
|
290
284
|
promises?: Map<Key, Promise<never>>;
|
|
291
|
-
subscriptions
|
|
285
|
+
subscriptions?: Subscriptions<GenericCallback>;
|
|
292
286
|
value: Value;
|
|
293
287
|
};
|
|
294
288
|
|
|
@@ -403,56 +397,34 @@ export type ReactiveStore<Store> = {
|
|
|
403
397
|
* Subscribe to changes
|
|
404
398
|
*
|
|
405
399
|
* @param callback Callback for changes
|
|
406
|
-
* @
|
|
400
|
+
* @param copy Copy the store? _(defaults to `false`)_
|
|
401
|
+
* @returns Subscription
|
|
407
402
|
*/
|
|
408
|
-
subscribe(callback: (value: Store) => void):
|
|
403
|
+
subscribe(callback: (value: Store) => void, copy?: boolean): Subscription;
|
|
409
404
|
|
|
410
405
|
/**
|
|
411
406
|
* Subscribe to changes for a specific key
|
|
412
407
|
*
|
|
413
408
|
* @param key Key of the value to subscribe to
|
|
414
409
|
* @param callback Callback for changes
|
|
415
|
-
* @
|
|
410
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
411
|
+
* @returns Subscription
|
|
416
412
|
*/
|
|
417
413
|
subscribe<Key extends keyof Store>(
|
|
418
414
|
key: Key,
|
|
419
415
|
callback: (value: Store[Key] | undefined) => void,
|
|
420
|
-
|
|
416
|
+
copy?: boolean,
|
|
417
|
+
): Subscription;
|
|
421
418
|
|
|
422
419
|
/**
|
|
423
420
|
* Subscribe to changes for a specific key
|
|
424
421
|
*
|
|
425
422
|
* @param key Key of the value to subscribe to
|
|
426
423
|
* @param callback Callback for changes
|
|
427
|
-
* @
|
|
428
|
-
|
|
429
|
-
subscribe(key: Key, callback: (value: unknown) => void): Unsubscribe;
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Unsubscribe from changes for a specific key
|
|
433
|
-
*
|
|
434
|
-
* @param key Key of the value to unsubscribe from
|
|
435
|
-
* @param callback Callback to unsubscribe
|
|
436
|
-
*/
|
|
437
|
-
unsubscribe<Key extends keyof Store>(
|
|
438
|
-
key: Key,
|
|
439
|
-
callback: (value: Store[Key] | undefined) => void,
|
|
440
|
-
): void;
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Unsubscribe from changes for a specific key
|
|
444
|
-
*
|
|
445
|
-
* @param key Key of the value to unsubscribe from
|
|
446
|
-
* @param callback Callback to unsubscribe
|
|
447
|
-
*/
|
|
448
|
-
unsubscribe(key: Key, callback: (value: unknown | undefined) => void): void;
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Unsubscribe from changes
|
|
452
|
-
*
|
|
453
|
-
* @param callback Callback to unsubscribe
|
|
424
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
425
|
+
* @returns Subscription
|
|
454
426
|
*/
|
|
455
|
-
|
|
427
|
+
subscribe(key: Key, callback: (value: unknown) => void, copy?: boolean): Subscription;
|
|
456
428
|
|
|
457
429
|
/**
|
|
458
430
|
* Update the value _(based on the current value)_
|
|
@@ -483,15 +455,6 @@ export type ReadonlySignalValue<Value> = Value extends unknown[]
|
|
|
483
455
|
? Readonly<Value>
|
|
484
456
|
: Value;
|
|
485
457
|
|
|
486
|
-
export type SetValueInProxyParameters<Value, Equal> = {
|
|
487
|
-
target: Value;
|
|
488
|
-
property: PropertyKey;
|
|
489
|
-
value: unknown;
|
|
490
|
-
state: ReactiveState<Value, Equal>;
|
|
491
|
-
isArray: boolean;
|
|
492
|
-
length?: Signal<number>;
|
|
493
|
-
};
|
|
494
|
-
|
|
495
458
|
export type Signal<Value> = {
|
|
496
459
|
/**
|
|
497
460
|
* Get a readonly version of the signal
|
|
@@ -538,34 +501,28 @@ type SimpleReactive<Value> = {
|
|
|
538
501
|
/**
|
|
539
502
|
* Get the value _(without reactivity)_
|
|
540
503
|
*
|
|
504
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
541
505
|
* @returns Current value
|
|
542
506
|
*/
|
|
543
|
-
peek(): Value;
|
|
507
|
+
peek(copy?: boolean): Value;
|
|
544
508
|
|
|
545
509
|
/**
|
|
546
510
|
* Subscribe to changes
|
|
547
511
|
*
|
|
548
512
|
* @param callback Callback for changes
|
|
549
|
-
* @
|
|
550
|
-
|
|
551
|
-
subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Unsubscribe from changes
|
|
555
|
-
*
|
|
556
|
-
* @param callback Callback to unsubscribe
|
|
513
|
+
* @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
|
|
514
|
+
* @returns Subscription
|
|
557
515
|
*/
|
|
558
|
-
|
|
516
|
+
subscribe(callback: (value: Value) => void, copy?: boolean): Subscription;
|
|
559
517
|
};
|
|
560
518
|
|
|
561
|
-
export type
|
|
519
|
+
export type StoredSubscription = {
|
|
562
520
|
callback: GenericCallback;
|
|
521
|
+
copy: boolean;
|
|
522
|
+
frozen: boolean;
|
|
563
523
|
state: ReactiveState<unknown, never>;
|
|
564
|
-
|
|
565
|
-
destroy(): void;
|
|
566
524
|
};
|
|
567
525
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
export type Unsubscribe = () => void;
|
|
526
|
+
export type SubscriptionType = 'copy' | 'frozen' | 'original' | 'readonly';
|
|
527
|
+
|
|
528
|
+
// #endregion
|