@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/dist/value/array.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ import { ReactiveArray, ReactiveOptions } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Reactive array
|
|
9
9
|
*/
|
|
10
|
-
declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
10
|
+
export declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
11
11
|
/**
|
|
12
12
|
* Create a reactive array from a promise
|
|
13
13
|
*
|
|
@@ -15,7 +15,7 @@ declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: Re
|
|
|
15
15
|
* @param options Reactivity options
|
|
16
16
|
* @returns Reactive array
|
|
17
17
|
*/
|
|
18
|
-
declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
18
|
+
export declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
19
19
|
/**
|
|
20
20
|
* Create a reactive array
|
|
21
21
|
*
|
|
@@ -23,6 +23,5 @@ declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<I
|
|
|
23
23
|
* @param options Reactivity options
|
|
24
24
|
* @returns Reactive array
|
|
25
25
|
*/
|
|
26
|
-
declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { array };
|
|
26
|
+
export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
27
|
+
//#endregion
|
package/dist/value/array.mjs
CHANGED
|
@@ -1,80 +1,54 @@
|
|
|
1
1
|
import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, NAME_MORA } from "../constants.mjs";
|
|
2
|
-
import { emitValue, equalArrays
|
|
3
|
-
import {
|
|
2
|
+
import { emitValue, equalArrays } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
4
4
|
import { reactive } from "./reactive.mjs";
|
|
5
5
|
import { computed } from "./computed.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
7
7
|
import { getReadonlyInstance } from "./readonly.mjs";
|
|
8
8
|
import { signal } from "./signal.mjs";
|
|
9
9
|
import { select } from "@oscarpalmer/atoms/array";
|
|
10
10
|
import { filter } from "@oscarpalmer/atoms/array/filter";
|
|
11
|
-
import { noop } from "@oscarpalmer/atoms/function";
|
|
12
|
-
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
13
11
|
//#region src/value/array.ts
|
|
14
12
|
function array(value, options) {
|
|
15
13
|
const [rx, state] = reactive([], options);
|
|
16
|
-
const
|
|
14
|
+
const isArray = true;
|
|
17
15
|
const length = signal(0);
|
|
16
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
18
17
|
const readonlies = {};
|
|
19
|
-
let instance = {};
|
|
20
18
|
state.value = new Proxy([], {
|
|
21
19
|
get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, state, length) : Reflect.get(target, property),
|
|
22
|
-
set: (target, property, value) => setValueInProxy(
|
|
23
|
-
length,
|
|
24
|
-
property,
|
|
25
|
-
state,
|
|
26
|
-
target,
|
|
27
|
-
value,
|
|
28
|
-
isArray: true
|
|
29
|
-
})
|
|
20
|
+
set: (target, property, value) => setValueInProxy(isArray, state, target, property, value, length)
|
|
30
21
|
});
|
|
31
22
|
function get(value) {
|
|
32
|
-
return
|
|
23
|
+
return value === "length" ? length.get() : getValueInProxy(isArray, instance, state, mapped, value);
|
|
33
24
|
}
|
|
34
25
|
function set(first, second) {
|
|
35
|
-
setProxyValue(true, state,
|
|
26
|
+
setProxyValue(true, state, setArrayValue, setAtIndex, first, second);
|
|
36
27
|
}
|
|
37
|
-
const
|
|
28
|
+
const instance = {
|
|
38
29
|
...rx,
|
|
39
|
-
|
|
40
|
-
peek: (first, second) => peekArrayValue(state, length, first, second),
|
|
41
|
-
subscribe: (first, second) => {
|
|
42
|
-
if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(instance, indiced, first, true).subscribe(second);
|
|
43
|
-
return typeof first === "function" ? subscribe(state, first) : noop;
|
|
44
|
-
},
|
|
45
|
-
unsubscribe: (first, second) => {
|
|
46
|
-
if (typeof first === "number" && typeof second === "function") getReactiveValueInProxy(instance, indiced, first, true)?.unsubscribe(second);
|
|
47
|
-
else if (typeof first === "function") unsubscribe(state, first);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
instance = {
|
|
51
|
-
...handlers,
|
|
52
|
-
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
|
|
30
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
53
31
|
at: (index) => get(index),
|
|
54
32
|
clear: () => {
|
|
55
33
|
state.value.length = 0;
|
|
56
34
|
},
|
|
57
35
|
filter: (callback) => computed(() => filter(get(), callback)),
|
|
36
|
+
get: (value) => get(value),
|
|
58
37
|
map: (callback) => computed(() => get().map(callback)),
|
|
59
|
-
notify: () =>
|
|
60
|
-
|
|
61
|
-
},
|
|
38
|
+
notify: () => emitProxyValues(state, mapped),
|
|
39
|
+
peek: (first, second) => peekArrayValue(state, length, first, second),
|
|
62
40
|
pop: () => state.value.pop(),
|
|
63
41
|
push: (...items) => state.value.push(...items),
|
|
64
42
|
select: (filter, map) => computed(() => select(get(), filter, map)),
|
|
65
|
-
set: (first, second) =>
|
|
66
|
-
set(first, second);
|
|
67
|
-
},
|
|
43
|
+
set: (first, second) => set(first, second),
|
|
68
44
|
shift: () => state.value.shift(),
|
|
69
45
|
splice: (from, to, ...items) => state.value.splice(from, to ?? state.value.length, ...items),
|
|
46
|
+
subscribe: (first, second, third) => subscribeToProxy(isArray, instance, state, mapped, first, second, third),
|
|
70
47
|
unshift: (...items) => state.value.unshift(...items),
|
|
71
|
-
update: (callback) =>
|
|
48
|
+
update: (callback) => updateProxyValue(true, state, setArrayValue, setAtIndex, callback)
|
|
72
49
|
};
|
|
73
50
|
Object.defineProperties(instance, {
|
|
74
|
-
[NAME_MORA]: {
|
|
75
|
-
enumerable: false,
|
|
76
|
-
value: NAME_ARRAY
|
|
77
|
-
},
|
|
51
|
+
[NAME_MORA]: { value: NAME_ARRAY },
|
|
78
52
|
length: {
|
|
79
53
|
enumerable: true,
|
|
80
54
|
get: () => length.get(),
|
|
@@ -84,31 +58,14 @@ function array(value, options) {
|
|
|
84
58
|
set(value);
|
|
85
59
|
return Object.freeze(instance);
|
|
86
60
|
}
|
|
87
|
-
function getArrayValue(instance, indiced, state, length, first) {
|
|
88
|
-
if (typeof first === "number") return getReactiveValueInProxy(instance, indiced, first, true).get();
|
|
89
|
-
return first === "length" ? length.get() : getSimpleValue(state);
|
|
90
|
-
}
|
|
91
|
-
function isArrayIndex(value) {
|
|
92
|
-
return typeof value === "number";
|
|
93
|
-
}
|
|
94
|
-
function isArrayValue(value) {
|
|
95
|
-
return value == null || Array.isArray(value);
|
|
96
|
-
}
|
|
97
61
|
function peekArrayValue(state, length, first, second) {
|
|
98
|
-
|
|
99
|
-
let value;
|
|
100
|
-
if (typeof first === "number") value = state.value.at(first);
|
|
101
|
-
else value = state.value;
|
|
102
|
-
if (!(first === true || second === true)) return value;
|
|
103
|
-
if (Array.isArray(value)) return value.slice();
|
|
104
|
-
if (isPlainObject(value)) return { ...value };
|
|
105
|
-
return value;
|
|
106
|
-
}
|
|
107
|
-
function setArray(state, value) {
|
|
108
|
-
state.value.splice(0, state.value.length, ...value ?? []);
|
|
62
|
+
return first === "length" ? length.peek() : peekValueInProxy(true, state, first, second);
|
|
109
63
|
}
|
|
110
64
|
function setArrayLength(state, value) {
|
|
111
|
-
if (typeof value === "number" && value >= 0 && value !== state.value.length) state.value.length = value;
|
|
65
|
+
if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== state.value.length) state.value.length = value;
|
|
66
|
+
}
|
|
67
|
+
function setArrayValue(state, value) {
|
|
68
|
+
state.value.splice(0, state.value.length, ...value ?? []);
|
|
112
69
|
}
|
|
113
70
|
function setAtIndex(state, index, value) {
|
|
114
71
|
const actual = index < 0 ? state.value.length + index : index;
|
|
@@ -127,9 +84,5 @@ function updateArray(type, array, state, length) {
|
|
|
127
84
|
return result;
|
|
128
85
|
};
|
|
129
86
|
}
|
|
130
|
-
function updateArrayValue(instance, state, callback) {
|
|
131
|
-
const updated = callback(state.value);
|
|
132
|
-
if (updated == null || Array.isArray(updated)) instance.set(updated);
|
|
133
|
-
}
|
|
134
87
|
//#endregion
|
|
135
88
|
export { array };
|
|
@@ -7,7 +7,6 @@ import { Computed, ComputedEffect, ReactiveOptions } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Computed value
|
|
9
9
|
*/
|
|
10
|
-
declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
11
|
-
declare function internalComputed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): [Computed<Value>, ComputedEffect];
|
|
12
|
-
//#endregion
|
|
13
|
-
export { computed, internalComputed };
|
|
10
|
+
export declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
|
|
11
|
+
export declare function internalComputed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): [Computed<Value>, ComputedEffect];
|
|
12
|
+
//#endregion
|
package/dist/value/computed.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA } from "../constants.mjs";
|
|
1
|
+
import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY } from "../constants.mjs";
|
|
2
2
|
import { internalEffect, runEffect } from "../effect.mjs";
|
|
3
|
+
import { handleSimpleValue, peekSimpleValue } from "../helpers/value.mjs";
|
|
3
4
|
import { flushHandlers } from "../batch.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { subscribe } from "../subscription.mjs";
|
|
5
|
+
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
6
6
|
import { reactive } from "./reactive.mjs";
|
|
7
7
|
//#region src/value/computed.ts
|
|
8
8
|
/**
|
|
@@ -16,21 +16,16 @@ function computed(callback, options) {
|
|
|
16
16
|
return getComputed(callback, options)[0];
|
|
17
17
|
}
|
|
18
18
|
function getComputed(callback, options) {
|
|
19
|
+
if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
|
|
19
20
|
const [rx, state] = reactive(void 0, options);
|
|
20
21
|
let fx;
|
|
21
22
|
const instance = {
|
|
22
23
|
...rx,
|
|
23
24
|
get: () => getValue(state, fx),
|
|
24
|
-
peek: () => state.value,
|
|
25
|
-
subscribe: (callback) =>
|
|
26
|
-
unsubscribe: (callback) => {
|
|
27
|
-
state.subscriptions.delete(callback);
|
|
28
|
-
}
|
|
25
|
+
peek: (copy) => peekSimpleValue(state.value, copy === true),
|
|
26
|
+
subscribe: (callback, copy) => subscribeToSignal(state, callback, copy === true)
|
|
29
27
|
};
|
|
30
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
31
|
-
enumerable: false,
|
|
32
|
-
value: NAME_COMPUTED
|
|
33
|
-
});
|
|
28
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_COMPUTED });
|
|
34
29
|
fx = getComputedEffect(state, callback);
|
|
35
30
|
return [Object.freeze(instance), fx];
|
|
36
31
|
}
|
|
@@ -64,8 +59,13 @@ function setAndEmit(state, value) {
|
|
|
64
59
|
if (state.equal(state.value, value)) return;
|
|
65
60
|
state.value = value;
|
|
66
61
|
for (const computed of state.computeds) computed.dirty = true;
|
|
67
|
-
for (const effect of state.effects) BATCH.handlers.
|
|
68
|
-
for (const
|
|
62
|
+
for (const effect of state.effects) BATCH.handlers.set(effect, effect);
|
|
63
|
+
for (const type of SUBSCRIPTION_TYPES) {
|
|
64
|
+
if (type === "frozen") continue;
|
|
65
|
+
const copy = SUBSCRIPTION_TYPES_COPY.has(type);
|
|
66
|
+
const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
|
|
67
|
+
if (subscriptions != null) for (const [, callback] of subscriptions) callback(peekSimpleValue(state.value, copy));
|
|
68
|
+
}
|
|
69
69
|
flushHandlers();
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Reactive, ReactiveOptions, ReactiveState } from "../models.mjs";
|
|
2
2
|
//#region src/value/reactive.d.ts
|
|
3
|
-
declare function reactive<Value,
|
|
4
|
-
//#endregion
|
|
5
|
-
export { reactive };
|
|
3
|
+
export declare function reactive<Value, Item = Value>(value: Value, options?: ReactiveOptions<Item>): [Reactive<Value>, ReactiveState<Value, Item>];
|
|
4
|
+
//#endregion
|
package/dist/value/reactive.mjs
CHANGED
|
@@ -4,7 +4,6 @@ function reactive(value, options) {
|
|
|
4
4
|
computeds: /* @__PURE__ */ new Set(),
|
|
5
5
|
effects: /* @__PURE__ */ new Set(),
|
|
6
6
|
equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
|
|
7
|
-
subscriptions: /* @__PURE__ */ new Map(),
|
|
8
7
|
value
|
|
9
8
|
};
|
|
10
9
|
return [{
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ReactiveState, ReadonlyFrozenSignal, ReadonlyInstances, ReadonlySignal } from "../models.mjs";
|
|
2
|
-
import { GenericCallback } from "@oscarpalmer/atoms/models";
|
|
3
2
|
//#region src/value/readonly.d.ts
|
|
4
|
-
declare function getReadonlyInstance<Value>(state: ReactiveState<Value, never>, instances: ReadonlyInstances<Value>,
|
|
5
|
-
declare function getReadonlySignal<Value>(state: ReactiveState<Value, never>,
|
|
6
|
-
//#endregion
|
|
7
|
-
export { getReadonlyInstance, getReadonlySignal };
|
|
3
|
+
export declare function getReadonlyInstance<Value>(state: ReactiveState<Value, never>, instances: ReadonlyInstances<Value>, frozen: boolean): ReadonlySignal<Value>;
|
|
4
|
+
export declare function getReadonlySignal<Value>(state: ReactiveState<Value, never>, frozen: boolean): ReadonlySignal<Value> | ReadonlyFrozenSignal<Value>;
|
|
5
|
+
//#endregion
|
package/dist/value/readonly.mjs
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import { NAME_MORA, NAME_READONLY } from "../constants.mjs";
|
|
2
|
-
import { getSimpleValue } from "../helpers/value.mjs";
|
|
3
|
-
import {
|
|
1
|
+
import { NAME_MORA, NAME_READONLY, SUBSCRIPTION_TYPE_FROZEN, SUBSCRIPTION_TYPE_READONLY } from "../constants.mjs";
|
|
2
|
+
import { getFrozenValue, getSimpleValue, peekSimpleValue } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToReactive } from "../helpers/subscription.mjs";
|
|
4
4
|
//#region src/value/readonly.ts
|
|
5
|
-
function getReadonlyInstance(state, instances,
|
|
5
|
+
function getReadonlyInstance(state, instances, frozen) {
|
|
6
6
|
const key = frozen ? "frozen" : "original";
|
|
7
|
-
instances[key] ??= getReadonlySignal(state,
|
|
7
|
+
instances[key] ??= getReadonlySignal(state, frozen);
|
|
8
8
|
return instances[key];
|
|
9
9
|
}
|
|
10
|
-
function getReadonlySignal(state,
|
|
10
|
+
function getReadonlySignal(state, frozen) {
|
|
11
|
+
const type = frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY;
|
|
11
12
|
const instance = {
|
|
12
|
-
...handlers,
|
|
13
13
|
get: () => getReadonlyValue(state, false, frozen),
|
|
14
|
-
peek: () => getReadonlyValue(state, true, frozen)
|
|
14
|
+
peek: (copy) => getReadonlyValue(state, true, frozen, copy),
|
|
15
|
+
subscribe: (callback) => subscribeToReactive(type, state, callback)
|
|
15
16
|
};
|
|
16
17
|
Object.defineProperties(instance, {
|
|
17
|
-
[NAME_MORA]: {
|
|
18
|
-
enumerable: false,
|
|
19
|
-
value: NAME_READONLY
|
|
20
|
-
},
|
|
18
|
+
[NAME_MORA]: { value: NAME_READONLY },
|
|
21
19
|
frozen: {
|
|
22
20
|
enumerable: true,
|
|
23
21
|
value: frozen
|
|
@@ -25,13 +23,11 @@ function getReadonlySignal(state, handlers, frozen) {
|
|
|
25
23
|
});
|
|
26
24
|
return Object.freeze(instance);
|
|
27
25
|
}
|
|
28
|
-
function getReadonlyValue(state, peek, frozen) {
|
|
29
|
-
let value
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
else value = state.value;
|
|
34
|
-
return Object.freeze(value);
|
|
26
|
+
function getReadonlyValue(state, peek, frozen, copy) {
|
|
27
|
+
let value;
|
|
28
|
+
if (peek) value = peekSimpleValue(state.value, copy === true);
|
|
29
|
+
else value = getSimpleValue(state);
|
|
30
|
+
return frozen ? getFrozenValue(value) : value;
|
|
35
31
|
}
|
|
36
32
|
//#endregion
|
|
37
33
|
export { getReadonlyInstance, getReadonlySignal };
|
package/dist/value/signal.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ import { ReactiveOptions, Signal } from "../models.mjs";
|
|
|
7
7
|
* @param options Reactivity options
|
|
8
8
|
* @returns Reactive value
|
|
9
9
|
*/
|
|
10
|
-
declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
10
|
+
export declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
11
11
|
/**
|
|
12
12
|
* Create a reactive value from a promise
|
|
13
13
|
*
|
|
@@ -15,7 +15,7 @@ declare function signal<Value>(value: () => Value | Promise<Value>, options?: Re
|
|
|
15
15
|
* @param options Reactivity options
|
|
16
16
|
* @returns Reactive value
|
|
17
17
|
*/
|
|
18
|
-
declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
18
|
+
export declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
19
19
|
/**
|
|
20
20
|
* Create a reactive value
|
|
21
21
|
*
|
|
@@ -23,6 +23,5 @@ declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<
|
|
|
23
23
|
* @param options Reactivity options
|
|
24
24
|
* @returns Reactive value
|
|
25
25
|
*/
|
|
26
|
-
declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { signal };
|
|
26
|
+
export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
27
|
+
//#endregion
|
package/dist/value/signal.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NAME_MORA, NAME_SIGNAL } from "../constants.mjs";
|
|
2
|
-
import { emitValue, getSimpleValue, handleSimpleValue } from "../helpers/value.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { emitValue, getSimpleValue, handleSimpleValue, peekSimpleValue, updateSimpleValue } from "../helpers/value.mjs";
|
|
3
|
+
import { subscribeToSignal } from "../helpers/subscription.mjs";
|
|
4
4
|
import { reactive } from "./reactive.mjs";
|
|
5
5
|
import { getReadonlyInstance } from "./readonly.mjs";
|
|
6
6
|
//#region src/value/signal.ts
|
|
@@ -13,29 +13,16 @@ function setAndEmit(state, value) {
|
|
|
13
13
|
function signal(value, options) {
|
|
14
14
|
const [rx, state] = reactive(void 0, options);
|
|
15
15
|
const readonlies = {};
|
|
16
|
-
const handlers = {
|
|
17
|
-
...rx,
|
|
18
|
-
subscribe: (callback) => subscribe(state, callback),
|
|
19
|
-
unsubscribe: (callback) => {
|
|
20
|
-
state.subscriptions.delete(callback);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
16
|
const instance = {
|
|
24
|
-
...
|
|
25
|
-
asReadonly: (frozen) => getReadonlyInstance(state, readonlies,
|
|
17
|
+
...rx,
|
|
18
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
26
19
|
get: () => getSimpleValue(state),
|
|
27
|
-
peek: () => state.value,
|
|
28
|
-
set: (value) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
update: (callback) => {
|
|
32
|
-
handleSimpleValue(state, callback(state.value), setAndEmit);
|
|
33
|
-
}
|
|
20
|
+
peek: (copy) => peekSimpleValue(state.value, copy === true),
|
|
21
|
+
set: (value) => handleSimpleValue(state, value, setAndEmit),
|
|
22
|
+
subscribe: (callback, copy) => subscribeToSignal(state, callback, copy === true),
|
|
23
|
+
update: (callback) => updateSimpleValue(state, callback, setAndEmit)
|
|
34
24
|
};
|
|
35
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
36
|
-
enumerable: false,
|
|
37
|
-
value: NAME_SIGNAL
|
|
38
|
-
});
|
|
25
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_SIGNAL });
|
|
39
26
|
handleSimpleValue(state, value, setAndEmit);
|
|
40
27
|
return Object.freeze(instance);
|
|
41
28
|
}
|
package/dist/value/store.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ import { PlainObject } from "@oscarpalmer/atoms/models";
|
|
|
8
8
|
* @param options Reactivity options
|
|
9
9
|
* @returns Reactive store
|
|
10
10
|
*/
|
|
11
|
-
declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
11
|
+
export declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
12
12
|
/**
|
|
13
13
|
* Create a reactive store from a promise
|
|
14
14
|
*
|
|
@@ -16,7 +16,7 @@ declare function store<Value extends PlainObject>(value: () => Value | Promise<V
|
|
|
16
16
|
* @param options Reactivity options
|
|
17
17
|
* @returns Reactive store
|
|
18
18
|
*/
|
|
19
|
-
declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
19
|
+
export declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
20
20
|
/**
|
|
21
21
|
* Create a reactive store
|
|
22
22
|
*
|
|
@@ -24,6 +24,5 @@ declare function store<Value extends PlainObject>(value: Promise<Value>, options
|
|
|
24
24
|
* @param options Reactivity options
|
|
25
25
|
* @returns Reactive store
|
|
26
26
|
*/
|
|
27
|
-
declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { store };
|
|
27
|
+
export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
|
|
28
|
+
//#endregion
|
package/dist/value/store.mjs
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { NAME_MORA, NAME_STORE } from "../constants.mjs";
|
|
2
2
|
import { startBatch, stopBatch } from "../batch.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { noop, subscribe, unsubscribe } from "../subscription.mjs";
|
|
3
|
+
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
5
4
|
import { reactive } from "./reactive.mjs";
|
|
6
|
-
import {
|
|
5
|
+
import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
7
6
|
import { getReadonlyInstance } from "./readonly.mjs";
|
|
8
|
-
import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
9
7
|
//#region src/value/store.ts
|
|
10
|
-
function
|
|
11
|
-
|
|
8
|
+
function setPropertyValue(state, key, value) {
|
|
9
|
+
state.value[key] = value;
|
|
12
10
|
}
|
|
13
|
-
function
|
|
11
|
+
function setStoreValue(state, value) {
|
|
14
12
|
startBatch();
|
|
15
13
|
const actual = value ?? {};
|
|
16
14
|
const proxy = state.value;
|
|
@@ -28,61 +26,23 @@ function setObject(state, value) {
|
|
|
28
26
|
}
|
|
29
27
|
stopBatch();
|
|
30
28
|
}
|
|
31
|
-
function peekStoreValue(state, first, second) {
|
|
32
|
-
let value;
|
|
33
|
-
if (isKey(first)) value = state.value[first];
|
|
34
|
-
else value = state.value;
|
|
35
|
-
if (!(first === true || second === true)) return value;
|
|
36
|
-
if (Array.isArray(value)) return value.slice();
|
|
37
|
-
if (isPlainObject(value)) return { ...value };
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
function setProperty(state, key, value) {
|
|
41
|
-
state.value[key] = value;
|
|
42
|
-
}
|
|
43
29
|
function store(value, options) {
|
|
44
30
|
const [rx, state] = reactive(void 0, options);
|
|
31
|
+
const isArray = false;
|
|
45
32
|
const keyed = /* @__PURE__ */ new Map();
|
|
46
33
|
const readonlies = {};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
target,
|
|
50
|
-
property,
|
|
51
|
-
state,
|
|
52
|
-
value,
|
|
53
|
-
isArray: false
|
|
54
|
-
}) });
|
|
55
|
-
const handlers = {
|
|
34
|
+
state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy(isArray, state, target, property, value) });
|
|
35
|
+
const instance = {
|
|
56
36
|
...rx,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
|
|
65
|
-
else if (typeof first === "function") unsubscribe(state, first);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
instance = {
|
|
69
|
-
...handlers,
|
|
70
|
-
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
|
|
71
|
-
notify() {
|
|
72
|
-
emityProxyValues(state, keyed);
|
|
73
|
-
},
|
|
74
|
-
set: (first, second) => {
|
|
75
|
-
setProxyValue(false, state, isStoreObject, isKey, setObject, setProperty, first, second);
|
|
76
|
-
},
|
|
77
|
-
update: (callback) => {
|
|
78
|
-
const updated = callback(state.value);
|
|
79
|
-
if (updated == null || isPlainObject(updated)) setObject(state, updated);
|
|
80
|
-
}
|
|
37
|
+
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
38
|
+
get: (value) => getValueInProxy(isArray, instance, state, keyed, value),
|
|
39
|
+
notify: () => emitProxyValues(state, keyed),
|
|
40
|
+
peek: (first, second) => peekValueInProxy(isArray, state, first, second),
|
|
41
|
+
set: (first, second) => setProxyValue(isArray, state, setStoreValue, setPropertyValue, first, second),
|
|
42
|
+
subscribe: (first, second, third) => subscribeToProxy(isArray, instance, state, keyed, first, second, third),
|
|
43
|
+
update: (callback) => updateProxyValue(isArray, state, setStoreValue, setPropertyValue, callback)
|
|
81
44
|
};
|
|
82
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
83
|
-
enumerable: false,
|
|
84
|
-
value: NAME_STORE
|
|
85
|
-
});
|
|
45
|
+
Object.defineProperty(instance, NAME_MORA, { value: NAME_STORE });
|
|
86
46
|
instance.set(value);
|
|
87
47
|
return Object.freeze(instance);
|
|
88
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -39,17 +39,17 @@
|
|
|
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.202"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/node": "^26.
|
|
46
|
-
"@vitest/coverage-istanbul": "4.1
|
|
45
|
+
"@types/node": "^26.5",
|
|
46
|
+
"@vitest/coverage-istanbul": "^4.1",
|
|
47
47
|
"jsdom": "^30",
|
|
48
|
-
"tsdown": "^0.
|
|
48
|
+
"tsdown": "^0.23",
|
|
49
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"
|
|
53
53
|
},
|
|
54
|
-
"packageManager": "npm@11.
|
|
54
|
+
"packageManager": "npm@11.19.0"
|
|
55
55
|
}
|
package/src/batch.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {BATCH} from './constants';
|
|
2
2
|
import {runEffect} from './effect';
|
|
3
|
-
import
|
|
3
|
+
import {getFrozenValue, peekSimpleValue} from './helpers/value';
|
|
4
|
+
import type {EffectState, StoredSubscription} from './models';
|
|
5
|
+
|
|
6
|
+
// #region Functions
|
|
4
7
|
|
|
5
8
|
export function flushHandlers(): void {
|
|
6
9
|
if (BATCH.flushing) {
|
|
@@ -17,10 +20,15 @@ export function flushHandlers(): void {
|
|
|
17
20
|
BATCH.handlers.clear();
|
|
18
21
|
|
|
19
22
|
for (let index = 0; index < length; index += 1) {
|
|
20
|
-
const handler = handlers[index];
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const [, handler] = handlers[index];
|
|
24
|
+
const subscription = handler as StoredSubscription;
|
|
25
|
+
|
|
26
|
+
if (typeof subscription.frozen === 'boolean') {
|
|
27
|
+
subscription.callback(
|
|
28
|
+
subscription.frozen
|
|
29
|
+
? getFrozenValue(subscription.state.value)
|
|
30
|
+
: peekSimpleValue(subscription.state.value, subscription.copy),
|
|
31
|
+
);
|
|
24
32
|
} else {
|
|
25
33
|
runEffect(handler as EffectState);
|
|
26
34
|
}
|
|
@@ -50,3 +58,5 @@ export function stopBatch(): void {
|
|
|
50
58
|
|
|
51
59
|
flushHandlers();
|
|
52
60
|
}
|
|
61
|
+
|
|
62
|
+
// #endregion
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {Active, Batch,
|
|
1
|
+
import type {Active, Batch, SubscriptionType} from './models';
|
|
2
|
+
|
|
3
|
+
// #region Variables
|
|
2
4
|
|
|
3
5
|
export const ACTIVE: Active = {};
|
|
4
6
|
|
|
@@ -11,7 +13,7 @@ export const ARRAY_PEEK = 10;
|
|
|
11
13
|
export const BATCH: Batch = {
|
|
12
14
|
depth: 0,
|
|
13
15
|
flushing: false,
|
|
14
|
-
handlers: new
|
|
16
|
+
handlers: new Map(),
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export const METHODS_AFFECTING_LENGTH = new Set<string>(['pop', 'push', 'shift', 'unshift']);
|
|
@@ -39,6 +41,8 @@ export const NAME_SIGNAL = 'signal';
|
|
|
39
41
|
|
|
40
42
|
export const NAME_STORE = 'store';
|
|
41
43
|
|
|
44
|
+
export const NAME_SUBSCRIPTION = 'subscription';
|
|
45
|
+
|
|
42
46
|
export const NAME_ALL = new Set([
|
|
43
47
|
NAME_ARRAY,
|
|
44
48
|
NAME_COMPUTED,
|
|
@@ -48,3 +52,29 @@ export const NAME_ALL = new Set([
|
|
|
48
52
|
]);
|
|
49
53
|
|
|
50
54
|
export const PROPERTY_LENGTH = 'length';
|
|
55
|
+
|
|
56
|
+
export const SUBSCRIPTION_PROPERTY = {
|
|
57
|
+
key: NAME_MORA,
|
|
58
|
+
value: NAME_SUBSCRIPTION,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const SUBSCRIPTION_TYPE_COPY: SubscriptionType = 'copy';
|
|
62
|
+
|
|
63
|
+
export const SUBSCRIPTION_TYPE_FROZEN: SubscriptionType = 'frozen';
|
|
64
|
+
|
|
65
|
+
export const SUBSCRIPTION_TYPE_ORIGINAL: SubscriptionType = 'original';
|
|
66
|
+
|
|
67
|
+
export const SUBSCRIPTION_TYPE_READONLY: SubscriptionType = 'readonly';
|
|
68
|
+
|
|
69
|
+
export const SUBSCRIPTION_TYPES_COPY = new Set<SubscriptionType>([
|
|
70
|
+
SUBSCRIPTION_TYPE_COPY,
|
|
71
|
+
SUBSCRIPTION_TYPE_READONLY,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
export const SUBSCRIPTION_TYPES: Set<SubscriptionType> = new Set([
|
|
75
|
+
...SUBSCRIPTION_TYPES_COPY,
|
|
76
|
+
SUBSCRIPTION_TYPE_FROZEN,
|
|
77
|
+
SUBSCRIPTION_TYPE_ORIGINAL,
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
// #endregion
|