@oscarpalmer/mora 0.29.0 → 0.31.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.mjs +15 -6
- package/dist/constants.d.mts +2 -2
- package/dist/constants.mjs +7 -4
- package/dist/effect.d.mts +5 -18
- package/dist/effect.mjs +23 -19
- package/dist/helpers/is.d.mts +17 -16
- package/dist/helpers/is.mjs +20 -11
- package/dist/helpers/proxy.d.mts +5 -9
- package/dist/helpers/proxy.mjs +4 -4
- package/dist/helpers/value.d.mts +3 -3
- package/dist/helpers/value.mjs +22 -5
- package/dist/index.d.mts +8 -9
- package/dist/index.mjs +2 -2
- package/dist/models.d.mts +423 -19
- package/dist/mora.full.mjs +532 -424
- package/dist/subscription.d.mts +1 -9
- package/dist/subscription.mjs +14 -15
- package/dist/value/array.d.mts +5 -133
- package/dist/value/array.mjs +108 -138
- package/dist/value/computed.d.mts +4 -12
- package/dist/value/computed.mjs +54 -50
- package/dist/value/reactive.d.mts +3 -49
- package/dist/value/reactive.mjs +10 -54
- package/dist/value/readonly.d.mts +7 -0
- package/dist/value/readonly.mjs +37 -0
- package/dist/value/signal.d.mts +5 -21
- package/dist/value/signal.mjs +33 -49
- package/dist/value/store.d.mts +9 -92
- package/dist/value/store.mjs +58 -49
- package/package.json +7 -8
- package/src/batch.ts +22 -9
- package/src/constants.ts +12 -5
- package/src/effect.ts +35 -40
- package/src/helpers/is.ts +36 -20
- package/src/helpers/proxy.ts +23 -18
- package/src/helpers/value.ts +39 -5
- package/src/index.ts +23 -8
- package/src/models.ts +520 -17
- package/src/subscription.ts +20 -20
- package/src/value/array.ts +220 -266
- package/src/value/computed.ts +80 -74
- package/src/value/reactive.ts +16 -77
- package/src/value/readonly.ts +71 -0
- package/src/value/signal.ts +43 -71
- package/src/value/store.ts +130 -177
- 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 +3 -0
- package/types/value/signal.d.ts +1 -1
- package/types/value/store.d.ts +1 -1
package/src/value/store.ts
CHANGED
|
@@ -1,183 +1,26 @@
|
|
|
1
1
|
import {isKey, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
2
|
import type {GenericCallback, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {startBatch, stopBatch} from '../batch';
|
|
4
|
-
import {NAME_STORE} from '../constants';
|
|
4
|
+
import {NAME_MORA, NAME_STORE} from '../constants';
|
|
5
5
|
import {
|
|
6
6
|
emityProxyValues,
|
|
7
7
|
getReactiveValueInProxy,
|
|
8
8
|
setProxyValue,
|
|
9
9
|
setValueInProxy,
|
|
10
10
|
} from '../helpers/proxy';
|
|
11
|
-
import {
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
set: (target: Value, property: PropertyKey, value: unknown) =>
|
|
25
|
-
setValueInProxy({
|
|
26
|
-
target,
|
|
27
|
-
property,
|
|
28
|
-
value,
|
|
29
|
-
isArray: false,
|
|
30
|
-
state: this.state,
|
|
31
|
-
}),
|
|
32
|
-
}),
|
|
33
|
-
options,
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @inheritdoc
|
|
39
|
-
*/
|
|
40
|
-
get(): Value;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get a value by key
|
|
44
|
-
* @param key Key of the value to get
|
|
45
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
46
|
-
*/
|
|
47
|
-
get<Key extends keyof Value>(key: Key): Value[Key];
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get a value by key
|
|
51
|
-
* @param key Key of the value to get
|
|
52
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
53
|
-
*/
|
|
54
|
-
get(key: Key): unknown;
|
|
55
|
-
|
|
56
|
-
get(key?: unknown): unknown {
|
|
57
|
-
return isKey(key)
|
|
58
|
-
? getReactiveValueInProxy(this, this.#keyed, key, false).get()
|
|
59
|
-
: getValue(this.state);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Notify dependents of changes
|
|
64
|
-
*
|
|
65
|
-
* _This bypasses equality checks and will immediately notify dependents.
|
|
66
|
-
* Use this only if you're modifying nested data that would be ignored by equality checks._
|
|
67
|
-
*/
|
|
68
|
-
notify(): void {
|
|
69
|
-
emityProxyValues(this.state, this.#keyed);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get the value _(without reactivity)_
|
|
74
|
-
* @returns The current value
|
|
75
|
-
*/
|
|
76
|
-
override peek(): Value;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get a value by key _(without reactivity)_
|
|
80
|
-
* @param key Key of the value to get
|
|
81
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
82
|
-
*/
|
|
83
|
-
override peek<Key extends keyof Value>(key: Key): Value[Key];
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Get a value by key _(without reactivity)_
|
|
87
|
-
* @param key Key of the value to get
|
|
88
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
89
|
-
*/
|
|
90
|
-
override peek(key: Key): unknown;
|
|
91
|
-
|
|
92
|
-
override peek(key?: unknown): unknown {
|
|
93
|
-
return isKey(key) ? this.state.value[key] : {...this.state.value};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Set the value
|
|
98
|
-
* @param value New value _(defaults to an empty object)_
|
|
99
|
-
*/
|
|
100
|
-
set(
|
|
101
|
-
value?:
|
|
102
|
-
| Value
|
|
103
|
-
| (() => null | undefined | Value | Promise<null | undefined | Value>)
|
|
104
|
-
| Promise<null | undefined | Value>,
|
|
105
|
-
): void;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Set a value by key
|
|
109
|
-
* @param key Key of the value to set
|
|
110
|
-
* @param value New value
|
|
111
|
-
*/
|
|
112
|
-
set<Key extends keyof Value>(
|
|
113
|
-
key: Key,
|
|
114
|
-
value: Value[Key] | (() => Value[Key] | Promise<Value[Key]>) | Promise<Value[Key]>,
|
|
115
|
-
): void;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Set a value by key
|
|
119
|
-
* @param key Key of the value to set
|
|
120
|
-
* @param value New value
|
|
121
|
-
*/
|
|
122
|
-
set(key: Key, value: unknown): void;
|
|
123
|
-
|
|
124
|
-
set(first?: unknown, second?: unknown): void {
|
|
125
|
-
setProxyValue<Value>(
|
|
126
|
-
false,
|
|
127
|
-
this.state,
|
|
128
|
-
isStoreObject,
|
|
129
|
-
isKey,
|
|
130
|
-
setObject,
|
|
131
|
-
setProperty,
|
|
132
|
-
first,
|
|
133
|
-
second,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @inheritdoc
|
|
139
|
-
*/
|
|
140
|
-
override subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Subscribe to changes for a specific key
|
|
144
|
-
* @param key Key of the value to subscribe to
|
|
145
|
-
* @param callback Callback for changes
|
|
146
|
-
* @returns Unsubscribe callback
|
|
147
|
-
*/
|
|
148
|
-
override subscribe<Key extends keyof Value>(
|
|
149
|
-
key: Key,
|
|
150
|
-
callback: (value: Value[Key] | undefined) => void,
|
|
151
|
-
): Unsubscribe;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Subscribe to changes for a specific key
|
|
155
|
-
* @param key Key of the value to subscribe to
|
|
156
|
-
* @param callback Callback for changes
|
|
157
|
-
* @returns Unsubscribe callback
|
|
158
|
-
*/
|
|
159
|
-
override subscribe(key: Key, callback: (value: unknown) => void): Unsubscribe;
|
|
160
|
-
|
|
161
|
-
override subscribe(first: Key | GenericCallback, second?: GenericCallback): Unsubscribe {
|
|
162
|
-
if (isKey(first) && typeof second === 'function') {
|
|
163
|
-
return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return typeof first === 'function' ? subscribe(this.state, first) : noop;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Update the value _(based on the current value)_
|
|
171
|
-
* @param callback Callback to update the value
|
|
172
|
-
*/
|
|
173
|
-
update(callback: (value: Value) => Value): void {
|
|
174
|
-
const updated = callback(this.state.value);
|
|
175
|
-
|
|
176
|
-
if (updated == null || isPlainObject(updated)) {
|
|
177
|
-
setObject(this.state, updated);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
11
|
+
import {getSimpleValue} from '../helpers/value';
|
|
12
|
+
import type {
|
|
13
|
+
Computed,
|
|
14
|
+
ComputedEffect,
|
|
15
|
+
ReactiveOptions,
|
|
16
|
+
ReactiveState,
|
|
17
|
+
ReactiveStore,
|
|
18
|
+
ReadonlyInstances,
|
|
19
|
+
Unsubscribe,
|
|
20
|
+
} from '../models';
|
|
21
|
+
import {noop, subscribe, unsubscribe} from '../subscription';
|
|
22
|
+
import {reactive} from './reactive';
|
|
23
|
+
import {getReadonlyInstance} from './readonly';
|
|
181
24
|
|
|
182
25
|
function isStoreObject<Value extends PlainObject>(value: unknown): value is Value | undefined {
|
|
183
26
|
return value == null || isPlainObject(value);
|
|
@@ -215,6 +58,34 @@ function setObject(state: ReactiveState<PlainObject, never>, value: PlainObject
|
|
|
215
58
|
stopBatch();
|
|
216
59
|
}
|
|
217
60
|
|
|
61
|
+
function peekStoreValue<Value extends PlainObject>(
|
|
62
|
+
state: ReactiveState<Value, Value>,
|
|
63
|
+
first?: unknown,
|
|
64
|
+
second?: boolean,
|
|
65
|
+
): unknown {
|
|
66
|
+
let value: unknown;
|
|
67
|
+
|
|
68
|
+
if (isKey(first)) {
|
|
69
|
+
value = state.value[first];
|
|
70
|
+
} else {
|
|
71
|
+
value = state.value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!(first === true || second === true)) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
return value.slice();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isPlainObject(value)) {
|
|
83
|
+
return {...value};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
|
|
218
89
|
function setProperty<Value extends PlainObject>(
|
|
219
90
|
state: ReactiveState<Value, Value>,
|
|
220
91
|
key: unknown,
|
|
@@ -225,6 +96,7 @@ function setProperty<Value extends PlainObject>(
|
|
|
225
96
|
|
|
226
97
|
/**
|
|
227
98
|
* Create a reactive store from a function result
|
|
99
|
+
*
|
|
228
100
|
* @param value Initial object value
|
|
229
101
|
* @param options Reactivity options
|
|
230
102
|
* @returns Reactive store
|
|
@@ -232,10 +104,11 @@ function setProperty<Value extends PlainObject>(
|
|
|
232
104
|
export function store<Value extends PlainObject>(
|
|
233
105
|
value: () => Value | Promise<Value>,
|
|
234
106
|
options?: ReactiveOptions<Value>,
|
|
235
|
-
):
|
|
107
|
+
): ReactiveStore<Value>;
|
|
236
108
|
|
|
237
109
|
/**
|
|
238
110
|
* Create a reactive store from a promise
|
|
111
|
+
*
|
|
239
112
|
* @param value Initial object value
|
|
240
113
|
* @param options Reactivity options
|
|
241
114
|
* @returns Reactive store
|
|
@@ -243,10 +116,11 @@ export function store<Value extends PlainObject>(
|
|
|
243
116
|
export function store<Value extends PlainObject>(
|
|
244
117
|
value: Promise<Value>,
|
|
245
118
|
options?: ReactiveOptions<Value>,
|
|
246
|
-
):
|
|
119
|
+
): ReactiveStore<Value>;
|
|
247
120
|
|
|
248
121
|
/**
|
|
249
122
|
* Create a reactive store
|
|
123
|
+
*
|
|
250
124
|
* @param value Initial object value
|
|
251
125
|
* @param options Reactivity options
|
|
252
126
|
* @returns Reactive store
|
|
@@ -254,15 +128,94 @@ export function store<Value extends PlainObject>(
|
|
|
254
128
|
export function store<Value extends PlainObject>(
|
|
255
129
|
value: Value,
|
|
256
130
|
options?: ReactiveOptions<Value>,
|
|
257
|
-
):
|
|
131
|
+
): ReactiveStore<Value>;
|
|
258
132
|
|
|
259
133
|
export function store<Value extends PlainObject>(
|
|
260
134
|
value: Value | (() => Value | Promise<Value>) | Promise<Value>,
|
|
261
135
|
options?: ReactiveOptions<Value>,
|
|
262
|
-
):
|
|
263
|
-
const
|
|
136
|
+
): ReactiveStore<Value> {
|
|
137
|
+
const [rx, state] = reactive<Value>(undefined as never, options);
|
|
138
|
+
|
|
139
|
+
const keyed = new Map<Key, [Computed<unknown>, ComputedEffect]>();
|
|
140
|
+
const readonlies: ReadonlyInstances<Value> = {};
|
|
141
|
+
|
|
142
|
+
let instance: Record<string, GenericCallback> = {};
|
|
143
|
+
|
|
144
|
+
state.value = new Proxy({} as Value, {
|
|
145
|
+
set: (target: Value, property: PropertyKey, value: unknown) =>
|
|
146
|
+
setValueInProxy({
|
|
147
|
+
target,
|
|
148
|
+
property,
|
|
149
|
+
state,
|
|
150
|
+
value,
|
|
151
|
+
isArray: false,
|
|
152
|
+
}),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const handlers = {
|
|
156
|
+
...rx,
|
|
157
|
+
get: (value?: unknown): unknown =>
|
|
158
|
+
isKey(value)
|
|
159
|
+
? getReactiveValueInProxy(instance as ReactiveStore<Value>, keyed, value, false).get()
|
|
160
|
+
: getSimpleValue(state),
|
|
161
|
+
peek: (first?: unknown, second?: boolean): unknown => peekStoreValue(state, first, second),
|
|
162
|
+
subscribe: (first: Key | GenericCallback, second?: GenericCallback): Unsubscribe => {
|
|
163
|
+
if (isKey(first) && typeof second === 'function') {
|
|
164
|
+
return getReactiveValueInProxy(
|
|
165
|
+
instance as ReactiveStore<Value>,
|
|
166
|
+
keyed,
|
|
167
|
+
first,
|
|
168
|
+
false,
|
|
169
|
+
).subscribe(second);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return typeof first === 'function' ? subscribe(state, first) : noop;
|
|
173
|
+
},
|
|
174
|
+
unsubscribe: (first: Key | GenericCallback, second?: GenericCallback) => {
|
|
175
|
+
if (isKey(first) && typeof second === 'function') {
|
|
176
|
+
getReactiveValueInProxy(instance as ReactiveStore<Value>, keyed, first, false)?.unsubscribe(
|
|
177
|
+
second,
|
|
178
|
+
);
|
|
179
|
+
} else if (typeof first === 'function') {
|
|
180
|
+
unsubscribe(state, first);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
instance = {
|
|
186
|
+
...handlers,
|
|
187
|
+
asReadonly: (frozen?: unknown) =>
|
|
188
|
+
getReadonlyInstance(state, readonlies, handlers, frozen === true),
|
|
189
|
+
notify(): void {
|
|
190
|
+
emityProxyValues(state, keyed);
|
|
191
|
+
},
|
|
192
|
+
set: (first?: unknown, second?: unknown) => {
|
|
193
|
+
setProxyValue<Value>(
|
|
194
|
+
false,
|
|
195
|
+
state,
|
|
196
|
+
isStoreObject,
|
|
197
|
+
isKey,
|
|
198
|
+
setObject,
|
|
199
|
+
setProperty,
|
|
200
|
+
first,
|
|
201
|
+
second,
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
update: (callback: (value: Value) => Value) => {
|
|
205
|
+
const updated = callback(state.value);
|
|
206
|
+
|
|
207
|
+
if (updated == null || isPlainObject(updated)) {
|
|
208
|
+
setObject(state, updated);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
Object.defineProperty(instance, NAME_MORA, {
|
|
214
|
+
enumerable: false,
|
|
215
|
+
value: NAME_STORE,
|
|
216
|
+
});
|
|
264
217
|
|
|
265
218
|
instance.set(value);
|
|
266
219
|
|
|
267
|
-
return instance
|
|
220
|
+
return Object.freeze(instance) as ReactiveStore<Value>;
|
|
268
221
|
}
|
package/types/constants.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export declare const NAME_EFFECT = "effect";
|
|
|
12
12
|
export declare const NAME_MORA = "$mora";
|
|
13
13
|
export declare const NAME_SIGNAL = "signal";
|
|
14
14
|
export declare const NAME_STORE = "store";
|
|
15
|
-
export declare const
|
|
15
|
+
export declare const NAME_ALL: Set<string>;
|
|
16
16
|
export declare const PROPERTY_LENGTH = "length";
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { startBatch, stopBatch } from './batch';
|
|
2
2
|
export { effect, type Effect } from './effect';
|
|
3
|
-
export { isArray, isComputed, isEffect, isReactive, isSignal
|
|
3
|
+
export { isArray, isComputed, isEffect, isReactive, isSignal } from './helpers/is';
|
|
4
4
|
export type { Unsubscribe } from './models';
|
|
5
5
|
export { array, type ReactiveArray } from './value/array';
|
|
6
6
|
export { computed, type Computed } from './value/computed';
|
package/types/value/array.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ export declare class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
131
131
|
/**
|
|
132
132
|
* Create a reactive array
|
|
133
133
|
* @param value Initial array of items
|
|
134
|
-
* @param options
|
|
134
|
+
* @param options Reactivity options
|
|
135
135
|
* @returns Reactive array
|
|
136
136
|
*/
|
|
137
137
|
export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
@@ -10,5 +10,8 @@ export declare class Computed<Value> extends Reactive<Value> {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Create a computed value
|
|
13
|
+
* @param callback Callback to compute the value
|
|
14
|
+
* @param options Reactivity options
|
|
15
|
+
* @returns Computed value
|
|
13
16
|
*/
|
|
14
17
|
export declare function computed<Value>(callback: () => Value, options?: ReactiveOptions<Value>): Computed<Value>;
|
package/types/value/signal.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export declare class Signal<Value> extends Reactive<Value> {
|
|
|
20
20
|
/**
|
|
21
21
|
* Create a reactive value
|
|
22
22
|
* @param value Initial value
|
|
23
|
-
* @param options
|
|
23
|
+
* @param options Reactivity options
|
|
24
24
|
* @returns Reactive value
|
|
25
25
|
*/
|
|
26
26
|
export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
package/types/value/store.d.ts
CHANGED
|
@@ -88,7 +88,7 @@ export declare class Store<Value extends PlainObject> extends Reactive<Value, Va
|
|
|
88
88
|
/**
|
|
89
89
|
* Create a reactive store
|
|
90
90
|
* @param value Initial object value
|
|
91
|
-
* @param options
|
|
91
|
+
* @param options Reactivity options
|
|
92
92
|
* @returns Reactive store
|
|
93
93
|
*/
|
|
94
94
|
export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): Store<Value>;
|