@montra-interactive/deepstate 0.2.3 → 0.3.1
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/README.md +2 -3
- package/dist/deepstate.d.ts +23 -26
- package/dist/deepstate.d.ts.map +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.js +10 -32
- package/package.json +2 -2
- package/src/deepstate.ts +33 -73
- package/src/helpers.ts +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Proxy-based reactive state management powered by RxJS. Each property is its own
|
|
|
9
9
|
- **Type-safe**: Full TypeScript support with inferred types
|
|
10
10
|
- **RxJS native**: Every node is an Observable - use `pipe()`, `combineLatest`, etc.
|
|
11
11
|
- **Batched updates**: Group multiple changes into a single emission
|
|
12
|
-
- **
|
|
12
|
+
- **Mutable snapshots**: Reads return plain values; use `.set()` to update state
|
|
13
13
|
- **Nullable objects**: First-class support for `T | null` properties with deep subscription
|
|
14
14
|
- **Debug mode**: Optional logging for development
|
|
15
15
|
|
|
@@ -301,14 +301,13 @@ store.selectedId.get(); // string | null
|
|
|
301
301
|
### Type Exports
|
|
302
302
|
|
|
303
303
|
```ts
|
|
304
|
-
import type { RxState, Draft
|
|
304
|
+
import type { RxState, Draft } from "@montra-interactive/deepstate";
|
|
305
305
|
```
|
|
306
306
|
|
|
307
307
|
| Type | Description |
|
|
308
308
|
|------|-------------|
|
|
309
309
|
| `RxState<T>` | The reactive state type returned by `state()` |
|
|
310
310
|
| `Draft<T>` | Type alias for values in update callbacks |
|
|
311
|
-
| `DeepReadonly<T>` | Deep readonly type for returned values |
|
|
312
311
|
|
|
313
312
|
## Architecture
|
|
314
313
|
|
package/dist/deepstate.d.ts
CHANGED
|
@@ -21,12 +21,9 @@ type IsNullish<T> = HasNull<T> extends true ? true : HasUndefined<T>;
|
|
|
21
21
|
type NonNullPartIsObject<T> = NonNullablePart<T> extends object ? NonNullablePart<T> extends Array<unknown> ? false : true : false;
|
|
22
22
|
type IsNullableObject<T> = IsNullish<T> extends true ? NonNullPartIsObject<T> : false;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
* Used for return types of get() and subscribe() to prevent accidental mutations.
|
|
24
|
+
* Type alias for values returned by get() and subscribe().
|
|
26
25
|
*/
|
|
27
|
-
export type DeepReadonly<T> =
|
|
28
|
-
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
29
|
-
} : T;
|
|
26
|
+
export type DeepReadonly<T> = T;
|
|
30
27
|
/**
|
|
31
28
|
* A mutable draft of state T for use in update callbacks.
|
|
32
29
|
*/
|
|
@@ -38,20 +35,20 @@ interface NodeCore<T> {
|
|
|
38
35
|
subscribeOnce?(callback: (value: T) => void): Subscription;
|
|
39
36
|
}
|
|
40
37
|
declare const NODE: unique symbol;
|
|
41
|
-
type RxLeaf<T> = Observable<
|
|
38
|
+
type RxLeaf<T> = Observable<T> & {
|
|
42
39
|
/** Get current value synchronously */
|
|
43
|
-
get():
|
|
40
|
+
get(): T;
|
|
44
41
|
/** Set value */
|
|
45
42
|
set(value: T): void;
|
|
46
43
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
47
|
-
subscribeOnce(callback: (value:
|
|
44
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
48
45
|
[NODE]: NodeCore<T>;
|
|
49
46
|
};
|
|
50
47
|
type RxObject<T extends object> = {
|
|
51
48
|
[K in keyof T]: RxNodeFor<T[K]>;
|
|
52
|
-
} & Observable<
|
|
49
|
+
} & Observable<T> & {
|
|
53
50
|
/** Get current value synchronously */
|
|
54
|
-
get():
|
|
51
|
+
get(): T;
|
|
55
52
|
/** Set value */
|
|
56
53
|
set(value: T): void;
|
|
57
54
|
/**
|
|
@@ -64,14 +61,14 @@ type RxObject<T extends object> = {
|
|
|
64
61
|
* draft.age.set(31);
|
|
65
62
|
* });
|
|
66
63
|
*/
|
|
67
|
-
update(callback: (draft: RxObject<T>) => void):
|
|
64
|
+
update(callback: (draft: RxObject<T>) => void): T;
|
|
68
65
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
69
|
-
subscribeOnce(callback: (value:
|
|
66
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
70
67
|
[NODE]: NodeCore<T>;
|
|
71
68
|
};
|
|
72
|
-
type RxArray<T> = Observable<
|
|
69
|
+
type RxArray<T> = Observable<T[]> & {
|
|
73
70
|
/** Get current value synchronously */
|
|
74
|
-
get():
|
|
71
|
+
get(): T[];
|
|
75
72
|
/** Set value */
|
|
76
73
|
set(value: T[]): void;
|
|
77
74
|
/**
|
|
@@ -84,9 +81,9 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
84
81
|
* draft.push({ id: 2, name: "New" });
|
|
85
82
|
* });
|
|
86
83
|
*/
|
|
87
|
-
update(callback: (draft: RxArray<T>) => void):
|
|
84
|
+
update(callback: (draft: RxArray<T>) => void): T[];
|
|
88
85
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
89
|
-
subscribeOnce(callback: (value:
|
|
86
|
+
subscribeOnce(callback: (value: T[]) => void): Subscription;
|
|
90
87
|
/** Get reactive node for array element at index */
|
|
91
88
|
at(index: number): RxNodeFor<T> | undefined;
|
|
92
89
|
/** Get current length (also observable) */
|
|
@@ -96,11 +93,11 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
96
93
|
/** Push items and return new length */
|
|
97
94
|
push(...items: T[]): number;
|
|
98
95
|
/** Pop last item */
|
|
99
|
-
pop():
|
|
96
|
+
pop(): T | undefined;
|
|
100
97
|
/** Map over current values (non-reactive, use .subscribe for reactive) */
|
|
101
|
-
map<U>(fn: (item:
|
|
98
|
+
map<U>(fn: (item: T, index: number) => U): U[];
|
|
102
99
|
/** Filter current values */
|
|
103
|
-
filter(fn: (item:
|
|
100
|
+
filter(fn: (item: T, index: number) => boolean): T[];
|
|
104
101
|
[NODE]: NodeCore<T[]>;
|
|
105
102
|
};
|
|
106
103
|
/**
|
|
@@ -124,13 +121,13 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
124
121
|
* store.user.name.get(); // "Alice"
|
|
125
122
|
* store.user.name.set("Bob"); // Works!
|
|
126
123
|
*/
|
|
127
|
-
type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<
|
|
124
|
+
type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<T> & {
|
|
128
125
|
/** Get current value (may be null/undefined) */
|
|
129
|
-
get():
|
|
126
|
+
get(): T;
|
|
130
127
|
/** Set value (can be null/undefined or the full object) */
|
|
131
128
|
set(value: T): void;
|
|
132
129
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
133
|
-
subscribeOnce(callback: (value:
|
|
130
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
134
131
|
/**
|
|
135
132
|
* Update multiple properties in a single emission.
|
|
136
133
|
* @example
|
|
@@ -139,7 +136,7 @@ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Obse
|
|
|
139
136
|
* user.age.set(31);
|
|
140
137
|
* });
|
|
141
138
|
*/
|
|
142
|
-
update(callback: (draft: RxObject<TNonNull>) => void):
|
|
139
|
+
update(callback: (draft: RxObject<TNonNull>) => void): T;
|
|
143
140
|
[NODE]: NodeCore<T>;
|
|
144
141
|
} & {
|
|
145
142
|
[K in keyof TNonNull]: RxNullableChild<TNonNull[K]>;
|
|
@@ -156,10 +153,10 @@ type RxNullableChild<T> = IsNullableObject<T> extends true ? RxNullable<T> : [T]
|
|
|
156
153
|
* The object itself might be undefined (if parent is null), but if present
|
|
157
154
|
* it has all the normal object methods and children.
|
|
158
155
|
*/
|
|
159
|
-
type RxNullableChildObject<T extends object> = Observable<
|
|
160
|
-
get():
|
|
156
|
+
type RxNullableChildObject<T extends object> = Observable<T | undefined> & {
|
|
157
|
+
get(): T | undefined;
|
|
161
158
|
set(value: T): void;
|
|
162
|
-
subscribeOnce(callback: (value:
|
|
159
|
+
subscribeOnce(callback: (value: T | undefined) => void): Subscription;
|
|
163
160
|
[NODE]: NodeCore<T | undefined>;
|
|
164
161
|
} & {
|
|
165
162
|
[K in keyof T]: RxNullableChild<T[K]>;
|
package/dist/deepstate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmB,UAAU,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAapF,eAAO,IAAI,iBAAiB,QAAI,CAAC;AACjC,wBAAgB,sBAAsB,SAErC;
|
|
1
|
+
{"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmB,UAAU,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAapF,eAAO,IAAI,iBAAiB,QAAI,CAAC;AACjC,wBAAgB,sBAAsB,SAErC;AAoDD,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAGhF,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AAGjE,KAAK,OAAO,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;AAChD,KAAK,YAAY,CAAC,CAAC,IAAI,SAAS,SAAS,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;AAC1D,KAAK,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;AAGrE,KAAK,mBAAmB,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,SAAS,MAAM,GAC3D,eAAe,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,CAAC,GACvC,KAAK,GACL,IAAI,GACN,KAAK,CAAC;AAGV,KAAK,gBAAgB,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAChD,mBAAmB,CAAC,CAAC,CAAC,GACtB,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AAEhC;;GAEG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;AAGzB,UAAU,QAAQ,CAAC,CAAC;IAClB,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1B,GAAG,IAAI,CAAC,CAAC;IACT,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,YAAY,CAAC;CAC5D;AAGD,QAAA,MAAM,IAAI,eAAiB,CAAC;AAG5B,KAAK,MAAM,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IAC/B,sCAAsC;IACtC,GAAG,IAAI,CAAC,CAAC;IACT,gBAAgB;IAChB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,qEAAqE;IACrE,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,YAAY,CAAC;IAC1D,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AAEF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI;KAC/B,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAChC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG;IAClB,sCAAsC;IACtC,GAAG,IAAI,CAAC,CAAC;IACT,gBAAgB;IAChB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;IAClD,qEAAqE;IACrE,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,YAAY,CAAC;IAC1D,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AAEF,KAAK,OAAO,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG;IAClC,sCAAsC;IACtC,GAAG,IAAI,CAAC,EAAE,CAAC;IACX,gBAAgB;IAChB,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,CAAC;IACnD,qEAAqE;IACrE,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,GAAG,YAAY,CAAC;IAC5D,mDAAmD;IACnD,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC5C,2CAA2C;IAC3C,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG;QAAE,GAAG,IAAI,MAAM,CAAA;KAAE,CAAC;IAC/C,uCAAuC;IACvC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC;IAC5B,oBAAoB;IACpB,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACrB,0EAA0E;IAC1E,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/C,4BAA4B;IAC5B,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,CAAC,EAAE,CAAC;IACrD,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,CAAC,CAAC,EAAE,QAAQ,SAAS,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IAC1F,gDAAgD;IAChD,GAAG,IAAI,CAAC,CAAC;IACT,2DAA2D;IAC3D,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,qEAAqE;IACrE,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,YAAY,CAAC;IAC1D;;;;;;;OAOG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;IACzD,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CACrB,GAAG;KAMD,CAAC,IAAI,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;CACpD,CAAC;AAEF;;;;;GAKG;AACH,KAAK,eAAe,CAAC,CAAC,IAEpB,gBAAgB,CAAC,CAAC,CAAC,SAAS,IAAI,GAC5B,UAAU,CAAC,CAAC,CAAC,GAEf,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GACrB,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,GAEvB,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,GAEhC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAClB,qBAAqB,CAAC,CAAC,CAAC,GAE1B,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAE1B;;;;GAIG;AACH,KAAK,qBAAqB,CAAC,CAAC,SAAS,MAAM,IAAI,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG;IACzE,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACrB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,GAAG,YAAY,CAAC;IACtE,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;CACjC,GAAG;KACD,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,IAEd,gBAAgB,CAAC,CAAC,CAAC,SAAS,IAAI,GAC5B,UAAU,CAAC,CAAC,CAAC,GAEf,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GACrB,MAAM,CAAC,CAAC,CAAC,GAEX,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,GAEZ,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAClB,QAAQ,CAAC,CAAC,CAAC,GAEb,MAAM,CAAC,CAAC,CAAC,CAAC;AAEd,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAwjCpD,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAQ3F;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAMpE;AAUD,kDAAkD;AAClD,MAAM,MAAM,aAAa,CAAC,CAAC,IACvB,KAAK,GACL,SAAS,GACT,MAAM,GACN,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;AAElC,qCAAqC;AACrC,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,GAAE,YAAY,CAAC,CAAC,CAAM,GAAG,CAAC,EAAE,CAIvE"}
|
package/dist/helpers.d.ts
CHANGED
|
@@ -56,6 +56,6 @@ export declare function select<T extends Record<string, Observable<unknown>>>(ob
|
|
|
56
56
|
* @param selector - A function that extracts/derives a value from each item
|
|
57
57
|
* @returns An Observable that emits an array of selected values
|
|
58
58
|
*/
|
|
59
|
-
export declare function selectFromEach<T, U>(arrayNode: Observable<
|
|
59
|
+
export declare function selectFromEach<T, U>(arrayNode: Observable<T[]>, selector: (item: T, index: number) => U): Observable<U[]>;
|
|
60
60
|
export {};
|
|
61
61
|
//# sourceMappingURL=helpers.d.ts.map
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,MAAM,CAAC;AA+CjD,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGpE,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KACtD,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAGF,KAAK,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI;KAC1E,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,EACpD,GAAG,WAAW,EAAE,CAAC,GAChB,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAClE,WAAW,EAAE,CAAC,GACb,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AAyBzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,MAAM,CAAC;AA+CjD,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGpE,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KACtD,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAGF,KAAK,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI;KAC1E,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,EACpD,GAAG,WAAW,EAAE,CAAC,GAChB,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAClE,WAAW,EAAE,CAAC,GACb,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AAyBzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,EAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GACtC,UAAU,CAAC,CAAC,EAAE,CAAC,CAOjB"}
|
package/dist/index.js
CHANGED
|
@@ -91,27 +91,6 @@ function countedDistinctUntilChanged(compareFn) {
|
|
|
91
91
|
return a === b;
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
|
-
function deepFreezeImpl(obj, seen) {
|
|
95
|
-
if (obj === null || typeof obj !== "object")
|
|
96
|
-
return obj;
|
|
97
|
-
if (Object.isFrozen(obj))
|
|
98
|
-
return obj;
|
|
99
|
-
if (seen.has(obj))
|
|
100
|
-
return obj;
|
|
101
|
-
seen.add(obj);
|
|
102
|
-
Object.freeze(obj);
|
|
103
|
-
if (Array.isArray(obj)) {
|
|
104
|
-
obj.forEach((item) => deepFreezeImpl(item, seen));
|
|
105
|
-
} else {
|
|
106
|
-
Object.keys(obj).forEach((key) => {
|
|
107
|
-
deepFreezeImpl(obj[key], seen);
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
return obj;
|
|
111
|
-
}
|
|
112
|
-
function deepFreeze(obj) {
|
|
113
|
-
return deepFreezeImpl(obj, new WeakSet);
|
|
114
|
-
}
|
|
115
94
|
var NODE = Symbol("node");
|
|
116
95
|
function createLeafNode(value) {
|
|
117
96
|
const subject$ = new BehaviorSubject(value);
|
|
@@ -160,11 +139,10 @@ function createObjectNode(value) {
|
|
|
160
139
|
return result;
|
|
161
140
|
}), shareReplay(1));
|
|
162
141
|
$.subscribe();
|
|
163
|
-
const frozen$ = $.pipe(map2(deepFreeze));
|
|
164
142
|
return {
|
|
165
|
-
|
|
143
|
+
$,
|
|
166
144
|
children,
|
|
167
|
-
get: () =>
|
|
145
|
+
get: () => getCurrentValue(),
|
|
168
146
|
set: (v) => {
|
|
169
147
|
for (const [key, child] of children) {
|
|
170
148
|
child.set(v[key]);
|
|
@@ -173,7 +151,7 @@ function createObjectNode(value) {
|
|
|
173
151
|
lock: () => lock$.next(false),
|
|
174
152
|
unlock: () => lock$.next(true),
|
|
175
153
|
subscribeOnce: (callback) => {
|
|
176
|
-
return
|
|
154
|
+
return $.pipe(take(1)).subscribe(callback);
|
|
177
155
|
}
|
|
178
156
|
};
|
|
179
157
|
}
|
|
@@ -202,7 +180,7 @@ function createArrayNode(value, comparator) {
|
|
|
202
180
|
};
|
|
203
181
|
const lock$ = new BehaviorSubject(true);
|
|
204
182
|
const baseLocked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr));
|
|
205
|
-
const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2(
|
|
183
|
+
const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2((arr) => [...arr]), shareReplay(1));
|
|
206
184
|
locked$.subscribe();
|
|
207
185
|
const length$ = locked$.pipe(map2((arr) => arr.length), distinctUntilChanged2(), shareReplay(1));
|
|
208
186
|
length$.subscribe();
|
|
@@ -212,7 +190,7 @@ function createArrayNode(value, comparator) {
|
|
|
212
190
|
return {
|
|
213
191
|
$: locked$,
|
|
214
192
|
childCache,
|
|
215
|
-
get: () =>
|
|
193
|
+
get: () => [...subject$.getValue()],
|
|
216
194
|
set: (v) => {
|
|
217
195
|
if (hasCircularReference(v)) {
|
|
218
196
|
throw new Error("Circular reference detected in array value. " + "Deepstate does not support circular references. " + "Please flatten your data structure or remove the circular reference.");
|
|
@@ -246,13 +224,13 @@ function createArrayNode(value, comparator) {
|
|
|
246
224
|
const last = current[current.length - 1];
|
|
247
225
|
childCache.delete(current.length - 1);
|
|
248
226
|
subject$.next(current.slice(0, -1));
|
|
249
|
-
return
|
|
227
|
+
return last;
|
|
250
228
|
},
|
|
251
229
|
mapItems: (fn) => {
|
|
252
|
-
return subject$.getValue().map((item, i) => fn(
|
|
230
|
+
return subject$.getValue().map((item, i) => fn(item, i));
|
|
253
231
|
},
|
|
254
232
|
filterItems: (fn) => {
|
|
255
|
-
return
|
|
233
|
+
return subject$.getValue().filter((item, i) => fn(item, i));
|
|
256
234
|
},
|
|
257
235
|
lock: () => lock$.next(false),
|
|
258
236
|
unlock: () => lock$.next(true)
|
|
@@ -300,7 +278,7 @@ function createNullableObjectNode(initialValue) {
|
|
|
300
278
|
if (b === null || b === undefined)
|
|
301
279
|
return false;
|
|
302
280
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
303
|
-
}),
|
|
281
|
+
}), shareReplay(1));
|
|
304
282
|
$.subscribe();
|
|
305
283
|
const nodeState = { children };
|
|
306
284
|
const updateChildrenRef = () => {
|
|
@@ -329,7 +307,7 @@ function createNullableObjectNode(initialValue) {
|
|
|
329
307
|
get children() {
|
|
330
308
|
return nodeState.children;
|
|
331
309
|
},
|
|
332
|
-
get: () =>
|
|
310
|
+
get: () => getCurrentValue(),
|
|
333
311
|
set: (value) => {
|
|
334
312
|
if (value === null || value === undefined) {
|
|
335
313
|
subject$.next(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@montra-interactive/deepstate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Proxy-based reactive state management with RxJS. Deep nested state observation with full TypeScript support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"homepage": "https://github.com/Montra-Interactive/deepstate/tree/main/packages/core",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/Montra-Interactive/deepstate",
|
|
22
|
+
"url": "git+https://github.com/Montra-Interactive/deepstate.git",
|
|
23
23
|
"directory": "packages/core"
|
|
24
24
|
},
|
|
25
25
|
"module": "dist/index.js",
|
package/src/deepstate.ts
CHANGED
|
@@ -75,35 +75,6 @@ function countedDistinctUntilChanged<T>(compareFn?: (a: T, b: T) => boolean) {
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
// =============================================================================
|
|
79
|
-
// Deep Freeze
|
|
80
|
-
// =============================================================================
|
|
81
|
-
|
|
82
|
-
function deepFreezeImpl<T>(obj: T, seen: WeakSet<object>): T {
|
|
83
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
84
|
-
if (Object.isFrozen(obj)) return obj;
|
|
85
|
-
|
|
86
|
-
// Circular reference protection
|
|
87
|
-
if (seen.has(obj as object)) return obj;
|
|
88
|
-
seen.add(obj as object);
|
|
89
|
-
|
|
90
|
-
Object.freeze(obj);
|
|
91
|
-
|
|
92
|
-
if (Array.isArray(obj)) {
|
|
93
|
-
obj.forEach((item) => deepFreezeImpl(item, seen));
|
|
94
|
-
} else {
|
|
95
|
-
Object.keys(obj).forEach((key) => {
|
|
96
|
-
deepFreezeImpl((obj as Record<string, unknown>)[key], seen);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return obj;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function deepFreeze<T>(obj: T): T {
|
|
104
|
-
return deepFreezeImpl(obj, new WeakSet<object>());
|
|
105
|
-
}
|
|
106
|
-
|
|
107
78
|
// =============================================================================
|
|
108
79
|
// Types
|
|
109
80
|
// =============================================================================
|
|
@@ -131,16 +102,9 @@ type IsNullableObject<T> = IsNullish<T> extends true
|
|
|
131
102
|
: false;
|
|
132
103
|
|
|
133
104
|
/**
|
|
134
|
-
*
|
|
135
|
-
* Used for return types of get() and subscribe() to prevent accidental mutations.
|
|
105
|
+
* Type alias for values returned by get() and subscribe().
|
|
136
106
|
*/
|
|
137
|
-
export type DeepReadonly<T> =
|
|
138
|
-
? T
|
|
139
|
-
: [T] extends [Array<infer U>]
|
|
140
|
-
? ReadonlyArray<DeepReadonly<U>>
|
|
141
|
-
: [T] extends [object]
|
|
142
|
-
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
|
143
|
-
: T;
|
|
107
|
+
export type DeepReadonly<T> = T;
|
|
144
108
|
|
|
145
109
|
/**
|
|
146
110
|
* A mutable draft of state T for use in update callbacks.
|
|
@@ -159,21 +123,21 @@ interface NodeCore<T> {
|
|
|
159
123
|
const NODE = Symbol("node");
|
|
160
124
|
|
|
161
125
|
// External API types
|
|
162
|
-
type RxLeaf<T> = Observable<
|
|
126
|
+
type RxLeaf<T> = Observable<T> & {
|
|
163
127
|
/** Get current value synchronously */
|
|
164
|
-
get():
|
|
128
|
+
get(): T;
|
|
165
129
|
/** Set value */
|
|
166
130
|
set(value: T): void;
|
|
167
131
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
168
|
-
subscribeOnce(callback: (value:
|
|
132
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
169
133
|
[NODE]: NodeCore<T>;
|
|
170
134
|
};
|
|
171
135
|
|
|
172
136
|
type RxObject<T extends object> = {
|
|
173
137
|
[K in keyof T]: RxNodeFor<T[K]>;
|
|
174
|
-
} & Observable<
|
|
138
|
+
} & Observable<T> & {
|
|
175
139
|
/** Get current value synchronously */
|
|
176
|
-
get():
|
|
140
|
+
get(): T;
|
|
177
141
|
/** Set value */
|
|
178
142
|
set(value: T): void;
|
|
179
143
|
/**
|
|
@@ -186,15 +150,15 @@ type RxObject<T extends object> = {
|
|
|
186
150
|
* draft.age.set(31);
|
|
187
151
|
* });
|
|
188
152
|
*/
|
|
189
|
-
update(callback: (draft: RxObject<T>) => void):
|
|
153
|
+
update(callback: (draft: RxObject<T>) => void): T;
|
|
190
154
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
191
|
-
subscribeOnce(callback: (value:
|
|
155
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
192
156
|
[NODE]: NodeCore<T>;
|
|
193
157
|
};
|
|
194
158
|
|
|
195
|
-
type RxArray<T> = Observable<
|
|
159
|
+
type RxArray<T> = Observable<T[]> & {
|
|
196
160
|
/** Get current value synchronously */
|
|
197
|
-
get():
|
|
161
|
+
get(): T[];
|
|
198
162
|
/** Set value */
|
|
199
163
|
set(value: T[]): void;
|
|
200
164
|
/**
|
|
@@ -207,9 +171,9 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
207
171
|
* draft.push({ id: 2, name: "New" });
|
|
208
172
|
* });
|
|
209
173
|
*/
|
|
210
|
-
update(callback: (draft: RxArray<T>) => void):
|
|
174
|
+
update(callback: (draft: RxArray<T>) => void): T[];
|
|
211
175
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
212
|
-
subscribeOnce(callback: (value:
|
|
176
|
+
subscribeOnce(callback: (value: T[]) => void): Subscription;
|
|
213
177
|
/** Get reactive node for array element at index */
|
|
214
178
|
at(index: number): RxNodeFor<T> | undefined;
|
|
215
179
|
/** Get current length (also observable) */
|
|
@@ -217,11 +181,11 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
217
181
|
/** Push items and return new length */
|
|
218
182
|
push(...items: T[]): number;
|
|
219
183
|
/** Pop last item */
|
|
220
|
-
pop():
|
|
184
|
+
pop(): T | undefined;
|
|
221
185
|
/** Map over current values (non-reactive, use .subscribe for reactive) */
|
|
222
|
-
map<U>(fn: (item:
|
|
186
|
+
map<U>(fn: (item: T, index: number) => U): U[];
|
|
223
187
|
/** Filter current values */
|
|
224
|
-
filter(fn: (item:
|
|
188
|
+
filter(fn: (item: T, index: number) => boolean): T[];
|
|
225
189
|
[NODE]: NodeCore<T[]>;
|
|
226
190
|
};
|
|
227
191
|
|
|
@@ -246,13 +210,13 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
|
|
|
246
210
|
* store.user.name.get(); // "Alice"
|
|
247
211
|
* store.user.name.set("Bob"); // Works!
|
|
248
212
|
*/
|
|
249
|
-
type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<
|
|
213
|
+
type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<T> & {
|
|
250
214
|
/** Get current value (may be null/undefined) */
|
|
251
|
-
get():
|
|
215
|
+
get(): T;
|
|
252
216
|
/** Set value (can be null/undefined or the full object) */
|
|
253
217
|
set(value: T): void;
|
|
254
218
|
/** Subscribe to a single emission, then automatically unsubscribe */
|
|
255
|
-
subscribeOnce(callback: (value:
|
|
219
|
+
subscribeOnce(callback: (value: T) => void): Subscription;
|
|
256
220
|
/**
|
|
257
221
|
* Update multiple properties in a single emission.
|
|
258
222
|
* @example
|
|
@@ -261,7 +225,7 @@ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Obse
|
|
|
261
225
|
* user.age.set(31);
|
|
262
226
|
* });
|
|
263
227
|
*/
|
|
264
|
-
update(callback: (draft: RxObject<TNonNull>) => void):
|
|
228
|
+
update(callback: (draft: RxObject<TNonNull>) => void): T;
|
|
265
229
|
[NODE]: NodeCore<T>;
|
|
266
230
|
} & {
|
|
267
231
|
/**
|
|
@@ -299,10 +263,10 @@ type RxNullableChild<T> =
|
|
|
299
263
|
* The object itself might be undefined (if parent is null), but if present
|
|
300
264
|
* it has all the normal object methods and children.
|
|
301
265
|
*/
|
|
302
|
-
type RxNullableChildObject<T extends object> = Observable<
|
|
303
|
-
get():
|
|
266
|
+
type RxNullableChildObject<T extends object> = Observable<T | undefined> & {
|
|
267
|
+
get(): T | undefined;
|
|
304
268
|
set(value: T): void;
|
|
305
|
-
subscribeOnce(callback: (value:
|
|
269
|
+
subscribeOnce(callback: (value: T | undefined) => void): Subscription;
|
|
306
270
|
[NODE]: NodeCore<T | undefined>;
|
|
307
271
|
} & {
|
|
308
272
|
[K in keyof T]: RxNullableChild<T[K]>;
|
|
@@ -411,13 +375,10 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
|
|
|
411
375
|
// Force subscription to make it hot (so emissions work even before external subscribers)
|
|
412
376
|
$.subscribe();
|
|
413
377
|
|
|
414
|
-
// Create a version that freezes on emission
|
|
415
|
-
const frozen$ = $.pipe(map(deepFreeze));
|
|
416
|
-
|
|
417
378
|
return {
|
|
418
|
-
|
|
379
|
+
$,
|
|
419
380
|
children: children as Map<string, NodeCore<unknown>>,
|
|
420
|
-
get: () =>
|
|
381
|
+
get: () => getCurrentValue(),
|
|
421
382
|
set: (v: T) => {
|
|
422
383
|
for (const [key, child] of children) {
|
|
423
384
|
child.set(v[key]);
|
|
@@ -427,7 +388,7 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
|
|
|
427
388
|
unlock: () => lock$.next(true),
|
|
428
389
|
// Note: update() is implemented in wrapWithProxy since it needs the proxy reference
|
|
429
390
|
subscribeOnce: (callback: (value: T) => void): Subscription => {
|
|
430
|
-
return
|
|
391
|
+
return $.pipe(take(1)).subscribe(callback);
|
|
431
392
|
},
|
|
432
393
|
};
|
|
433
394
|
}
|
|
@@ -496,11 +457,11 @@ function createArrayNode<T>(
|
|
|
496
457
|
);
|
|
497
458
|
|
|
498
459
|
// Apply distinct comparison if provided
|
|
499
|
-
const locked$ = (comparator
|
|
460
|
+
const locked$ = (comparator
|
|
500
461
|
? baseLocked$.pipe(distinctUntilChanged(comparator))
|
|
501
462
|
: baseLocked$
|
|
502
463
|
).pipe(
|
|
503
|
-
map(
|
|
464
|
+
map((arr) => [...arr]),
|
|
504
465
|
shareReplay(1)
|
|
505
466
|
);
|
|
506
467
|
locked$.subscribe(); // Keep hot
|
|
@@ -520,7 +481,7 @@ function createArrayNode<T>(
|
|
|
520
481
|
return {
|
|
521
482
|
$: locked$ as Observable<T[]>,
|
|
522
483
|
childCache,
|
|
523
|
-
get: () =>
|
|
484
|
+
get: () => [...subject$.getValue()] as T[],
|
|
524
485
|
set: (v: T[]) => {
|
|
525
486
|
// Check for circular references in array items
|
|
526
487
|
if (hasCircularReference(v)) {
|
|
@@ -560,13 +521,13 @@ function createArrayNode<T>(
|
|
|
560
521
|
// Clear cached node for popped index
|
|
561
522
|
childCache.delete(current.length - 1);
|
|
562
523
|
subject$.next(current.slice(0, -1));
|
|
563
|
-
return
|
|
524
|
+
return last as T;
|
|
564
525
|
},
|
|
565
526
|
mapItems: <U>(fn: (item: T, index: number) => U): U[] => {
|
|
566
|
-
return subject$.getValue().map((item, i) => fn(
|
|
527
|
+
return subject$.getValue().map((item, i) => fn(item as T, i));
|
|
567
528
|
},
|
|
568
529
|
filterItems: (fn: (item: T, index: number) => boolean): T[] => {
|
|
569
|
-
return
|
|
530
|
+
return subject$.getValue().filter((item, i) => fn(item as T, i)) as T[];
|
|
570
531
|
},
|
|
571
532
|
lock: () => lock$.next(false),
|
|
572
533
|
unlock: () => lock$.next(true),
|
|
@@ -668,7 +629,6 @@ function createNullableObjectNode<T>(
|
|
|
668
629
|
if (b === null || b === undefined) return false;
|
|
669
630
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
670
631
|
}),
|
|
671
|
-
map(deepFreeze),
|
|
672
632
|
shareReplay(1)
|
|
673
633
|
);
|
|
674
634
|
$.subscribe(); // Keep hot
|
|
@@ -711,7 +671,7 @@ function createNullableObjectNode<T>(
|
|
|
711
671
|
$,
|
|
712
672
|
get children() { return nodeState.children; },
|
|
713
673
|
|
|
714
|
-
get: () =>
|
|
674
|
+
get: () => getCurrentValue(),
|
|
715
675
|
|
|
716
676
|
set: (value: T) => {
|
|
717
677
|
if (value === null || value === undefined) {
|
package/src/helpers.ts
CHANGED
|
@@ -137,7 +137,7 @@ export function select(
|
|
|
137
137
|
* @returns An Observable that emits an array of selected values
|
|
138
138
|
*/
|
|
139
139
|
export function selectFromEach<T, U>(
|
|
140
|
-
arrayNode: Observable<
|
|
140
|
+
arrayNode: Observable<T[]>,
|
|
141
141
|
selector: (item: T, index: number) => U
|
|
142
142
|
): Observable<U[]> {
|
|
143
143
|
return arrayNode.pipe(
|