@oscarpalmer/mora 0.28.0 → 0.30.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 +0 -1
- package/dist/constants.mjs +4 -3
- package/dist/effect.d.mts +5 -8
- package/dist/effect.mjs +23 -19
- package/dist/helpers/is.d.mts +9 -9
- package/dist/helpers/is.mjs +6 -0
- 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 +21 -3
- package/dist/index.d.mts +7 -8
- package/dist/index.mjs +1 -1
- package/dist/models.d.mts +356 -18
- package/dist/mora.full.mjs +458 -409
- 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 +91 -137
- package/dist/value/computed.d.mts +4 -12
- package/dist/value/computed.mjs +54 -50
- package/dist/value/reactive.d.mts +3 -38
- package/dist/value/reactive.mjs +10 -49
- package/dist/value/signal.d.mts +5 -21
- package/dist/value/signal.mjs +27 -49
- package/dist/value/store.d.mts +9 -92
- package/dist/value/store.mjs +42 -49
- package/package.json +8 -8
- package/src/batch.ts +22 -9
- package/src/constants.ts +3 -4
- package/src/effect.ts +31 -26
- package/src/helpers/is.ts +11 -10
- package/src/helpers/proxy.ts +23 -18
- package/src/helpers/value.ts +38 -3
- package/src/index.ts +6 -7
- package/src/models.ts +431 -16
- package/src/subscription.ts +20 -20
- package/src/value/array.ts +183 -265
- package/src/value/computed.ts +80 -74
- package/src/value/reactive.ts +16 -64
- package/src/value/signal.ts +34 -71
- package/src/value/store.ts +84 -177
package/dist/value/reactive.mjs
CHANGED
|
@@ -1,55 +1,16 @@
|
|
|
1
|
-
import { NAME_MORA } from "../constants.mjs";
|
|
2
|
-
import { subscribe, unsubscribe } from "../subscription.mjs";
|
|
3
1
|
//#region src/value/reactive.ts
|
|
4
|
-
|
|
5
|
-
state = {
|
|
2
|
+
function reactive(value, options) {
|
|
3
|
+
const state = {
|
|
6
4
|
computeds: /* @__PURE__ */ new Set(),
|
|
7
5
|
effects: /* @__PURE__ */ new Set(),
|
|
8
|
-
equal: Object.is,
|
|
6
|
+
equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
|
|
9
7
|
subscriptions: /* @__PURE__ */ new Map(),
|
|
10
|
-
value
|
|
8
|
+
value
|
|
11
9
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Get the value _(without reactivity)_
|
|
19
|
-
* @return Current value
|
|
20
|
-
*/
|
|
21
|
-
peek() {
|
|
22
|
-
return this.state.value;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Subscribe to changes
|
|
26
|
-
* @param callback Callback for changes
|
|
27
|
-
* @return Unsubscribe callback
|
|
28
|
-
*/
|
|
29
|
-
subscribe(callback) {
|
|
30
|
-
return subscribe(this.state, callback);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* JSON representation of the value
|
|
34
|
-
* @return JSON value
|
|
35
|
-
*/
|
|
36
|
-
toJSON() {
|
|
37
|
-
return this.get();
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* String representation of the value
|
|
41
|
-
* @return Value as string
|
|
42
|
-
*/
|
|
43
|
-
toString() {
|
|
44
|
-
return String(this.get());
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Unsubscribe from changes
|
|
48
|
-
* @param callback Callback to unsubscribe
|
|
49
|
-
*/
|
|
50
|
-
unsubscribe(callback) {
|
|
51
|
-
unsubscribe(this.state, callback);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
10
|
+
return [{
|
|
11
|
+
toJSON: () => state.value,
|
|
12
|
+
toString: () => String(state.value)
|
|
13
|
+
}, state];
|
|
14
|
+
}
|
|
54
15
|
//#endregion
|
|
55
|
-
export {
|
|
16
|
+
export { reactive };
|
package/dist/value/signal.d.mts
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ReactiveOptions } from "../models.mjs";
|
|
3
|
-
|
|
1
|
+
import { ReactiveOptions, Signal } from "../models.mjs";
|
|
4
2
|
//#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
3
|
/**
|
|
23
4
|
* Create a reactive value from a function result
|
|
5
|
+
*
|
|
24
6
|
* @param value Initial value
|
|
25
7
|
* @param options Reactivity options
|
|
26
8
|
* @returns Reactive value
|
|
@@ -28,6 +10,7 @@ declare class Signal<Value> extends Reactive<Value> {
|
|
|
28
10
|
declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
29
11
|
/**
|
|
30
12
|
* Create a reactive value from a promise
|
|
13
|
+
*
|
|
31
14
|
* @param value Initial value
|
|
32
15
|
* @param options Reactivity options
|
|
33
16
|
* @returns Reactive value
|
|
@@ -35,10 +18,11 @@ declare function signal<Value>(value: () => Value | Promise<Value>, options?: Re
|
|
|
35
18
|
declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
36
19
|
/**
|
|
37
20
|
* Create a reactive value
|
|
21
|
+
*
|
|
38
22
|
* @param value Initial value
|
|
39
23
|
* @param options Reactivity options
|
|
40
24
|
* @returns Reactive value
|
|
41
25
|
*/
|
|
42
26
|
declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
43
27
|
//#endregion
|
|
44
|
-
export {
|
|
28
|
+
export { signal };
|
package/dist/value/signal.mjs
CHANGED
|
@@ -1,59 +1,37 @@
|
|
|
1
|
-
import { NAME_SIGNAL } from "../constants.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { NAME_MORA, NAME_SIGNAL } from "../constants.mjs";
|
|
2
|
+
import { emitValue, getSimpleValue, handleSimpleValue } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribe } from "../subscription.mjs";
|
|
4
|
+
import { reactive } from "./reactive.mjs";
|
|
4
5
|
//#region src/value/signal.ts
|
|
5
|
-
var Signal = class extends Reactive {
|
|
6
|
-
constructor(value, options) {
|
|
7
|
-
super(NAME_SIGNAL, value, options);
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* @inheritdoc
|
|
11
|
-
*/
|
|
12
|
-
get() {
|
|
13
|
-
return getValue(this.state);
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Set the value
|
|
17
|
-
* @param value New value
|
|
18
|
-
*/
|
|
19
|
-
set(value) {
|
|
20
|
-
setValue(this.state, value);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Update the value _(based on the current value)_
|
|
24
|
-
* @param callback Callback to update the value
|
|
25
|
-
*/
|
|
26
|
-
update(callback) {
|
|
27
|
-
this.set(callback(this.state.value));
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
6
|
function setAndEmit(state, value) {
|
|
31
7
|
if (!state.equal(state.value, value)) {
|
|
32
8
|
state.value = value;
|
|
33
9
|
emitValue(state);
|
|
34
10
|
}
|
|
35
11
|
}
|
|
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
|
-
}
|
|
53
12
|
function signal(value, options) {
|
|
54
|
-
const
|
|
55
|
-
instance
|
|
56
|
-
|
|
13
|
+
const [rx, state] = reactive(void 0, options);
|
|
14
|
+
const instance = {
|
|
15
|
+
...rx,
|
|
16
|
+
get: () => getSimpleValue(state),
|
|
17
|
+
peek: () => state.value,
|
|
18
|
+
set: (value) => {
|
|
19
|
+
handleSimpleValue(state, value, setAndEmit);
|
|
20
|
+
},
|
|
21
|
+
update: (callback) => {
|
|
22
|
+
handleSimpleValue(state, callback(state.value), setAndEmit);
|
|
23
|
+
},
|
|
24
|
+
subscribe: (callback) => subscribe(state, callback),
|
|
25
|
+
unsubscribe: (callback) => {
|
|
26
|
+
state.subscriptions.delete(callback);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(instance, NAME_MORA, {
|
|
30
|
+
enumerable: false,
|
|
31
|
+
value: NAME_SIGNAL
|
|
32
|
+
});
|
|
33
|
+
handleSimpleValue(state, value, setAndEmit);
|
|
34
|
+
return Object.freeze(instance);
|
|
57
35
|
}
|
|
58
36
|
//#endregion
|
|
59
|
-
export {
|
|
37
|
+
export { signal };
|
package/dist/value/store.d.mts
CHANGED
|
@@ -1,112 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Key, PlainObject } from "@oscarpalmer/atoms/models";
|
|
4
|
-
|
|
1
|
+
import { ReactiveOptions, ReactiveStore } from "../models.mjs";
|
|
2
|
+
import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
5
3
|
//#region src/value/store.d.ts
|
|
6
|
-
declare class Store<Value extends PlainObject> extends Reactive<Value, Value> {
|
|
7
|
-
#private;
|
|
8
|
-
constructor(value: Value, options?: ReactiveOptions<Value>);
|
|
9
|
-
/**
|
|
10
|
-
* @inheritdoc
|
|
11
|
-
*/
|
|
12
|
-
get(): Value;
|
|
13
|
-
/**
|
|
14
|
-
* Get a value by key
|
|
15
|
-
* @param key Key of the value to get
|
|
16
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
17
|
-
*/
|
|
18
|
-
get<Key extends keyof Value>(key: Key): Value[Key];
|
|
19
|
-
/**
|
|
20
|
-
* Get a value by key
|
|
21
|
-
* @param key Key of the value to get
|
|
22
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
23
|
-
*/
|
|
24
|
-
get(key: Key): unknown;
|
|
25
|
-
/**
|
|
26
|
-
* Notify dependents of changes
|
|
27
|
-
*
|
|
28
|
-
* _This bypasses equality checks and will immediately notify dependents.
|
|
29
|
-
* Use this only if you're modifying nested data that would be ignored by equality checks._
|
|
30
|
-
*/
|
|
31
|
-
notify(): void;
|
|
32
|
-
/**
|
|
33
|
-
* Get the value _(without reactivity)_
|
|
34
|
-
* @returns The current value
|
|
35
|
-
*/
|
|
36
|
-
peek(): Value;
|
|
37
|
-
/**
|
|
38
|
-
* Get a value by key _(without reactivity)_
|
|
39
|
-
* @param key Key of the value to get
|
|
40
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
41
|
-
*/
|
|
42
|
-
peek<Key extends keyof Value>(key: Key): Value[Key];
|
|
43
|
-
/**
|
|
44
|
-
* Get a value by key _(without reactivity)_
|
|
45
|
-
* @param key Key of the value to get
|
|
46
|
-
* @returns Value for the specified key, or `undefined` if it doesn't exist
|
|
47
|
-
*/
|
|
48
|
-
peek(key: Key): unknown;
|
|
49
|
-
/**
|
|
50
|
-
* Set the value
|
|
51
|
-
* @param value New value _(defaults to an empty object)_
|
|
52
|
-
*/
|
|
53
|
-
set(value?: Value | (() => null | undefined | Value | Promise<null | undefined | Value>) | Promise<null | undefined | Value>): void;
|
|
54
|
-
/**
|
|
55
|
-
* Set a value by key
|
|
56
|
-
* @param key Key of the value to set
|
|
57
|
-
* @param value New value
|
|
58
|
-
*/
|
|
59
|
-
set<Key extends keyof Value>(key: Key, value: Value[Key] | (() => Value[Key] | Promise<Value[Key]>) | Promise<Value[Key]>): void;
|
|
60
|
-
/**
|
|
61
|
-
* Set a value by key
|
|
62
|
-
* @param key Key of the value to set
|
|
63
|
-
* @param value New value
|
|
64
|
-
*/
|
|
65
|
-
set(key: Key, value: unknown): void;
|
|
66
|
-
/**
|
|
67
|
-
* @inheritdoc
|
|
68
|
-
*/
|
|
69
|
-
subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
70
|
-
/**
|
|
71
|
-
* Subscribe to changes for a specific key
|
|
72
|
-
* @param key Key of the value to subscribe to
|
|
73
|
-
* @param callback Callback for changes
|
|
74
|
-
* @returns Unsubscribe callback
|
|
75
|
-
*/
|
|
76
|
-
subscribe<Key extends keyof Value>(key: Key, callback: (value: Value[Key] | undefined) => void): Unsubscribe;
|
|
77
|
-
/**
|
|
78
|
-
* Subscribe to changes for a specific key
|
|
79
|
-
* @param key Key of the value to subscribe to
|
|
80
|
-
* @param callback Callback for changes
|
|
81
|
-
* @returns Unsubscribe callback
|
|
82
|
-
*/
|
|
83
|
-
subscribe(key: Key, callback: (value: unknown) => void): Unsubscribe;
|
|
84
|
-
/**
|
|
85
|
-
* Update the value _(based on the current value)_
|
|
86
|
-
* @param callback Callback to update the value
|
|
87
|
-
*/
|
|
88
|
-
update(callback: (value: Value) => Value): void;
|
|
89
|
-
}
|
|
90
4
|
/**
|
|
91
5
|
* Create a reactive store from a function result
|
|
6
|
+
*
|
|
92
7
|
* @param value Initial object value
|
|
93
8
|
* @param options Reactivity options
|
|
94
9
|
* @returns Reactive store
|
|
95
10
|
*/
|
|
96
|
-
declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>):
|
|
11
|
+
declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
97
12
|
/**
|
|
98
13
|
* Create a reactive store from a promise
|
|
14
|
+
*
|
|
99
15
|
* @param value Initial object value
|
|
100
16
|
* @param options Reactivity options
|
|
101
17
|
* @returns Reactive store
|
|
102
18
|
*/
|
|
103
|
-
declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>):
|
|
19
|
+
declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
104
20
|
/**
|
|
105
21
|
* Create a reactive store
|
|
22
|
+
*
|
|
106
23
|
* @param value Initial object value
|
|
107
24
|
* @param options Reactivity options
|
|
108
25
|
* @returns Reactive store
|
|
109
26
|
*/
|
|
110
|
-
declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>):
|
|
27
|
+
declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
111
28
|
//#endregion
|
|
112
|
-
export {
|
|
29
|
+
export { store };
|
package/dist/value/store.mjs
CHANGED
|
@@ -1,53 +1,11 @@
|
|
|
1
|
-
import { NAME_STORE } from "../constants.mjs";
|
|
1
|
+
import { NAME_MORA, NAME_STORE } from "../constants.mjs";
|
|
2
2
|
import { startBatch, stopBatch } from "../batch.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { getSimpleValue } from "../helpers/value.mjs";
|
|
4
|
+
import { noop, subscribe, unsubscribe } from "../subscription.mjs";
|
|
5
|
+
import { reactive } from "./reactive.mjs";
|
|
6
6
|
import { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy } from "../helpers/proxy.mjs";
|
|
7
7
|
import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
8
8
|
//#region src/value/store.ts
|
|
9
|
-
var Store = class extends Reactive {
|
|
10
|
-
#keyed = /* @__PURE__ */ new Map();
|
|
11
|
-
constructor(value, options) {
|
|
12
|
-
super(NAME_STORE, new Proxy(value, { set: (target, property, value) => setValueInProxy({
|
|
13
|
-
target,
|
|
14
|
-
property,
|
|
15
|
-
value,
|
|
16
|
-
isArray: false,
|
|
17
|
-
state: this.state
|
|
18
|
-
}) }), options);
|
|
19
|
-
}
|
|
20
|
-
get(key) {
|
|
21
|
-
return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue(this.state);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Notify dependents of changes
|
|
25
|
-
*
|
|
26
|
-
* _This bypasses equality checks and will immediately notify dependents.
|
|
27
|
-
* Use this only if you're modifying nested data that would be ignored by equality checks._
|
|
28
|
-
*/
|
|
29
|
-
notify() {
|
|
30
|
-
emityProxyValues(this.state, this.#keyed);
|
|
31
|
-
}
|
|
32
|
-
peek(key) {
|
|
33
|
-
return isKey(key) ? this.state.value[key] : { ...this.state.value };
|
|
34
|
-
}
|
|
35
|
-
set(first, second) {
|
|
36
|
-
setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
|
|
37
|
-
}
|
|
38
|
-
subscribe(first, second) {
|
|
39
|
-
if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
|
|
40
|
-
return typeof first === "function" ? subscribe(this.state, first) : noop;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Update the value _(based on the current value)_
|
|
44
|
-
* @param callback Callback to update the value
|
|
45
|
-
*/
|
|
46
|
-
update(callback) {
|
|
47
|
-
const updated = callback(this.state.value);
|
|
48
|
-
if (updated == null || isPlainObject(updated)) setObject(this.state, updated);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
9
|
function isStoreObject(value) {
|
|
52
10
|
return value == null || isPlainObject(value);
|
|
53
11
|
}
|
|
@@ -73,9 +31,44 @@ function setProperty(state, key, value) {
|
|
|
73
31
|
state.value[key] = value;
|
|
74
32
|
}
|
|
75
33
|
function store(value, options) {
|
|
76
|
-
const
|
|
34
|
+
const [rx, state] = reactive(void 0, options);
|
|
35
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
36
|
+
state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy({
|
|
37
|
+
target,
|
|
38
|
+
property,
|
|
39
|
+
state,
|
|
40
|
+
value,
|
|
41
|
+
isArray: false
|
|
42
|
+
}) });
|
|
43
|
+
const instance = {
|
|
44
|
+
...rx,
|
|
45
|
+
get: (value) => isKey(value) ? getReactiveValueInProxy(instance, keyed, value, false).get() : getSimpleValue(state),
|
|
46
|
+
notify() {
|
|
47
|
+
emityProxyValues(state, keyed);
|
|
48
|
+
},
|
|
49
|
+
peek: (value) => isKey(value) ? state.value[value] : { ...state.value },
|
|
50
|
+
set: (first, second) => {
|
|
51
|
+
setProxyValue(false, state, isStoreObject, isKey, setObject, setProperty, first, second);
|
|
52
|
+
},
|
|
53
|
+
subscribe: (first, second) => {
|
|
54
|
+
if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(instance, keyed, first, false).subscribe(second);
|
|
55
|
+
return typeof first === "function" ? subscribe(state, first) : noop;
|
|
56
|
+
},
|
|
57
|
+
unsubscribe: (first, second) => {
|
|
58
|
+
if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
|
|
59
|
+
else if (typeof first === "function") unsubscribe(state, first);
|
|
60
|
+
},
|
|
61
|
+
update: (callback) => {
|
|
62
|
+
const updated = callback(state.value);
|
|
63
|
+
if (updated == null || isPlainObject(updated)) setObject(state, updated);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
Object.defineProperty(instance, NAME_MORA, {
|
|
67
|
+
enumerable: false,
|
|
68
|
+
value: NAME_STORE
|
|
69
|
+
});
|
|
77
70
|
instance.set(value);
|
|
78
|
-
return instance;
|
|
71
|
+
return Object.freeze(instance);
|
|
79
72
|
}
|
|
80
73
|
//#endregion
|
|
81
|
-
export {
|
|
74
|
+
export { store };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -35,18 +35,18 @@
|
|
|
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.190"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/node": "^
|
|
46
|
-
"@vitest/coverage-istanbul": "
|
|
47
|
-
"jsdom": "^
|
|
48
|
-
"tsdown": "^0.
|
|
49
|
-
"typescript": "^
|
|
45
|
+
"@types/node": "^26.2",
|
|
46
|
+
"@vitest/coverage-istanbul": "4.1.10",
|
|
47
|
+
"jsdom": "^30",
|
|
48
|
+
"tsdown": "^0.22",
|
|
49
|
+
"typescript": "^6",
|
|
50
50
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
|
51
51
|
"vite-plus": "latest",
|
|
52
52
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
package/src/batch.ts
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
import {BATCH} from './constants';
|
|
2
2
|
import {runEffect} from './effect';
|
|
3
|
-
import {
|
|
3
|
+
import type {EffectState, Subscription} from './models';
|
|
4
4
|
|
|
5
5
|
export function flushHandlers(): void {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
if (BATCH.flushing) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
BATCH.flushing = true;
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
|
|
14
|
+
const handlers = [...BATCH.handlers];
|
|
15
|
+
const {length} = handlers;
|
|
16
|
+
|
|
17
|
+
BATCH.handlers.clear();
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
for (let index = 0; index < length; index += 1) {
|
|
20
|
+
const handler = handlers[index];
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
if (typeof (handler as Subscription).destroy === 'function') {
|
|
23
|
+
(handler as Subscription).callback((handler as Subscription).state.value);
|
|
24
|
+
} else {
|
|
25
|
+
runEffect(handler as EffectState);
|
|
26
|
+
}
|
|
16
27
|
}
|
|
17
28
|
}
|
|
29
|
+
} finally {
|
|
30
|
+
BATCH.flushing = false;
|
|
18
31
|
}
|
|
19
32
|
}
|
|
20
33
|
|
package/src/constants.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {Active, Batch} from './models';
|
|
3
|
-
import type {Subscription} from './subscription';
|
|
1
|
+
import type {Active, Batch, EffectState, Subscription} from './models';
|
|
4
2
|
|
|
5
3
|
export const ACTIVE: Active = {};
|
|
6
4
|
|
|
@@ -12,7 +10,8 @@ export const ARRAY_PEEK = 10;
|
|
|
12
10
|
|
|
13
11
|
export const BATCH: Batch = {
|
|
14
12
|
depth: 0,
|
|
15
|
-
|
|
13
|
+
flushing: false,
|
|
14
|
+
handlers: new Set<EffectState | Subscription>(),
|
|
16
15
|
};
|
|
17
16
|
|
|
18
17
|
export const METHODS_AFFECTING_LENGTH = new Set<string>(['pop', 'push', 'shift', 'unshift']);
|
package/src/effect.ts
CHANGED
|
@@ -1,42 +1,47 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {ACTIVE, NAME_EFFECT
|
|
3
|
-
import type {
|
|
2
|
+
import {ACTIVE, NAME_EFFECT} from './constants';
|
|
3
|
+
import type {Effect, EffectState} from './models';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Create an effect
|
|
7
|
+
*
|
|
8
|
+
* @param callback Callback for handling signal effects
|
|
9
|
+
* @returns Effect
|
|
10
|
+
*/
|
|
11
|
+
export function effect(callback: GenericCallback): Effect {
|
|
12
|
+
if (typeof callback !== 'function') {
|
|
13
|
+
throw new TypeError('Effect callback must be a function');
|
|
14
|
+
}
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
return getEffect(callback)[0];
|
|
17
|
+
}
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
function getEffect(callback: GenericCallback): [Effect, EffectState] {
|
|
20
|
+
const state: EffectState = {
|
|
21
|
+
callback,
|
|
22
|
+
};
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
const instance = Object.freeze({
|
|
25
|
+
$mora: NAME_EFFECT,
|
|
26
|
+
});
|
|
18
27
|
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
runEffect(state);
|
|
29
|
+
|
|
30
|
+
return [instance, state];
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
export function
|
|
33
|
+
export function internalEffect(callback: GenericCallback): EffectState {
|
|
34
|
+
return getEffect(callback)[1];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function runEffect(state: EffectState): void {
|
|
24
38
|
const previousEffect = ACTIVE.effect;
|
|
25
39
|
|
|
26
|
-
ACTIVE.effect =
|
|
40
|
+
ACTIVE.effect = state;
|
|
27
41
|
|
|
28
42
|
try {
|
|
29
|
-
|
|
43
|
+
state.callback();
|
|
30
44
|
} finally {
|
|
31
45
|
ACTIVE.effect = previousEffect;
|
|
32
46
|
}
|
|
33
47
|
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Create an effect
|
|
37
|
-
* @param callback Callback for handling signal effects
|
|
38
|
-
* @returns Effect
|
|
39
|
-
*/
|
|
40
|
-
export function effect(callback: GenericCallback): Effect {
|
|
41
|
-
return typeof callback === 'function' ? new Effect(callback) : (undefined as never);
|
|
42
|
-
}
|
package/src/helpers/is.ts
CHANGED
|
@@ -8,15 +8,11 @@ import {
|
|
|
8
8
|
NAME_SIGNAL,
|
|
9
9
|
NAME_STORE,
|
|
10
10
|
} from '../constants';
|
|
11
|
-
import type {Effect} from '../
|
|
12
|
-
import type {ReactiveArray} from '../value/array';
|
|
13
|
-
import type {Computed} from '../value/computed';
|
|
14
|
-
import type {Reactive} from '../value/reactive';
|
|
15
|
-
import type {Signal} from '../value/signal';
|
|
16
|
-
import type {Store} from '../value/store';
|
|
11
|
+
import type {Computed, Effect, Reactive, ReactiveArray, ReactiveStore, Signal} from '../models';
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Is the value a reactive array?
|
|
15
|
+
*
|
|
20
16
|
* @param value Value to check
|
|
21
17
|
* @returns True if value is a {@link ReactiveArray}
|
|
22
18
|
*/
|
|
@@ -26,6 +22,7 @@ export function isArray<Item>(value: unknown): value is ReactiveArray<Item> {
|
|
|
26
22
|
|
|
27
23
|
/**
|
|
28
24
|
* Is the value a computed signal?
|
|
25
|
+
*
|
|
29
26
|
* @param value Value to check
|
|
30
27
|
* @returns True if value is a {@link Computed}
|
|
31
28
|
*/
|
|
@@ -35,6 +32,7 @@ export function isComputed<Value>(value: unknown): value is Computed<Value> {
|
|
|
35
32
|
|
|
36
33
|
/**
|
|
37
34
|
* Is the value an effect?
|
|
35
|
+
*
|
|
38
36
|
* @param value Value to check
|
|
39
37
|
* @returns True if value is an {@link Effect}
|
|
40
38
|
*/
|
|
@@ -55,15 +53,17 @@ function isMora<T>(value: unknown, name: string | Set<string>): value is T {
|
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
55
|
* Is the value reactive?
|
|
56
|
+
*
|
|
58
57
|
* @param value Value to check
|
|
59
58
|
* @returns True if value is a {@link Reactive}
|
|
60
59
|
*/
|
|
61
|
-
export function isReactive<Value
|
|
62
|
-
return isMora<Reactive<Value
|
|
60
|
+
export function isReactive<Value>(value: unknown): value is Reactive<Value> {
|
|
61
|
+
return isMora<Reactive<Value>>(value, NAME_ALL);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
/**
|
|
66
65
|
* Is the value a signal?
|
|
66
|
+
*
|
|
67
67
|
* @param value Value to check
|
|
68
68
|
* @returns True if value is a {@link Signal}
|
|
69
69
|
*/
|
|
@@ -73,9 +73,10 @@ export function isSignal<Value>(value: unknown): value is Signal<Value> {
|
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* Is the value a reactive store?
|
|
76
|
+
*
|
|
76
77
|
* @param value Value to check
|
|
77
78
|
* @returns True if value is a {@link Store}
|
|
78
79
|
*/
|
|
79
|
-
export function isStore<Value extends PlainObject>(value: unknown): value is
|
|
80
|
-
return isMora<
|
|
80
|
+
export function isStore<Value extends PlainObject>(value: unknown): value is ReactiveStore<Value> {
|
|
81
|
+
return isMora<ReactiveStore<Value>>(value, NAME_STORE);
|
|
81
82
|
}
|