@oscarpalmer/mora 0.27.0 → 0.28.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 +16 -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/index.d.mts +5 -2
- package/dist/models.d.mts +61 -1
- package/dist/mora.full.mjs +144 -63
- 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 +39 -1
- 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 +3 -3
- package/src/helpers/proxy.ts +64 -17
- package/src/models.ts +3 -1
- package/src/value/array.ts +74 -18
- package/src/value/computed.ts +65 -30
- package/src/value/signal.ts +77 -9
- package/src/value/store.ts +100 -11
- 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/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,40 @@
|
|
|
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
|
+
protected readonly state: ReactiveState<Value, Equal>;
|
|
6
|
+
constructor(name: string, value: Value, options?: ReactiveOptions<Equal>);
|
|
7
|
+
/**
|
|
8
|
+
* Get the value
|
|
9
|
+
* @return Current value
|
|
10
|
+
*/
|
|
11
|
+
abstract get(): Value;
|
|
12
|
+
/**
|
|
13
|
+
* Get the value _(without reactivity)_
|
|
14
|
+
* @return Current value
|
|
15
|
+
*/
|
|
16
|
+
peek(): Value;
|
|
17
|
+
/**
|
|
18
|
+
* Subscribe to changes
|
|
19
|
+
* @param callback Callback for changes
|
|
20
|
+
* @return Unsubscribe callback
|
|
21
|
+
*/
|
|
22
|
+
subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
23
|
+
/**
|
|
24
|
+
* JSON representation of the value
|
|
25
|
+
* @return JSON value
|
|
26
|
+
*/
|
|
27
|
+
toJSON(): Value;
|
|
28
|
+
/**
|
|
29
|
+
* String representation of the value
|
|
30
|
+
* @return Value as string
|
|
31
|
+
*/
|
|
32
|
+
toString(): string;
|
|
33
|
+
/**
|
|
34
|
+
* Unsubscribe from changes
|
|
35
|
+
* @param callback Callback to unsubscribe
|
|
36
|
+
*/
|
|
37
|
+
unsubscribe(callback: (value: Value) => void): void;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
2
40
|
export { Reactive };
|
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.28.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -39,12 +39,12 @@
|
|
|
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.172"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^25.5",
|
|
46
46
|
"@vitest/coverage-istanbul": "^4.1",
|
|
47
|
-
"jsdom": "^
|
|
47
|
+
"jsdom": "^29",
|
|
48
48
|
"tsdown": "^0.21",
|
|
49
49
|
"typescript": "^5.9",
|
|
50
50
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
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/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
|
};
|
package/src/value/array.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, PROPERTY_LENGTH} from '../constants';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
emityProxyValues,
|
|
5
|
+
getReactiveValueInProxy,
|
|
6
|
+
setProxyValue,
|
|
7
|
+
setValueInProxy,
|
|
8
|
+
} from '../helpers/proxy';
|
|
4
9
|
import {emitValue, equalArrays, getValue} from '../helpers/value';
|
|
5
10
|
import type {ReactiveOptions, ReactiveState, Unsubscribe} from '../models';
|
|
6
11
|
import {noop, subscribe} from '../subscription';
|
|
@@ -137,7 +142,7 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
137
142
|
return this.#size.peek();
|
|
138
143
|
}
|
|
139
144
|
|
|
140
|
-
return typeof value === 'number' ? this.state.value.at(value) :
|
|
145
|
+
return typeof value === 'number' ? this.state.value.at(value) : this.state.value.slice();
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
/**
|
|
@@ -161,14 +166,19 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
161
166
|
* Set the value
|
|
162
167
|
* @param value New array of items _(defaults to an empty array)_
|
|
163
168
|
*/
|
|
164
|
-
set(
|
|
169
|
+
set(
|
|
170
|
+
value?:
|
|
171
|
+
| Item[]
|
|
172
|
+
| (() => null | undefined | Item[] | Promise<null | undefined | Item[]>)
|
|
173
|
+
| Promise<null | undefined | Item[]>,
|
|
174
|
+
): void;
|
|
165
175
|
|
|
166
176
|
/**
|
|
167
177
|
* Set the value at an index
|
|
168
178
|
* @param index Index of item to set __(if negative, starts from the end)_
|
|
169
179
|
* @param value New item
|
|
170
180
|
*/
|
|
171
|
-
set(index: number, value: Item): void;
|
|
181
|
+
set(index: number, value: Item | (() => Item | Promise<Item>) | Promise<Item>): void;
|
|
172
182
|
|
|
173
183
|
/**
|
|
174
184
|
* Set the length of the array
|
|
@@ -176,14 +186,17 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
176
186
|
*/
|
|
177
187
|
set(property: typeof PROPERTY_LENGTH, value: number): void;
|
|
178
188
|
|
|
179
|
-
set(first?:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
set(first?: unknown, second?: unknown): void {
|
|
190
|
+
setProxyValue<Item[], Item>(
|
|
191
|
+
true,
|
|
192
|
+
this.state,
|
|
193
|
+
isArrayValue,
|
|
194
|
+
isArrayIndex,
|
|
195
|
+
setArray,
|
|
196
|
+
setAtIndex,
|
|
197
|
+
first,
|
|
198
|
+
second,
|
|
199
|
+
);
|
|
187
200
|
}
|
|
188
201
|
|
|
189
202
|
/**
|
|
@@ -248,14 +261,53 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
|
248
261
|
}
|
|
249
262
|
}
|
|
250
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Create a reactive array from a function result
|
|
266
|
+
* @param value Initial array of items
|
|
267
|
+
* @param options Reactivity options
|
|
268
|
+
* @returns Reactive array
|
|
269
|
+
*/
|
|
270
|
+
export function array<Item>(
|
|
271
|
+
value: () => Item[] | Promise<Item[]>,
|
|
272
|
+
options?: ReactiveOptions<Item>,
|
|
273
|
+
): ReactiveArray<Item>;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Create a reactive array from a promise
|
|
277
|
+
* @param value Initial array of items
|
|
278
|
+
* @param options Reactivity options
|
|
279
|
+
* @returns Reactive array
|
|
280
|
+
*/
|
|
281
|
+
export function array<Item>(
|
|
282
|
+
value: Promise<Item[]>,
|
|
283
|
+
options?: ReactiveOptions<Item>,
|
|
284
|
+
): ReactiveArray<Item>;
|
|
285
|
+
|
|
251
286
|
/**
|
|
252
287
|
* Create a reactive array
|
|
253
288
|
* @param value Initial array of items
|
|
254
289
|
* @param options Reactivity options
|
|
255
290
|
* @returns Reactive array
|
|
256
291
|
*/
|
|
257
|
-
export function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item
|
|
258
|
-
|
|
292
|
+
export function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
|
|
293
|
+
|
|
294
|
+
export function array<Item>(
|
|
295
|
+
value: Item[] | (() => Item[] | Promise<Item[]>) | Promise<Item[]>,
|
|
296
|
+
options?: ReactiveOptions<Item>,
|
|
297
|
+
): ReactiveArray<Item> {
|
|
298
|
+
const instance = new ReactiveArray([], options);
|
|
299
|
+
|
|
300
|
+
instance.set(value);
|
|
301
|
+
|
|
302
|
+
return instance;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isArrayIndex(value: unknown): boolean {
|
|
306
|
+
return typeof value === 'number';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function isArrayValue<Item>(value: unknown): value is Item[] | undefined {
|
|
310
|
+
return value == null || Array.isArray(value);
|
|
259
311
|
}
|
|
260
312
|
|
|
261
313
|
function updateArray<Item>(
|
|
@@ -265,7 +317,7 @@ function updateArray<Item>(
|
|
|
265
317
|
length: Signal<number>,
|
|
266
318
|
): unknown {
|
|
267
319
|
const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
|
|
268
|
-
const previousArray = affectsLength ? [] :
|
|
320
|
+
const previousArray = affectsLength ? [] : array.slice();
|
|
269
321
|
const previousLength = array.length;
|
|
270
322
|
|
|
271
323
|
return (...args: unknown[]): unknown => {
|
|
@@ -283,10 +335,14 @@ function updateArray<Item>(
|
|
|
283
335
|
};
|
|
284
336
|
}
|
|
285
337
|
|
|
286
|
-
function
|
|
287
|
-
|
|
338
|
+
function setArray<Item>(state: ReactiveState<Item[], Item>, value: Item[] | undefined): void {
|
|
339
|
+
state.value.splice(0, state.value.length, ...(value ?? []));
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function setAtIndex<Item>(state: ReactiveState<Item[], Item>, index: unknown, value: Item): void {
|
|
343
|
+
const actual = (index as number) < 0 ? state.value.length + (index as number) : (index as number);
|
|
288
344
|
|
|
289
345
|
if (actual > -1) {
|
|
290
|
-
|
|
346
|
+
state.value[actual] = value;
|
|
291
347
|
}
|
|
292
348
|
}
|