@montra-interactive/deepstate 0.1.1 → 0.2.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 +343 -0
- package/dist/deepstate.d.ts +39 -0
- package/dist/deepstate.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -3
- package/package.json +1 -1
- package/src/deepstate.ts +99 -3
- package/src/index.ts +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# @montra-interactive/deepstate
|
|
2
|
+
|
|
3
|
+
Proxy-based reactive state management powered by RxJS. Each property is its own observable with O(depth) change propagation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fine-grained reactivity**: Subscribe to any property at any depth
|
|
8
|
+
- **O(depth) performance**: Changes only notify ancestors, never siblings
|
|
9
|
+
- **Type-safe**: Full TypeScript support with inferred types
|
|
10
|
+
- **RxJS native**: Every node is an Observable - use `pipe()`, `combineLatest`, etc.
|
|
11
|
+
- **Batched updates**: Group multiple changes into a single emission
|
|
12
|
+
- **Immutable reads**: Values are deeply frozen to prevent accidental mutations
|
|
13
|
+
- **Nullable objects**: First-class support for `T | null` properties with deep subscription
|
|
14
|
+
- **Debug mode**: Optional logging for development
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @montra-interactive/deepstate rxjs
|
|
20
|
+
# or
|
|
21
|
+
bun add @montra-interactive/deepstate rxjs
|
|
22
|
+
# or
|
|
23
|
+
yarn add @montra-interactive/deepstate rxjs
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { state } from "@montra-interactive/deepstate";
|
|
30
|
+
|
|
31
|
+
// Create reactive state
|
|
32
|
+
const store = state({
|
|
33
|
+
user: { name: "Alice", age: 30 },
|
|
34
|
+
todos: [{ id: 1, text: "Learn deepstate", done: false }],
|
|
35
|
+
count: 0,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Subscribe to any property (it's an Observable)
|
|
39
|
+
store.user.name.subscribe(name => console.log("Name:", name));
|
|
40
|
+
|
|
41
|
+
// Get values synchronously
|
|
42
|
+
console.log(store.user.name.get()); // "Alice"
|
|
43
|
+
|
|
44
|
+
// Set values
|
|
45
|
+
store.user.name.set("Bob"); // triggers subscription
|
|
46
|
+
|
|
47
|
+
// Subscribe to parent nodes (emits when any child changes)
|
|
48
|
+
store.user.subscribe(user => console.log("User changed:", user));
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API Reference
|
|
52
|
+
|
|
53
|
+
### `state<T>(initialState, options?)`
|
|
54
|
+
|
|
55
|
+
Creates a reactive state store.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { state } from "@montra-interactive/deepstate";
|
|
59
|
+
|
|
60
|
+
const store = state({
|
|
61
|
+
user: { name: "Alice", age: 30 },
|
|
62
|
+
items: [{ id: 1, name: "Item 1" }],
|
|
63
|
+
count: 0,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// With debug mode
|
|
67
|
+
const debugStore = state(
|
|
68
|
+
{ count: 0 },
|
|
69
|
+
{ debug: true, name: "counter" }
|
|
70
|
+
);
|
|
71
|
+
// Logs: [deepstate:counter] set count: 0 -> 1
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Options:**
|
|
75
|
+
|
|
76
|
+
| Option | Type | Description |
|
|
77
|
+
|--------|------|-------------|
|
|
78
|
+
| `debug` | `boolean` | Enable debug logging for all set operations |
|
|
79
|
+
| `name` | `string` | Store name used in debug log prefix |
|
|
80
|
+
|
|
81
|
+
### Node Methods
|
|
82
|
+
|
|
83
|
+
Every property on the state is a reactive node with these methods:
|
|
84
|
+
|
|
85
|
+
| Method | Description |
|
|
86
|
+
|--------|-------------|
|
|
87
|
+
| `.get()` | Get current value synchronously |
|
|
88
|
+
| `.set(value)` | Update the value |
|
|
89
|
+
| `.subscribe(callback)` | Subscribe to changes (RxJS Observable) |
|
|
90
|
+
| `.pipe(operators...)` | Chain RxJS operators |
|
|
91
|
+
| `.subscribeOnce(callback)` | Subscribe to a single emission, then auto-unsubscribe |
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
// Primitives
|
|
95
|
+
store.count.get(); // 0
|
|
96
|
+
store.count.set(5); // Updates to 5
|
|
97
|
+
|
|
98
|
+
// Objects
|
|
99
|
+
store.user.get(); // { name: "Alice", age: 30 }
|
|
100
|
+
store.user.name.get(); // "Alice"
|
|
101
|
+
store.user.name.set("Bob");
|
|
102
|
+
|
|
103
|
+
// Subscribe at any level
|
|
104
|
+
store.user.name.subscribe(name => console.log(name));
|
|
105
|
+
store.user.subscribe(user => console.log(user));
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Batched Updates with `.update()`
|
|
109
|
+
|
|
110
|
+
Batch multiple changes into a single emission:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// Without batching - emits twice
|
|
114
|
+
store.user.name.set("Bob");
|
|
115
|
+
store.user.age.set(31);
|
|
116
|
+
// Subscribers see intermediate state
|
|
117
|
+
|
|
118
|
+
// With batching - emits once
|
|
119
|
+
store.user.update(user => {
|
|
120
|
+
user.name.set("Bob");
|
|
121
|
+
user.age.set(31);
|
|
122
|
+
});
|
|
123
|
+
// Subscribers only see final state
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Arrays
|
|
127
|
+
|
|
128
|
+
Arrays have additional methods:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const store = state({
|
|
132
|
+
items: [
|
|
133
|
+
{ id: 1, name: "First" },
|
|
134
|
+
{ id: 2, name: "Second" },
|
|
135
|
+
],
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Access by index
|
|
139
|
+
store.items.at(0)?.name.get(); // "First"
|
|
140
|
+
store.items.at(0)?.name.set("Updated");
|
|
141
|
+
|
|
142
|
+
// Array methods
|
|
143
|
+
store.items.push({ id: 3, name: "Third" }); // Returns new length
|
|
144
|
+
store.items.pop(); // Returns removed item
|
|
145
|
+
store.items.length.get(); // Current length
|
|
146
|
+
|
|
147
|
+
// Observable length
|
|
148
|
+
store.items.length.subscribe(len => console.log("Length:", len));
|
|
149
|
+
|
|
150
|
+
// Non-reactive iteration
|
|
151
|
+
store.items.map((item, i) => item.name);
|
|
152
|
+
store.items.filter(item => item.id > 1);
|
|
153
|
+
|
|
154
|
+
// Batched array updates
|
|
155
|
+
store.items.update(items => {
|
|
156
|
+
items.at(0)?.name.set("Modified");
|
|
157
|
+
items.push({ id: 4, name: "New" });
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### `array(value, options?)` - Array with Distinct
|
|
162
|
+
|
|
163
|
+
Control array emission deduplication:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { state, array } from "@montra-interactive/deepstate";
|
|
167
|
+
|
|
168
|
+
const store = state({
|
|
169
|
+
// No deduplication (default)
|
|
170
|
+
items: [1, 2, 3],
|
|
171
|
+
|
|
172
|
+
// Reference equality per element
|
|
173
|
+
tags: array(["a", "b"], { distinct: "shallow" }),
|
|
174
|
+
|
|
175
|
+
// JSON comparison (deep equality)
|
|
176
|
+
settings: array([{ theme: "dark" }], { distinct: "deep" }),
|
|
177
|
+
|
|
178
|
+
// Custom comparator
|
|
179
|
+
custom: array([1, 2, 3], {
|
|
180
|
+
distinct: (a, b) => a.length === b.length
|
|
181
|
+
}),
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Distinct Options:**
|
|
186
|
+
|
|
187
|
+
| Value | Description |
|
|
188
|
+
|-------|-------------|
|
|
189
|
+
| `false` | No deduplication (default) |
|
|
190
|
+
| `"shallow"` | Reference equality: `a[i] === b[i]` |
|
|
191
|
+
| `"deep"` | JSON comparison: `JSON.stringify(a) === JSON.stringify(b)` |
|
|
192
|
+
| `(a, b) => boolean` | Custom comparator function |
|
|
193
|
+
|
|
194
|
+
### `nullable(value)` - Nullable Objects
|
|
195
|
+
|
|
196
|
+
For properties that can be `null` or an object:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { state, nullable } from "@montra-interactive/deepstate";
|
|
200
|
+
|
|
201
|
+
const store = state({
|
|
202
|
+
// Start as null, can become object
|
|
203
|
+
user: nullable<{ name: string; age: number }>(null),
|
|
204
|
+
|
|
205
|
+
// Start as object, can become null
|
|
206
|
+
profile: nullable({ bio: "Hello", avatar: "url" }),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Deep subscription works even when null!
|
|
210
|
+
store.user.name.subscribe(name => {
|
|
211
|
+
console.log(name); // undefined when user is null, value when set
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Transitions
|
|
215
|
+
store.user.set({ name: "Alice", age: 30 }); // Now has value
|
|
216
|
+
store.user.name.set("Bob"); // Update nested
|
|
217
|
+
store.user.set(null); // Back to null
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### `select(...observables)` - Combine Observables
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { select } from "@montra-interactive/deepstate";
|
|
224
|
+
|
|
225
|
+
// Array form - returns tuple
|
|
226
|
+
select(store.user.name, store.count).subscribe(([name, count]) => {
|
|
227
|
+
console.log(`${name}: ${count}`);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Object form - returns object
|
|
231
|
+
select({
|
|
232
|
+
name: store.user.name,
|
|
233
|
+
count: store.count,
|
|
234
|
+
}).subscribe(({ name, count }) => {
|
|
235
|
+
console.log(`${name}: ${count}`);
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### `selectFromEach(arrayNode, selector)` - Select from Array Items
|
|
240
|
+
|
|
241
|
+
Derive values from each array item with precise change detection:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import { selectFromEach } from "@montra-interactive/deepstate";
|
|
245
|
+
|
|
246
|
+
const store = state({
|
|
247
|
+
items: [
|
|
248
|
+
{ name: "A", price: 10, qty: 2 },
|
|
249
|
+
{ name: "B", price: 20, qty: 1 },
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Select single property from each item
|
|
254
|
+
selectFromEach(store.items, item => item.price).subscribe(prices => {
|
|
255
|
+
console.log(prices); // [10, 20]
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Derive computed values
|
|
259
|
+
selectFromEach(store.items, item => item.price * item.qty).subscribe(totals => {
|
|
260
|
+
console.log(totals); // [20, 20]
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Only emits when selected values change
|
|
264
|
+
store.items.at(0)?.name.set("Changed"); // No emission (name wasn't selected)
|
|
265
|
+
store.items.at(0)?.price.set(15); // Emits [15, 20]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## RxJS Integration
|
|
269
|
+
|
|
270
|
+
Every node is a full RxJS Observable:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
import { debounceTime, filter, map } from "rxjs/operators";
|
|
274
|
+
|
|
275
|
+
store.user.name
|
|
276
|
+
.pipe(
|
|
277
|
+
debounceTime(300),
|
|
278
|
+
filter(name => name.length > 0),
|
|
279
|
+
map(name => name.toUpperCase())
|
|
280
|
+
)
|
|
281
|
+
.subscribe(name => console.log(name));
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## TypeScript
|
|
285
|
+
|
|
286
|
+
Full type inference from your initial state:
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
const store = state({
|
|
290
|
+
user: { name: "Alice", age: 30 },
|
|
291
|
+
items: [{ id: 1 }],
|
|
292
|
+
selectedId: null as string | null,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
store.user.name.get(); // string
|
|
296
|
+
store.user.age.get(); // number
|
|
297
|
+
store.items.at(0)?.id; // RxLeaf<number> | undefined
|
|
298
|
+
store.selectedId.get(); // string | null
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Type Exports
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import type { RxState, Draft, DeepReadonly } from "@montra-interactive/deepstate";
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
| Type | Description |
|
|
308
|
+
|------|-------------|
|
|
309
|
+
| `RxState<T>` | The reactive state type returned by `state()` |
|
|
310
|
+
| `Draft<T>` | Type alias for values in update callbacks |
|
|
311
|
+
| `DeepReadonly<T>` | Deep readonly type for returned values |
|
|
312
|
+
|
|
313
|
+
## Architecture
|
|
314
|
+
|
|
315
|
+
deepstate uses a **nested BehaviorSubject architecture**:
|
|
316
|
+
|
|
317
|
+
- **Primitives**: Each has its own `BehaviorSubject`
|
|
318
|
+
- **Objects**: Derived from `combineLatest(children)`
|
|
319
|
+
- **Arrays**: `BehaviorSubject<T[]>` with child projections
|
|
320
|
+
|
|
321
|
+
This gives **O(depth) performance**: updating `store.a.b.c` only notifies `c`, `b`, `a`, and the root - never siblings like `store.x.y.z`.
|
|
322
|
+
|
|
323
|
+
## React Integration
|
|
324
|
+
|
|
325
|
+
See [@montra-interactive/deepstate-react](https://www.npmjs.com/package/@montra-interactive/deepstate-react) for React hooks:
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
import { useSelect, usePipeSelect } from "@montra-interactive/deepstate-react";
|
|
329
|
+
|
|
330
|
+
function UserName() {
|
|
331
|
+
const name = useSelect(store.user.name);
|
|
332
|
+
return <span>{name}</span>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function DebouncedSearch() {
|
|
336
|
+
const query = usePipeSelect(store.search.pipe(debounceTime(300)));
|
|
337
|
+
return <input value={query ?? ""} />;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## License
|
|
342
|
+
|
|
343
|
+
MIT
|
package/dist/deepstate.d.ts
CHANGED
|
@@ -191,5 +191,44 @@ export declare function state<T extends object>(initialState: T, options?: State
|
|
|
191
191
|
* store.user?.name.set("Charlie"); // After ?. on user, children are directly accessible
|
|
192
192
|
*/
|
|
193
193
|
export declare function nullable<T extends object>(value: T | null): T | null;
|
|
194
|
+
/** Comparison mode for array distinct checking */
|
|
195
|
+
export type ArrayDistinct<T> = false | 'shallow' | 'deep' | ((a: T[], b: T[]) => boolean);
|
|
196
|
+
/** Options for the array() helper */
|
|
197
|
+
export interface ArrayOptions<T> {
|
|
198
|
+
/**
|
|
199
|
+
* How to compare arrays to prevent duplicate emissions.
|
|
200
|
+
* - false: No deduplication (default, always emits on set)
|
|
201
|
+
* - 'shallow': Reference equality per element (a[i] === b[i])
|
|
202
|
+
* - 'deep': JSON.stringify comparison (expensive for large arrays)
|
|
203
|
+
* - function: Custom comparator (a, b) => boolean
|
|
204
|
+
*/
|
|
205
|
+
distinct?: ArrayDistinct<T>;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Marks an array with options for how it should behave in state.
|
|
209
|
+
* Use this to enable deduplication (prevent emissions when setting same values).
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* const store = state({
|
|
214
|
+
* // Default behavior - emits on every set
|
|
215
|
+
* items: [1, 2, 3],
|
|
216
|
+
*
|
|
217
|
+
* // Shallow comparison - only emits if elements differ by reference
|
|
218
|
+
* tags: array(['a', 'b'], { distinct: 'shallow' }),
|
|
219
|
+
*
|
|
220
|
+
* // Deep comparison - only emits if JSON representation differs
|
|
221
|
+
* settings: array([{ theme: 'dark' }], { distinct: 'deep' }),
|
|
222
|
+
*
|
|
223
|
+
* // Custom comparator - you define equality
|
|
224
|
+
* users: array([{ id: 1, name: 'Alice' }], {
|
|
225
|
+
* distinct: (a, b) =>
|
|
226
|
+
* a.length === b.length &&
|
|
227
|
+
* a.every((user, i) => user.id === b[i].id)
|
|
228
|
+
* }),
|
|
229
|
+
* });
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export declare function array<T>(value: T[], options?: ArrayOptions<T>): T[];
|
|
194
233
|
export {};
|
|
195
234
|
//# sourceMappingURL=deepstate.d.ts.map
|
package/dist/deepstate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Core exports:
|
|
5
5
|
* - state() - Create reactive state from plain objects
|
|
6
6
|
* - nullable() - Mark a property as nullable (can transition between null and object)
|
|
7
|
+
* - array() - Mark an array with deduplication options
|
|
7
8
|
* - RxState, Draft - Type exports
|
|
8
9
|
*
|
|
9
10
|
* Helper exports:
|
|
10
11
|
* - select() - Combine multiple observables
|
|
11
12
|
* - selectFromEach() - Select from each array item with precise change detection
|
|
12
13
|
*/
|
|
13
|
-
export { state, nullable, type RxState, type Draft, type StateOptions } from "./deepstate";
|
|
14
|
+
export { state, nullable, array, type RxState, type Draft, type StateOptions, type ArrayOptions, type ArrayDistinct } from "./deepstate";
|
|
14
15
|
export { select, selectFromEach } from "./helpers";
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACzI,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -164,7 +164,7 @@ function createObjectNode(value) {
|
|
|
164
164
|
}
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
|
-
function createArrayNode(value) {
|
|
167
|
+
function createArrayNode(value, comparator) {
|
|
168
168
|
const subject$ = new BehaviorSubject([...value]);
|
|
169
169
|
const childCache = new Map;
|
|
170
170
|
const createChildProjection = (index) => {
|
|
@@ -188,7 +188,8 @@ function createArrayNode(value) {
|
|
|
188
188
|
};
|
|
189
189
|
};
|
|
190
190
|
const lock$ = new BehaviorSubject(true);
|
|
191
|
-
const
|
|
191
|
+
const baseLocked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr));
|
|
192
|
+
const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2(deepFreeze), shareReplay(1));
|
|
192
193
|
locked$.subscribe();
|
|
193
194
|
const length$ = locked$.pipe(map2((arr) => arr.length), distinctUntilChanged2(), shareReplay(1));
|
|
194
195
|
length$.subscribe();
|
|
@@ -562,6 +563,12 @@ function createNodeForValue(value, maybeNullable = false) {
|
|
|
562
563
|
return createLeafNode(value);
|
|
563
564
|
}
|
|
564
565
|
if (Array.isArray(value)) {
|
|
566
|
+
if (isArrayMarked(value)) {
|
|
567
|
+
const options = value[ARRAY_MARKER];
|
|
568
|
+
const comparator = getArrayComparator(options);
|
|
569
|
+
delete value[ARRAY_MARKER];
|
|
570
|
+
return createArrayNode(value, comparator);
|
|
571
|
+
}
|
|
565
572
|
return createArrayNode(value);
|
|
566
573
|
}
|
|
567
574
|
return createObjectNode(value);
|
|
@@ -782,9 +789,30 @@ function nullable(value) {
|
|
|
782
789
|
function isNullableMarked(value) {
|
|
783
790
|
return value !== null && typeof value === "object" && NULLABLE_MARKER in value;
|
|
784
791
|
}
|
|
792
|
+
var ARRAY_MARKER = Symbol("array");
|
|
793
|
+
function array(value, options = {}) {
|
|
794
|
+
const marked = [...value];
|
|
795
|
+
marked[ARRAY_MARKER] = options;
|
|
796
|
+
return marked;
|
|
797
|
+
}
|
|
798
|
+
function isArrayMarked(value) {
|
|
799
|
+
return Array.isArray(value) && ARRAY_MARKER in value;
|
|
800
|
+
}
|
|
801
|
+
function getArrayComparator(options) {
|
|
802
|
+
if (!options.distinct)
|
|
803
|
+
return;
|
|
804
|
+
if (options.distinct === "shallow") {
|
|
805
|
+
return (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
806
|
+
}
|
|
807
|
+
if (options.distinct === "deep") {
|
|
808
|
+
return (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
809
|
+
}
|
|
810
|
+
return options.distinct;
|
|
811
|
+
}
|
|
785
812
|
export {
|
|
786
813
|
state,
|
|
787
814
|
selectFromEach,
|
|
788
815
|
select,
|
|
789
|
-
nullable
|
|
816
|
+
nullable,
|
|
817
|
+
array
|
|
790
818
|
};
|
package/package.json
CHANGED
package/src/deepstate.ts
CHANGED
|
@@ -424,7 +424,10 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
|
|
|
424
424
|
};
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
function createArrayNode<T>(
|
|
427
|
+
function createArrayNode<T>(
|
|
428
|
+
value: T[],
|
|
429
|
+
comparator?: (a: T[], b: T[]) => boolean
|
|
430
|
+
): NodeCore<T[]> & {
|
|
428
431
|
at(index: number): NodeCore<T> | undefined;
|
|
429
432
|
childCache: Map<number, NodeCore<T>>;
|
|
430
433
|
length$: Observable<number> & { get(): number };
|
|
@@ -478,10 +481,17 @@ function createArrayNode<T>(value: T[]): NodeCore<T[]> & {
|
|
|
478
481
|
// Lock for batching updates - when false, emissions are filtered out
|
|
479
482
|
const lock$ = new BehaviorSubject<boolean>(true);
|
|
480
483
|
|
|
481
|
-
// Create observable that respects lock
|
|
482
|
-
const
|
|
484
|
+
// Create observable that respects lock, with optional distinct comparison
|
|
485
|
+
const baseLocked$ = combineLatest([subject$, lock$]).pipe(
|
|
483
486
|
filter(([_, unlocked]) => unlocked),
|
|
484
487
|
map(([arr, _]) => arr),
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
// Apply distinct comparison if provided
|
|
491
|
+
const locked$ = (comparator
|
|
492
|
+
? baseLocked$.pipe(distinctUntilChanged(comparator))
|
|
493
|
+
: baseLocked$
|
|
494
|
+
).pipe(
|
|
485
495
|
map(deepFreeze),
|
|
486
496
|
shareReplay(1)
|
|
487
497
|
);
|
|
@@ -1079,6 +1089,14 @@ function createNodeForValue<T>(value: T, maybeNullable: boolean = false): NodeCo
|
|
|
1079
1089
|
return createLeafNode(value as Primitive) as NodeCore<T>;
|
|
1080
1090
|
}
|
|
1081
1091
|
if (Array.isArray(value)) {
|
|
1092
|
+
// Check if array was marked with options via array() helper
|
|
1093
|
+
if (isArrayMarked(value)) {
|
|
1094
|
+
const options = value[ARRAY_MARKER];
|
|
1095
|
+
const comparator = getArrayComparator(options);
|
|
1096
|
+
// Remove the marker before creating the node
|
|
1097
|
+
delete (value as Record<symbol, unknown>)[ARRAY_MARKER];
|
|
1098
|
+
return createArrayNode(value, comparator) as unknown as NodeCore<T>;
|
|
1099
|
+
}
|
|
1082
1100
|
return createArrayNode(value) as unknown as NodeCore<T>;
|
|
1083
1101
|
}
|
|
1084
1102
|
return createObjectNode(value as object) as unknown as NodeCore<T>;
|
|
@@ -1401,3 +1419,81 @@ export function nullable<T extends object>(value: T | null): T | null {
|
|
|
1401
1419
|
function isNullableMarked<T>(value: T): boolean {
|
|
1402
1420
|
return value !== null && typeof value === "object" && NULLABLE_MARKER in value;
|
|
1403
1421
|
}
|
|
1422
|
+
|
|
1423
|
+
// Symbol to mark an array with distinct options
|
|
1424
|
+
const ARRAY_MARKER = Symbol("array");
|
|
1425
|
+
|
|
1426
|
+
/** Comparison mode for array distinct checking */
|
|
1427
|
+
export type ArrayDistinct<T> =
|
|
1428
|
+
| false // No deduplication (default)
|
|
1429
|
+
| 'shallow' // Reference equality per element
|
|
1430
|
+
| 'deep' // JSON.stringify comparison
|
|
1431
|
+
| ((a: T[], b: T[]) => boolean); // Custom comparator
|
|
1432
|
+
|
|
1433
|
+
/** Options for the array() helper */
|
|
1434
|
+
export interface ArrayOptions<T> {
|
|
1435
|
+
/**
|
|
1436
|
+
* How to compare arrays to prevent duplicate emissions.
|
|
1437
|
+
* - false: No deduplication (default, always emits on set)
|
|
1438
|
+
* - 'shallow': Reference equality per element (a[i] === b[i])
|
|
1439
|
+
* - 'deep': JSON.stringify comparison (expensive for large arrays)
|
|
1440
|
+
* - function: Custom comparator (a, b) => boolean
|
|
1441
|
+
*/
|
|
1442
|
+
distinct?: ArrayDistinct<T>;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
interface MarkedArray<T> extends Array<T> {
|
|
1446
|
+
[ARRAY_MARKER]: ArrayOptions<T>;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
/**
|
|
1450
|
+
* Marks an array with options for how it should behave in state.
|
|
1451
|
+
* Use this to enable deduplication (prevent emissions when setting same values).
|
|
1452
|
+
*
|
|
1453
|
+
* @example
|
|
1454
|
+
* ```ts
|
|
1455
|
+
* const store = state({
|
|
1456
|
+
* // Default behavior - emits on every set
|
|
1457
|
+
* items: [1, 2, 3],
|
|
1458
|
+
*
|
|
1459
|
+
* // Shallow comparison - only emits if elements differ by reference
|
|
1460
|
+
* tags: array(['a', 'b'], { distinct: 'shallow' }),
|
|
1461
|
+
*
|
|
1462
|
+
* // Deep comparison - only emits if JSON representation differs
|
|
1463
|
+
* settings: array([{ theme: 'dark' }], { distinct: 'deep' }),
|
|
1464
|
+
*
|
|
1465
|
+
* // Custom comparator - you define equality
|
|
1466
|
+
* users: array([{ id: 1, name: 'Alice' }], {
|
|
1467
|
+
* distinct: (a, b) =>
|
|
1468
|
+
* a.length === b.length &&
|
|
1469
|
+
* a.every((user, i) => user.id === b[i].id)
|
|
1470
|
+
* }),
|
|
1471
|
+
* });
|
|
1472
|
+
* ```
|
|
1473
|
+
*/
|
|
1474
|
+
export function array<T>(value: T[], options: ArrayOptions<T> = {}): T[] {
|
|
1475
|
+
const marked = [...value] as MarkedArray<T>;
|
|
1476
|
+
marked[ARRAY_MARKER] = options;
|
|
1477
|
+
return marked;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// Check if an array was marked with options
|
|
1481
|
+
function isArrayMarked<T>(value: unknown): value is MarkedArray<T> {
|
|
1482
|
+
return Array.isArray(value) && ARRAY_MARKER in value;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Get the distinct comparator function from array options
|
|
1486
|
+
function getArrayComparator<T>(options: ArrayOptions<T>): ((a: T[], b: T[]) => boolean) | undefined {
|
|
1487
|
+
if (!options.distinct) return undefined;
|
|
1488
|
+
|
|
1489
|
+
if (options.distinct === 'shallow') {
|
|
1490
|
+
return (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
if (options.distinct === 'deep') {
|
|
1494
|
+
return (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// Custom function
|
|
1498
|
+
return options.distinct;
|
|
1499
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Core exports:
|
|
5
5
|
* - state() - Create reactive state from plain objects
|
|
6
6
|
* - nullable() - Mark a property as nullable (can transition between null and object)
|
|
7
|
+
* - array() - Mark an array with deduplication options
|
|
7
8
|
* - RxState, Draft - Type exports
|
|
8
9
|
*
|
|
9
10
|
* Helper exports:
|
|
@@ -11,5 +12,5 @@
|
|
|
11
12
|
* - selectFromEach() - Select from each array item with precise change detection
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
|
-
export { state, nullable, type RxState, type Draft, type StateOptions } from "./deepstate";
|
|
15
|
+
export { state, nullable, array, type RxState, type Draft, type StateOptions, type ArrayOptions, type ArrayDistinct } from "./deepstate";
|
|
15
16
|
export { select, selectFromEach } from "./helpers";
|