@oscarpalmer/mora 0.27.0 → 0.29.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 +19 -1
- package/dist/effect.d.mts +26 -1
- package/dist/helpers/is.d.mts +4 -2
- package/dist/helpers/proxy.d.mts +3 -2
- package/dist/helpers/proxy.mjs +36 -14
- package/dist/helpers/value.d.mts +1 -1
- package/dist/helpers/value.mjs +2 -1
- package/dist/index.d.mts +5 -2
- package/dist/models.d.mts +61 -1
- package/dist/mora.full.mjs +187 -84
- package/dist/subscription.d.mts +14 -1
- package/dist/value/array.d.mts +20 -4
- package/dist/value/array.mjs +19 -16
- package/dist/value/computed.d.mts +20 -1
- package/dist/value/computed.mjs +32 -11
- package/dist/value/reactive.d.mts +50 -1
- package/dist/value/reactive.mjs +5 -0
- package/dist/value/signal.d.mts +43 -1
- package/dist/value/signal.mjs +27 -11
- package/dist/value/store.d.mts +18 -3
- package/dist/value/store.mjs +31 -11
- package/package.json +6 -5
- package/src/effect.ts +10 -0
- package/src/helpers/proxy.ts +64 -17
- package/src/helpers/value.ts +2 -1
- package/src/models.ts +3 -1
- package/src/value/array.ts +74 -18
- package/src/value/computed.ts +65 -30
- package/src/value/reactive.ts +13 -0
- package/src/value/signal.ts +77 -9
- package/src/value/store.ts +100 -11
- 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/constants-Cy6_M9Vk.d.mts +0 -20
- package/dist/effect-BkupB1p9.d.mts +0 -17
- package/dist/models-QwNga87R.d.mts +0 -148
package/dist/value/array.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Reactive } from "./reactive.mjs";
|
|
2
|
+
import { Computed } from "./computed.mjs";
|
|
3
|
+
import { ReactiveOptions, Unsubscribe } from "../models.mjs";
|
|
4
|
+
import { PROPERTY_LENGTH } from "../constants.mjs";
|
|
3
5
|
|
|
4
6
|
//#region src/value/array.d.ts
|
|
5
7
|
declare class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
@@ -81,13 +83,13 @@ declare class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
81
83
|
* Set the value
|
|
82
84
|
* @param value New array of items _(defaults to an empty array)_
|
|
83
85
|
*/
|
|
84
|
-
set(value?: Item[]): void;
|
|
86
|
+
set(value?: Item[] | (() => null | undefined | Item[] | Promise<null | undefined | Item[]>) | Promise<null | undefined | Item[]>): void;
|
|
85
87
|
/**
|
|
86
88
|
* Set the value at an index
|
|
87
89
|
* @param index Index of item to set __(if negative, starts from the end)_
|
|
88
90
|
* @param value New item
|
|
89
91
|
*/
|
|
90
|
-
set(index: number, value: Item): void;
|
|
92
|
+
set(index: number, value: Item | (() => Item | Promise<Item>) | Promise<Item>): void;
|
|
91
93
|
/**
|
|
92
94
|
* Set the length of the array
|
|
93
95
|
* @param value New array length
|
|
@@ -129,6 +131,20 @@ declare class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
129
131
|
*/
|
|
130
132
|
update(callback: (value: Item[]) => Item[]): void;
|
|
131
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Create a reactive array from a function result
|
|
136
|
+
* @param value Initial array of items
|
|
137
|
+
* @param options Reactivity options
|
|
138
|
+
* @returns Reactive array
|
|
139
|
+
*/
|
|
140
|
+
declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
141
|
+
/**
|
|
142
|
+
* Create a reactive array from a promise
|
|
143
|
+
* @param value Initial array of items
|
|
144
|
+
* @param options Reactivity options
|
|
145
|
+
* @returns Reactive array
|
|
146
|
+
*/
|
|
147
|
+
declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
132
148
|
/**
|
|
133
149
|
* Create a reactive array
|
|
134
150
|
* @param value Initial array of items
|
package/dist/value/array.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { noop, subscribe } from "../subscription.mjs";
|
|
|
3
3
|
import { Reactive } from "./reactive.mjs";
|
|
4
4
|
import { computed } from "./computed.mjs";
|
|
5
5
|
import { emitValue, equalArrays, getValue } from "../helpers/value.mjs";
|
|
6
|
-
import { emityProxyValues, getReactiveValueInProxy, setValueInProxy } from "../helpers/proxy.mjs";
|
|
6
|
+
import { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy } from "../helpers/proxy.mjs";
|
|
7
7
|
import { signal } from "./signal.mjs";
|
|
8
8
|
//#region src/value/array.ts
|
|
9
9
|
var ReactiveArray = class extends Reactive {
|
|
@@ -72,7 +72,7 @@ var ReactiveArray = class extends Reactive {
|
|
|
72
72
|
}
|
|
73
73
|
peek(value) {
|
|
74
74
|
if (value === "length") return this.#size.peek();
|
|
75
|
-
return typeof value === "number" ? this.state.value.at(value) :
|
|
75
|
+
return typeof value === "number" ? this.state.value.at(value) : this.state.value.slice();
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
78
|
* Remove and return the last item of the array
|
|
@@ -90,9 +90,7 @@ var ReactiveArray = class extends Reactive {
|
|
|
90
90
|
return this.state.value.push(...items);
|
|
91
91
|
}
|
|
92
92
|
set(first, second) {
|
|
93
|
-
|
|
94
|
-
else if (first === "length") this.length = second;
|
|
95
|
-
else if (typeof first === "number" && !Number.isNaN(first)) setAtIndex(this.state.value, first, second);
|
|
93
|
+
setProxyValue(true, this.state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
|
|
96
94
|
}
|
|
97
95
|
/**
|
|
98
96
|
* Remove and return the first item of the array
|
|
@@ -132,18 +130,20 @@ var ReactiveArray = class extends Reactive {
|
|
|
132
130
|
if (updated == null || Array.isArray(updated)) this.set(updated);
|
|
133
131
|
}
|
|
134
132
|
};
|
|
135
|
-
/**
|
|
136
|
-
* Create a reactive array
|
|
137
|
-
* @param value Initial array of items
|
|
138
|
-
* @param options Reactivity options
|
|
139
|
-
* @returns Reactive array
|
|
140
|
-
*/
|
|
141
133
|
function array(value, options) {
|
|
142
|
-
|
|
134
|
+
const instance = new ReactiveArray([], options);
|
|
135
|
+
instance.set(value);
|
|
136
|
+
return instance;
|
|
137
|
+
}
|
|
138
|
+
function isArrayIndex(value) {
|
|
139
|
+
return typeof value === "number";
|
|
140
|
+
}
|
|
141
|
+
function isArrayValue(value) {
|
|
142
|
+
return value == null || Array.isArray(value);
|
|
143
143
|
}
|
|
144
144
|
function updateArray(type, array, state, length) {
|
|
145
145
|
const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
|
|
146
|
-
const previousArray = affectsLength ? [] :
|
|
146
|
+
const previousArray = affectsLength ? [] : array.slice();
|
|
147
147
|
const previousLength = array.length;
|
|
148
148
|
return (...args) => {
|
|
149
149
|
const result = array[type](...args);
|
|
@@ -154,9 +154,12 @@ function updateArray(type, array, state, length) {
|
|
|
154
154
|
return result;
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
|
-
function
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
function setArray(state, value) {
|
|
158
|
+
state.value.splice(0, state.value.length, ...value ?? []);
|
|
159
|
+
}
|
|
160
|
+
function setAtIndex(state, index, value) {
|
|
161
|
+
const actual = index < 0 ? state.value.length + index : index;
|
|
162
|
+
if (actual > -1) state.value[actual] = value;
|
|
160
163
|
}
|
|
161
164
|
//#endregion
|
|
162
165
|
export { ReactiveArray, array };
|
|
@@ -1,2 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Reactive } from "./reactive.mjs";
|
|
2
|
+
import { ReactiveOptions } from "../models.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/value/computed.d.ts
|
|
5
|
+
declare class Computed<Value> extends Reactive<Value> {
|
|
6
|
+
private readonly effect;
|
|
7
|
+
constructor(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>);
|
|
8
|
+
/**
|
|
9
|
+
* @inheritdoc
|
|
10
|
+
*/
|
|
11
|
+
get(): Value;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a computed value
|
|
15
|
+
* @param callback Callback to compute the value
|
|
16
|
+
* @param options Reactivity options
|
|
17
|
+
* @returns Computed value
|
|
18
|
+
*/
|
|
19
|
+
declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
20
|
+
//#endregion
|
|
2
21
|
export { Computed, computed };
|
package/dist/value/computed.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ACTIVE, BATCH, NAME_COMPUTED } from "../constants.mjs";
|
|
2
2
|
import { effect, runEffect } from "../effect.mjs";
|
|
3
|
+
import { flushHandlers } from "../batch.mjs";
|
|
3
4
|
import { Reactive } from "./reactive.mjs";
|
|
4
5
|
//#region src/value/computed.ts
|
|
5
6
|
var Computed = class extends Reactive {
|
|
@@ -10,18 +11,10 @@ var Computed = class extends Reactive {
|
|
|
10
11
|
constructor(callback, options) {
|
|
11
12
|
super(NAME_COMPUTED, void 0, options);
|
|
12
13
|
this.effect.instance = effect(() => {
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const value = callback();
|
|
17
|
-
ACTIVE.computed = previousComputed;
|
|
18
|
-
if (!this.state.equal(this.state.value, value)) {
|
|
19
|
-
this.state.value = value;
|
|
20
|
-
for (const computed of this.state.computeds) computed.effect.dirty = true;
|
|
21
|
-
for (const effect of this.state.effects) BATCH.handlers.add(effect);
|
|
22
|
-
for (const [, subscription] of this.state.subscriptions) subscription.callback(value);
|
|
14
|
+
if (this.effect.dirty) {
|
|
15
|
+
setValue(this, this.state, callback);
|
|
16
|
+
this.effect.dirty = false;
|
|
23
17
|
}
|
|
24
|
-
this.effect.dirty = false;
|
|
25
18
|
});
|
|
26
19
|
}
|
|
27
20
|
/**
|
|
@@ -43,5 +36,33 @@ var Computed = class extends Reactive {
|
|
|
43
36
|
function computed(callback, options) {
|
|
44
37
|
return new Computed(callback, options);
|
|
45
38
|
}
|
|
39
|
+
function setAndEmit(state, value) {
|
|
40
|
+
if (state.equal(state.value, value)) return;
|
|
41
|
+
state.value = value;
|
|
42
|
+
for (const computed of state.computeds) computed.effect.dirty = true;
|
|
43
|
+
for (const effect of state.effects) BATCH.handlers.add(effect);
|
|
44
|
+
for (const [, subscription] of state.subscriptions) subscription.callback(value);
|
|
45
|
+
flushHandlers();
|
|
46
|
+
}
|
|
47
|
+
function setValue(instance, state, callback) {
|
|
48
|
+
const previousComputed = ACTIVE.computed;
|
|
49
|
+
ACTIVE.computed = instance;
|
|
50
|
+
try {
|
|
51
|
+
const value = callback();
|
|
52
|
+
if (value instanceof Promise) {
|
|
53
|
+
state.promise = value;
|
|
54
|
+
value.then((resolvedValue) => {
|
|
55
|
+
if (state.promise === value) {
|
|
56
|
+
state.promise = void 0;
|
|
57
|
+
setAndEmit(state, resolvedValue);
|
|
58
|
+
}
|
|
59
|
+
}).catch(() => {
|
|
60
|
+
if (state.promise === value) state.promise = void 0;
|
|
61
|
+
});
|
|
62
|
+
} else setAndEmit(state, value);
|
|
63
|
+
} finally {
|
|
64
|
+
ACTIVE.computed = previousComputed;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
46
67
|
//#endregion
|
|
47
68
|
export { Computed, computed };
|
|
@@ -1,2 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactiveOptions, ReactiveState, Unsubscribe } from "../models.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/value/reactive.d.ts
|
|
4
|
+
declare abstract class Reactive<Value, Equal = Value> {
|
|
5
|
+
/**
|
|
6
|
+
* Internal name of the reactive value
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
protected readonly $mora: string;
|
|
11
|
+
/**
|
|
12
|
+
* Internal state of the reactive value
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
protected readonly state: ReactiveState<Value, Equal>;
|
|
17
|
+
constructor(name: string, value: Value, options?: ReactiveOptions<Equal>);
|
|
18
|
+
/**
|
|
19
|
+
* Get the value
|
|
20
|
+
* @return Current value
|
|
21
|
+
*/
|
|
22
|
+
abstract get(): Value;
|
|
23
|
+
/**
|
|
24
|
+
* Get the value _(without reactivity)_
|
|
25
|
+
* @return Current value
|
|
26
|
+
*/
|
|
27
|
+
peek(): Value;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to changes
|
|
30
|
+
* @param callback Callback for changes
|
|
31
|
+
* @return Unsubscribe callback
|
|
32
|
+
*/
|
|
33
|
+
subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
34
|
+
/**
|
|
35
|
+
* JSON representation of the value
|
|
36
|
+
* @return JSON value
|
|
37
|
+
*/
|
|
38
|
+
toJSON(): Value;
|
|
39
|
+
/**
|
|
40
|
+
* String representation of the value
|
|
41
|
+
* @return Value as string
|
|
42
|
+
*/
|
|
43
|
+
toString(): string;
|
|
44
|
+
/**
|
|
45
|
+
* Unsubscribe from changes
|
|
46
|
+
* @param callback Callback to unsubscribe
|
|
47
|
+
*/
|
|
48
|
+
unsubscribe(callback: (value: Value) => void): void;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
2
51
|
export { Reactive };
|
package/dist/value/reactive.mjs
CHANGED
|
@@ -2,6 +2,11 @@ import { NAME_MORA } from "../constants.mjs";
|
|
|
2
2
|
import { subscribe, unsubscribe } from "../subscription.mjs";
|
|
3
3
|
//#region src/value/reactive.ts
|
|
4
4
|
var Reactive = class {
|
|
5
|
+
/**
|
|
6
|
+
* Internal state of the reactive value
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
5
10
|
state = {
|
|
6
11
|
computeds: /* @__PURE__ */ new Set(),
|
|
7
12
|
effects: /* @__PURE__ */ new Set(),
|
package/dist/value/signal.d.mts
CHANGED
|
@@ -1,2 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Reactive } from "./reactive.mjs";
|
|
2
|
+
import { ReactiveOptions } from "../models.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/value/signal.d.ts
|
|
5
|
+
declare class Signal<Value> extends Reactive<Value> {
|
|
6
|
+
constructor(value: Value, options?: ReactiveOptions<Value>);
|
|
7
|
+
/**
|
|
8
|
+
* @inheritdoc
|
|
9
|
+
*/
|
|
10
|
+
get(): Value;
|
|
11
|
+
/**
|
|
12
|
+
* Set the value
|
|
13
|
+
* @param value New value
|
|
14
|
+
*/
|
|
15
|
+
set(value: Value | (() => Value | Promise<Value>) | Promise<Value>): void;
|
|
16
|
+
/**
|
|
17
|
+
* Update the value _(based on the current value)_
|
|
18
|
+
* @param callback Callback to update the value
|
|
19
|
+
*/
|
|
20
|
+
update(callback: (value: Value) => Value): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a reactive value from a function result
|
|
24
|
+
* @param value Initial value
|
|
25
|
+
* @param options Reactivity options
|
|
26
|
+
* @returns Reactive value
|
|
27
|
+
*/
|
|
28
|
+
declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
29
|
+
/**
|
|
30
|
+
* Create a reactive value from a promise
|
|
31
|
+
* @param value Initial value
|
|
32
|
+
* @param options Reactivity options
|
|
33
|
+
* @returns Reactive value
|
|
34
|
+
*/
|
|
35
|
+
declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
36
|
+
/**
|
|
37
|
+
* Create a reactive value
|
|
38
|
+
* @param value Initial value
|
|
39
|
+
* @param options Reactivity options
|
|
40
|
+
* @returns Reactive value
|
|
41
|
+
*/
|
|
42
|
+
declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
43
|
+
//#endregion
|
|
2
44
|
export { Signal, signal };
|
package/dist/value/signal.mjs
CHANGED
|
@@ -17,10 +17,7 @@ var Signal = class extends Reactive {
|
|
|
17
17
|
* @param value New value
|
|
18
18
|
*/
|
|
19
19
|
set(value) {
|
|
20
|
-
|
|
21
|
-
this.state.value = value;
|
|
22
|
-
emitValue(this.state);
|
|
23
|
-
}
|
|
20
|
+
setValue(this.state, value);
|
|
24
21
|
}
|
|
25
22
|
/**
|
|
26
23
|
* Update the value _(based on the current value)_
|
|
@@ -30,14 +27,33 @@ var Signal = class extends Reactive {
|
|
|
30
27
|
this.set(callback(this.state.value));
|
|
31
28
|
}
|
|
32
29
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
function setAndEmit(state, value) {
|
|
31
|
+
if (!state.equal(state.value, value)) {
|
|
32
|
+
state.value = value;
|
|
33
|
+
emitValue(state);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function setValue(state, value) {
|
|
37
|
+
try {
|
|
38
|
+
let actual = value;
|
|
39
|
+
if (typeof value === "function") actual = value();
|
|
40
|
+
if (actual instanceof Promise) {
|
|
41
|
+
state.promise = actual;
|
|
42
|
+
actual.then((value) => {
|
|
43
|
+
if (actual === state.promise) {
|
|
44
|
+
state.promise = void 0;
|
|
45
|
+
setAndEmit(state, value);
|
|
46
|
+
}
|
|
47
|
+
}).catch(() => {
|
|
48
|
+
if (actual === state.promise) state.promise = void 0;
|
|
49
|
+
});
|
|
50
|
+
} else setAndEmit(state, actual);
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
39
53
|
function signal(value, options) {
|
|
40
|
-
|
|
54
|
+
const instance = new Signal(void 0, options);
|
|
55
|
+
instance.set(value);
|
|
56
|
+
return instance;
|
|
41
57
|
}
|
|
42
58
|
//#endregion
|
|
43
59
|
export { Signal, signal };
|
package/dist/value/store.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Reactive } from "./reactive.mjs";
|
|
2
|
+
import { ReactiveOptions, Unsubscribe } from "../models.mjs";
|
|
2
3
|
import { Key, PlainObject } from "@oscarpalmer/atoms/models";
|
|
3
4
|
|
|
4
5
|
//#region src/value/store.d.ts
|
|
@@ -49,13 +50,13 @@ declare class Store<Value extends PlainObject> extends Reactive<Value, Value> {
|
|
|
49
50
|
* Set the value
|
|
50
51
|
* @param value New value _(defaults to an empty object)_
|
|
51
52
|
*/
|
|
52
|
-
set(value?: Value): void;
|
|
53
|
+
set(value?: Value | (() => null | undefined | Value | Promise<null | undefined | Value>) | Promise<null | undefined | Value>): void;
|
|
53
54
|
/**
|
|
54
55
|
* Set a value by key
|
|
55
56
|
* @param key Key of the value to set
|
|
56
57
|
* @param value New value
|
|
57
58
|
*/
|
|
58
|
-
set<Key extends keyof Value>(key: Key, value: Value[Key]): void;
|
|
59
|
+
set<Key extends keyof Value>(key: Key, value: Value[Key] | (() => Value[Key] | Promise<Value[Key]>) | Promise<Value[Key]>): void;
|
|
59
60
|
/**
|
|
60
61
|
* Set a value by key
|
|
61
62
|
* @param key Key of the value to set
|
|
@@ -86,6 +87,20 @@ declare class Store<Value extends PlainObject> extends Reactive<Value, Value> {
|
|
|
86
87
|
*/
|
|
87
88
|
update(callback: (value: Value) => Value): void;
|
|
88
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Create a reactive store from a function result
|
|
92
|
+
* @param value Initial object value
|
|
93
|
+
* @param options Reactivity options
|
|
94
|
+
* @returns Reactive store
|
|
95
|
+
*/
|
|
96
|
+
declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Store<Value>;
|
|
97
|
+
/**
|
|
98
|
+
* Create a reactive store from a promise
|
|
99
|
+
* @param value Initial object value
|
|
100
|
+
* @param options Reactivity options
|
|
101
|
+
* @returns Reactive store
|
|
102
|
+
*/
|
|
103
|
+
declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): Store<Value>;
|
|
89
104
|
/**
|
|
90
105
|
* Create a reactive store
|
|
91
106
|
* @param value Initial object value
|
package/dist/value/store.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NAME_STORE } from "../constants.mjs";
|
|
2
|
+
import { startBatch, stopBatch } from "../batch.mjs";
|
|
2
3
|
import { noop, subscribe } from "../subscription.mjs";
|
|
3
4
|
import { Reactive } from "./reactive.mjs";
|
|
4
5
|
import { getValue } from "../helpers/value.mjs";
|
|
@@ -32,8 +33,7 @@ var Store = class extends Reactive {
|
|
|
32
33
|
return isKey(key) ? this.state.value[key] : { ...this.state.value };
|
|
33
34
|
}
|
|
34
35
|
set(first, second) {
|
|
35
|
-
|
|
36
|
-
else if (first == null || isPlainObject(first)) setProxyValue(this.state.value, first ?? {});
|
|
36
|
+
setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
|
|
37
37
|
}
|
|
38
38
|
subscribe(first, second) {
|
|
39
39
|
if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
|
|
@@ -44,18 +44,38 @@ var Store = class extends Reactive {
|
|
|
44
44
|
* @param callback Callback to update the value
|
|
45
45
|
*/
|
|
46
46
|
update(callback) {
|
|
47
|
-
const updated = callback(
|
|
48
|
-
if (updated == null || isPlainObject(updated))
|
|
47
|
+
const updated = callback(this.state.value);
|
|
48
|
+
if (updated == null || isPlainObject(updated)) setObject(this.state, updated);
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
function isStoreObject(value) {
|
|
52
|
+
return value == null || isPlainObject(value);
|
|
53
|
+
}
|
|
54
|
+
function setObject(state, value) {
|
|
55
|
+
startBatch();
|
|
56
|
+
const actual = value ?? {};
|
|
57
|
+
const proxy = state.value;
|
|
58
|
+
const proxyKeys = Object.keys(proxy);
|
|
59
|
+
const actualKeys = Object.keys(actual);
|
|
60
|
+
let { length } = proxyKeys;
|
|
61
|
+
for (let index = 0; index < length; index += 1) {
|
|
62
|
+
const key = proxyKeys[index];
|
|
63
|
+
proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
|
|
64
|
+
}
|
|
65
|
+
length = actualKeys.length;
|
|
66
|
+
for (let index = 0; index < length; index += 1) {
|
|
67
|
+
const key = actualKeys[index];
|
|
68
|
+
if (!proxyKeys.includes(key)) proxy[key] = actual[key];
|
|
69
|
+
}
|
|
70
|
+
stopBatch();
|
|
71
|
+
}
|
|
72
|
+
function setProperty(state, key, value) {
|
|
73
|
+
state.value[key] = value;
|
|
74
|
+
}
|
|
57
75
|
function store(value, options) {
|
|
58
|
-
|
|
76
|
+
const instance = new Store({}, options);
|
|
77
|
+
instance.set(value);
|
|
78
|
+
return instance;
|
|
59
79
|
}
|
|
60
80
|
//#endregion
|
|
61
81
|
export { Store, store };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -35,16 +35,17 @@
|
|
|
35
35
|
"build": "vpx vp run tsdown:build && vpx vp pack",
|
|
36
36
|
"tsdown:build": "vpx tsdown -c ./tsdown.config.ts",
|
|
37
37
|
"tsdown:watch": "vpx tsdown -c ./tsdown.config.ts --watch",
|
|
38
|
-
"test": "
|
|
38
|
+
"test": "npx vp test run --coverage",
|
|
39
39
|
"test:leak": "vpx vp test run --detect-async-leaks --coverage"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oscarpalmer/atoms": "^0.
|
|
42
|
+
"@oscarpalmer/atoms": "^0.184"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@
|
|
45
|
+
"@oxlint/plugins": "^1.62",
|
|
46
|
+
"@types/node": "^25.6",
|
|
46
47
|
"@vitest/coverage-istanbul": "^4.1",
|
|
47
|
-
"jsdom": "^
|
|
48
|
+
"jsdom": "^29.1",
|
|
48
49
|
"tsdown": "^0.21",
|
|
49
50
|
"typescript": "^5.9",
|
|
50
51
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
package/src/effect.ts
CHANGED
|
@@ -3,8 +3,18 @@ import {ACTIVE, NAME_EFFECT, NAME_MORA} from './constants';
|
|
|
3
3
|
import type {EffectState, InternalEffect} from './models';
|
|
4
4
|
|
|
5
5
|
export class Effect {
|
|
6
|
+
/**
|
|
7
|
+
* Internal name of the effect
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
6
11
|
declare private readonly $mora: string;
|
|
7
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Internal state of the effect
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
8
18
|
declare private readonly state: EffectState;
|
|
9
19
|
|
|
10
20
|
constructor(callback: GenericCallback) {
|
package/src/helpers/proxy.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {ArrayOrPlainObject, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {startBatch, stopBatch} from '../batch';
|
|
3
2
|
import {PROPERTY_LENGTH} from '../constants';
|
|
4
3
|
import type {InternalComputed, ReactiveState, SetValueInProxyParameters} from '../models';
|
|
5
4
|
import type {ReactiveArray} from '../value/array';
|
|
@@ -66,33 +65,81 @@ export function getReactiveValueInProxy(
|
|
|
66
65
|
return item;
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
export function setProxyValue
|
|
70
|
-
|
|
68
|
+
export function setProxyValue<Value, Item = Value>(
|
|
69
|
+
array: boolean,
|
|
70
|
+
state: ReactiveState<Value, Item>,
|
|
71
|
+
isObject: (value: unknown) => value is Value | undefined,
|
|
72
|
+
isProperty: (value: unknown) => boolean,
|
|
73
|
+
setObject: (state: ReactiveState<Value, Item>, value: Value | undefined) => void,
|
|
74
|
+
setProperty: (state: ReactiveState<Value, Item>, property: unknown, value: Item) => void,
|
|
75
|
+
first?: unknown,
|
|
76
|
+
second?: unknown,
|
|
77
|
+
): void {
|
|
78
|
+
if (array && first === PROPERTY_LENGTH) {
|
|
79
|
+
(state.value as unknown[]).length = second as number;
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
74
83
|
|
|
75
|
-
|
|
84
|
+
if (isObject(first)) {
|
|
85
|
+
setObject(state, first);
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
const key = proxyKeys[index];
|
|
79
|
-
|
|
80
|
-
(proxy as PlainObject)[key] = valueKeys.includes(key) ? (value as PlainObject)[key] : undefined;
|
|
87
|
+
return;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
const property = isProperty(first);
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
if (array && property && Number.isNaN(first)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
87
95
|
|
|
88
|
-
|
|
89
|
-
const keyedValue = (value as PlainObject)[key];
|
|
96
|
+
let actual = property ? second : first;
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
if (typeof actual === 'function') {
|
|
99
|
+
try {
|
|
100
|
+
actual = (actual as Function)();
|
|
101
|
+
} catch {
|
|
102
|
+
return;
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
|
|
95
|
-
|
|
106
|
+
if (actual instanceof Promise) {
|
|
107
|
+
if (property) {
|
|
108
|
+
state.promises ??= new Map();
|
|
109
|
+
|
|
110
|
+
state.promises.set(first as Key, actual as Promise<never>);
|
|
111
|
+
} else {
|
|
112
|
+
state.promise = actual as Promise<never>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void actual
|
|
116
|
+
.then(value => {
|
|
117
|
+
if (property && state.promises!.get(first as Key) === actual) {
|
|
118
|
+
state.promises!.delete(first as Key);
|
|
119
|
+
|
|
120
|
+
setProperty(state, first, value);
|
|
121
|
+
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!property && isObject(value) && state.promise === actual) {
|
|
126
|
+
state.promise = undefined;
|
|
127
|
+
|
|
128
|
+
setObject(state, value);
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
.catch(() => {
|
|
132
|
+
if (property && state.promises!.get(first as Key) === actual) {
|
|
133
|
+
state.promises!.delete(first as Key);
|
|
134
|
+
} else if (!property && state.promise === actual) {
|
|
135
|
+
state.promise = undefined;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
} else if (property) {
|
|
139
|
+
setProperty(state, first, actual as Item);
|
|
140
|
+
} else if (isObject(actual)) {
|
|
141
|
+
setObject(state, actual);
|
|
142
|
+
}
|
|
96
143
|
}
|
|
97
144
|
|
|
98
145
|
export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
|
package/src/helpers/value.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {round} from '@oscarpalmer/atoms/math';
|
|
1
2
|
import {flushHandlers} from '../batch';
|
|
2
3
|
import {ACTIVE, ARRAY_OFFSET, ARRAY_PEEK, ARRAY_THRESHOLD, BATCH} from '../constants';
|
|
3
4
|
import type {InternalComputed, ReactiveState} from '../models';
|
|
@@ -34,7 +35,7 @@ export function equalArrays<Value>(
|
|
|
34
35
|
let offset = 0;
|
|
35
36
|
|
|
36
37
|
if (length >= ARRAY_THRESHOLD) {
|
|
37
|
-
offset =
|
|
38
|
+
offset = round(length / ARRAY_PEEK);
|
|
38
39
|
offset = offset > ARRAY_OFFSET ? ARRAY_OFFSET : offset;
|
|
39
40
|
|
|
40
41
|
for (let index = 0; index < offset; index += 1) {
|
package/src/models.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
1
|
+
import type {GenericCallback, Key} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import type {Effect} from './effect';
|
|
3
3
|
import type {Subscription} from './subscription';
|
|
4
4
|
import type {Computed} from './value/computed';
|
|
@@ -47,6 +47,8 @@ export type ReactiveState<Value, Equal> = {
|
|
|
47
47
|
computeds: Set<Computed<unknown>>;
|
|
48
48
|
effects: Set<Effect>;
|
|
49
49
|
equal: (first: Equal, second: Equal) => boolean;
|
|
50
|
+
promise?: Promise<Value>;
|
|
51
|
+
promises?: Map<Key, Promise<never>>;
|
|
50
52
|
subscriptions: Map<GenericCallback, Subscription>;
|
|
51
53
|
value: Value;
|
|
52
54
|
};
|