juststore 0.0.1 → 0.0.2
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/LICENSE +661 -0
- package/README.md +358 -0
- package/dist/form.d.ts +35 -3
- package/dist/form.js +58 -0
- package/dist/impl.d.ts +69 -6
- package/dist/impl.js +107 -18
- package/dist/memory.d.ts +35 -3
- package/dist/memory.js +35 -3
- package/dist/mixed_state.d.ts +4 -0
- package/dist/node.d.ts +31 -1
- package/dist/node.js +25 -1
- package/dist/root.d.ts +16 -0
- package/dist/root.js +12 -0
- package/dist/store.d.ts +23 -0
- package/dist/store.js +23 -0
- package/package.json +1 -1
package/dist/impl.js
CHANGED
|
@@ -3,6 +3,13 @@ import isEqual from 'react-fast-compare';
|
|
|
3
3
|
import { localStorageDelete, localStorageGet, localStorageSet } from './local_storage';
|
|
4
4
|
export { getNestedValue, getSnapshot, joinPath, notifyListeners, produce, setLeaf, useDebounce, useObject, useSubscribe };
|
|
5
5
|
const memoryStore = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Joins a namespace and path into a full key string.
|
|
8
|
+
*
|
|
9
|
+
* @param namespace - The store namespace (root key)
|
|
10
|
+
* @param path - Optional dot-separated path within the namespace
|
|
11
|
+
* @returns Combined key string (e.g., "app.user.name")
|
|
12
|
+
*/
|
|
6
13
|
function joinPath(namespace, path) {
|
|
7
14
|
if (!path)
|
|
8
15
|
return namespace;
|
|
@@ -32,22 +39,27 @@ function getNestedValue(obj, path) {
|
|
|
32
39
|
}
|
|
33
40
|
return current;
|
|
34
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a deep clone of an object, optimized for common cases.
|
|
44
|
+
*
|
|
45
|
+
* Uses fast paths for primitives and arrays of primitives, falling back
|
|
46
|
+
* to structuredClone for complex objects. Returns null if cloning fails.
|
|
47
|
+
*
|
|
48
|
+
* @param obj - The value to clone
|
|
49
|
+
* @returns A deep copy of the value, or null if cloning fails
|
|
50
|
+
*/
|
|
35
51
|
function tryStructuredClone(obj) {
|
|
36
52
|
if (obj === null || obj === undefined)
|
|
37
53
|
return null;
|
|
38
54
|
if (typeof obj !== 'object')
|
|
39
55
|
return obj;
|
|
40
|
-
// Fast path for array type
|
|
41
56
|
if (Array.isArray(obj)) {
|
|
42
|
-
// Check if array needs deep cloning (contains objects/arrays)
|
|
43
57
|
const needsDeepClone = obj.some(item => item !== null && typeof item === 'object');
|
|
44
58
|
if (!needsDeepClone) {
|
|
45
|
-
// Array of primitives - just return new array reference
|
|
46
59
|
return [...obj];
|
|
47
60
|
}
|
|
48
61
|
return obj.map(item => tryStructuredClone(item));
|
|
49
62
|
}
|
|
50
|
-
// Fallback to structuredClone for complex objects
|
|
51
63
|
try {
|
|
52
64
|
return structuredClone(obj);
|
|
53
65
|
}
|
|
@@ -56,10 +68,16 @@ function tryStructuredClone(obj) {
|
|
|
56
68
|
}
|
|
57
69
|
}
|
|
58
70
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
71
|
+
* Immutably sets or deletes a nested value using a dot-separated path.
|
|
72
|
+
*
|
|
73
|
+
* Creates intermediate objects or arrays as needed based on whether the next
|
|
74
|
+
* path segment is numeric. When value is undefined, the key is deleted from
|
|
75
|
+
* objects or the index is spliced from arrays.
|
|
76
|
+
*
|
|
77
|
+
* @param obj - The root object to update
|
|
78
|
+
* @param path - Dot-separated path to the target location
|
|
79
|
+
* @param value - The value to set, or undefined to delete
|
|
80
|
+
* @returns A new root object with the change applied
|
|
63
81
|
*/
|
|
64
82
|
function setNestedValue(obj, path, value) {
|
|
65
83
|
if (!path)
|
|
@@ -111,17 +129,36 @@ function setNestedValue(obj, path, value) {
|
|
|
111
129
|
}
|
|
112
130
|
return result;
|
|
113
131
|
}
|
|
114
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Extracts the root namespace from a full key.
|
|
134
|
+
*
|
|
135
|
+
* @param key - Full key string (e.g., "app.user.name")
|
|
136
|
+
* @returns The first segment (e.g., "app")
|
|
137
|
+
*/
|
|
115
138
|
function getRootKey(key) {
|
|
116
139
|
return key.split('.')[0];
|
|
117
140
|
}
|
|
118
|
-
/**
|
|
141
|
+
/**
|
|
142
|
+
* Extracts the nested path from a full key, excluding the namespace.
|
|
143
|
+
*
|
|
144
|
+
* @param key - Full key string (e.g., "app.user.name")
|
|
145
|
+
* @returns The path after the namespace (e.g., "user.name")
|
|
146
|
+
*/
|
|
119
147
|
function getPath(key) {
|
|
120
148
|
const segments = key.split('.');
|
|
121
149
|
return segments.slice(1).join('.');
|
|
122
150
|
}
|
|
123
|
-
|
|
124
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Notifies all relevant listeners when a value changes.
|
|
153
|
+
*
|
|
154
|
+
* Handles three types of listeners:
|
|
155
|
+
* 1. Exact match - listeners subscribed to the exact changed path
|
|
156
|
+
* 2. Root listeners - listeners on the namespace root (for full-store subscriptions)
|
|
157
|
+
* 3. Child listeners - listeners on nested paths that may be affected by the change
|
|
158
|
+
*
|
|
159
|
+
* Child listeners are only notified if their specific value actually changed,
|
|
160
|
+
* determined by deep equality comparison.
|
|
161
|
+
*/
|
|
125
162
|
function notifyListeners(key, oldValue, newValue, skipRoot = false, skipChildren = false) {
|
|
126
163
|
const rootKey = skipRoot ? null : key.split('.').slice(0, 2).join('.');
|
|
127
164
|
const keyPrefix = skipChildren ? null : key + '.';
|
|
@@ -282,7 +319,13 @@ if (broadcastChannel) {
|
|
|
282
319
|
});
|
|
283
320
|
}
|
|
284
321
|
const listeners = new Map();
|
|
285
|
-
/**
|
|
322
|
+
/**
|
|
323
|
+
* Subscribes to changes for a specific key.
|
|
324
|
+
*
|
|
325
|
+
* @param key - The full key path to subscribe to
|
|
326
|
+
* @param listener - Callback invoked when the value changes
|
|
327
|
+
* @returns An unsubscribe function to remove the listener
|
|
328
|
+
*/
|
|
286
329
|
function subscribe(key, listener) {
|
|
287
330
|
if (!listeners.has(key)) {
|
|
288
331
|
listeners.set(key, new Set());
|
|
@@ -298,7 +341,17 @@ function subscribe(key, listener) {
|
|
|
298
341
|
}
|
|
299
342
|
};
|
|
300
343
|
}
|
|
301
|
-
/**
|
|
344
|
+
/**
|
|
345
|
+
* Core mutation function that updates the store and notifies listeners.
|
|
346
|
+
*
|
|
347
|
+
* Handles both setting and deleting values, with optimizations to skip
|
|
348
|
+
* unnecessary updates when the value hasn't changed.
|
|
349
|
+
*
|
|
350
|
+
* @param key - The full key path to update
|
|
351
|
+
* @param value - The new value, or undefined to delete
|
|
352
|
+
* @param skipUpdate - When true, skips notifying listeners
|
|
353
|
+
* @param memoryOnly - When true, skips localStorage persistence
|
|
354
|
+
*/
|
|
302
355
|
function produce(key, value, skipUpdate = false, memoryOnly = false) {
|
|
303
356
|
const current = store.get(key);
|
|
304
357
|
if (value === undefined) {
|
|
@@ -315,13 +368,32 @@ function produce(key, value, skipUpdate = false, memoryOnly = false) {
|
|
|
315
368
|
// Notify listeners hierarchically with old and new values
|
|
316
369
|
notifyListeners(key, current, value);
|
|
317
370
|
}
|
|
318
|
-
/**
|
|
371
|
+
/**
|
|
372
|
+
* React hook that subscribes to and reads a value at a path.
|
|
373
|
+
*
|
|
374
|
+
* Uses useSyncExternalStore for tear-free reads and automatic re-rendering
|
|
375
|
+
* when the subscribed value changes.
|
|
376
|
+
*
|
|
377
|
+
* @param key - The namespace or full key
|
|
378
|
+
* @param path - Optional path within the namespace
|
|
379
|
+
* @returns The current value at the path, or undefined if not set
|
|
380
|
+
*/
|
|
319
381
|
function useObject(key, path) {
|
|
320
382
|
const fullKey = joinPath(key, path);
|
|
321
383
|
const value = useSyncExternalStore(listener => subscribe(fullKey, listener), () => getSnapshot(fullKey), () => getSnapshot(fullKey));
|
|
322
384
|
return value;
|
|
323
385
|
}
|
|
324
|
-
/**
|
|
386
|
+
/**
|
|
387
|
+
* React hook that subscribes to a value with debounced updates.
|
|
388
|
+
*
|
|
389
|
+
* The returned value only updates after the specified delay has passed
|
|
390
|
+
* since the last change, useful for expensive operations like search.
|
|
391
|
+
*
|
|
392
|
+
* @param key - The namespace or full key
|
|
393
|
+
* @param path - Path within the namespace
|
|
394
|
+
* @param delay - Debounce delay in milliseconds
|
|
395
|
+
* @returns The debounced value at the path
|
|
396
|
+
*/
|
|
325
397
|
function useDebounce(key, path, delay) {
|
|
326
398
|
const fullKey = joinPath(key, path);
|
|
327
399
|
const currentValue = useSyncExternalStore(listener => subscribe(fullKey, listener), () => getSnapshot(fullKey), () => getSnapshot(fullKey));
|
|
@@ -344,7 +416,16 @@ function useDebounce(key, path, delay) {
|
|
|
344
416
|
}, [currentValue, delay, debouncedValue]);
|
|
345
417
|
return debouncedValue;
|
|
346
418
|
}
|
|
347
|
-
/**
|
|
419
|
+
/**
|
|
420
|
+
* React hook for side effects when a value changes.
|
|
421
|
+
*
|
|
422
|
+
* Unlike `use()`, this doesn't cause re-renders. Instead, it calls the
|
|
423
|
+
* provided callback whenever the value changes, useful for syncing with
|
|
424
|
+
* external systems or triggering effects.
|
|
425
|
+
*
|
|
426
|
+
* @param key - The full key path to subscribe to
|
|
427
|
+
* @param onChange - Callback invoked with the new value on each change
|
|
428
|
+
*/
|
|
348
429
|
function useSubscribe(key, onChange) {
|
|
349
430
|
const onChangeRef = useRef(onChange);
|
|
350
431
|
useEffect(() => {
|
|
@@ -358,7 +439,15 @@ function useSubscribe(key, onChange) {
|
|
|
358
439
|
return unsubscribe;
|
|
359
440
|
}, [key]);
|
|
360
441
|
}
|
|
361
|
-
/**
|
|
442
|
+
/**
|
|
443
|
+
* Sets a value at a specific path within a namespace.
|
|
444
|
+
*
|
|
445
|
+
* @param key - The namespace
|
|
446
|
+
* @param path - Path within the namespace
|
|
447
|
+
* @param value - The value to set, or undefined to delete
|
|
448
|
+
* @param skipUpdate - When true, skips notifying listeners
|
|
449
|
+
* @param memoryOnly - When true, skips localStorage persistence
|
|
450
|
+
*/
|
|
362
451
|
function setLeaf(key, path, value, skipUpdate = false, memoryOnly = false) {
|
|
363
452
|
const fullKey = joinPath(key, path);
|
|
364
453
|
produce(fullKey, value, skipUpdate, memoryOnly);
|
package/dist/memory.d.ts
CHANGED
|
@@ -14,8 +14,40 @@ type MemoryStore<T extends FieldValues> = State<T> & {
|
|
|
14
14
|
[K in keyof T]: NonNullable<T[K]> extends object ? DeepProxy<T[K]> : State<T[K]>;
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* React hook that creates a component-scoped memory store.
|
|
18
|
+
*
|
|
19
|
+
* Unlike `createStore`, this store is not persisted to localStorage and is
|
|
20
|
+
* unique to each component instance. Useful for complex local state that
|
|
21
|
+
* benefits from the store's path-based API without persistence.
|
|
22
|
+
*
|
|
23
|
+
* @param defaultValue - Initial state shape
|
|
24
|
+
* @returns A proxy providing dynamic path access to the store
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* type SearchState = {
|
|
28
|
+
* query: string
|
|
29
|
+
* filters: { category: string }
|
|
30
|
+
* results: { id: number; name: string }[]
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* function ProductSearch() {
|
|
34
|
+
* const state = useMemoryStore<SearchState>({
|
|
35
|
+
* query: '',
|
|
36
|
+
* filters: { category: 'all' },
|
|
37
|
+
* results: []
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* return (
|
|
41
|
+
* <>
|
|
42
|
+
* <SearchInput state={state} />
|
|
43
|
+
* <FilterPanel state={state} />
|
|
44
|
+
* </>
|
|
45
|
+
* )
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* function SearchInput({ state }: { state: MemoryStore<SearchState> }) {
|
|
49
|
+
* const query = state.query.use()
|
|
50
|
+
* return <input value={query} onChange={e => state.query.set(e.target.value)} />
|
|
51
|
+
* }
|
|
20
52
|
*/
|
|
21
53
|
declare function useMemoryStore<T extends FieldValues>(defaultValue: T): MemoryStore<T>;
|
package/dist/memory.js
CHANGED
|
@@ -3,9 +3,41 @@ import { createRootNode } from './node';
|
|
|
3
3
|
import { createStoreRoot } from './root';
|
|
4
4
|
export { useMemoryStore };
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* React hook that creates a component-scoped memory store.
|
|
7
|
+
*
|
|
8
|
+
* Unlike `createStore`, this store is not persisted to localStorage and is
|
|
9
|
+
* unique to each component instance. Useful for complex local state that
|
|
10
|
+
* benefits from the store's path-based API without persistence.
|
|
11
|
+
*
|
|
12
|
+
* @param defaultValue - Initial state shape
|
|
13
|
+
* @returns A proxy providing dynamic path access to the store
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* type SearchState = {
|
|
17
|
+
* query: string
|
|
18
|
+
* filters: { category: string }
|
|
19
|
+
* results: { id: number; name: string }[]
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* function ProductSearch() {
|
|
23
|
+
* const state = useMemoryStore<SearchState>({
|
|
24
|
+
* query: '',
|
|
25
|
+
* filters: { category: 'all' },
|
|
26
|
+
* results: []
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <>
|
|
31
|
+
* <SearchInput state={state} />
|
|
32
|
+
* <FilterPanel state={state} />
|
|
33
|
+
* </>
|
|
34
|
+
* )
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* function SearchInput({ state }: { state: MemoryStore<SearchState> }) {
|
|
38
|
+
* const query = state.query.use()
|
|
39
|
+
* return <input value={query} onChange={e => state.query.set(e.target.value)} />
|
|
40
|
+
* }
|
|
9
41
|
*/
|
|
10
42
|
function useMemoryStore(defaultValue) {
|
|
11
43
|
const memoryStoreId = useId();
|
package/dist/mixed_state.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Prettify, State } from './types';
|
|
2
2
|
export { createMixedState, type MixedState };
|
|
3
|
+
/**
|
|
4
|
+
* A combined state that aggregates multiple independent states into a tuple.
|
|
5
|
+
* Provides read-only access via `value`, `use`, `Render`, and `Show`.
|
|
6
|
+
*/
|
|
3
7
|
type MixedState<T extends readonly unknown[]> = Prettify<Pick<State<Readonly<T>>, 'value' | 'use' | 'Render' | 'Show'>>;
|
|
4
8
|
/**
|
|
5
9
|
* Creates a mixed state that combines multiple states into a tuple.
|
package/dist/node.d.ts
CHANGED
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
import type { FieldValues } from './path';
|
|
2
2
|
import type { State, StoreRoot } from './types';
|
|
3
3
|
export { createNode, createRootNode, type Extension };
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Creates the root proxy node for dynamic path access.
|
|
6
|
+
*
|
|
7
|
+
* This is an internal function that wraps a store API in a Proxy, enabling
|
|
8
|
+
* property-chain syntax like `store.user.profile.name.use()`.
|
|
9
|
+
*
|
|
10
|
+
* @param storeApi - The underlying store API with path-based methods
|
|
11
|
+
* @param initialPath - Starting path segment (default: empty string for root)
|
|
12
|
+
* @returns A proxy that intercepts property access and returns nested proxies or state methods
|
|
13
|
+
*/
|
|
5
14
|
declare function createRootNode<T extends FieldValues>(storeApi: StoreRoot<T>, initialPath?: string): State<T>;
|
|
15
|
+
/**
|
|
16
|
+
* Extension interface for adding custom getters/setters to proxy nodes.
|
|
17
|
+
* Used internally by form handling to add error-related methods.
|
|
18
|
+
*/
|
|
6
19
|
type Extension = {
|
|
20
|
+
/** Custom getter function */
|
|
7
21
|
get?: () => any;
|
|
22
|
+
/** Custom setter function; returns true if the set was handled */
|
|
8
23
|
set?: (value: any) => boolean;
|
|
9
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Creates a proxy node for a specific path in the store.
|
|
27
|
+
*
|
|
28
|
+
* The proxy intercepts property access to provide state methods (use, set, value, etc.)
|
|
29
|
+
* and recursively creates child proxies for nested paths. Supports derived state
|
|
30
|
+
* transformations via the `from` and `to` parameters.
|
|
31
|
+
*
|
|
32
|
+
* @param storeApi - The underlying store API
|
|
33
|
+
* @param path - Dot-separated path to this node (e.g., "user.profile.name")
|
|
34
|
+
* @param cache - Shared cache to avoid recreating proxies for the same path
|
|
35
|
+
* @param extensions - Optional custom getters/setters (used by form handling)
|
|
36
|
+
* @param from - Transform function applied when reading values (for derived state)
|
|
37
|
+
* @param to - Transform function applied when writing values (for derived state)
|
|
38
|
+
* @returns A proxy implementing the State interface for the given path
|
|
39
|
+
*/
|
|
10
40
|
declare function createNode<T extends FieldValues>(storeApi: StoreRoot<any>, path: string, cache: Map<string, any>, extensions?: Record<string | symbol, Extension>, from?: typeof unchanged, to?: typeof unchanged): State<T>;
|
|
11
41
|
declare function unchanged(value: any): any;
|
package/dist/node.js
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
export { createNode, createRootNode };
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Creates the root proxy node for dynamic path access.
|
|
6
|
+
*
|
|
7
|
+
* This is an internal function that wraps a store API in a Proxy, enabling
|
|
8
|
+
* property-chain syntax like `store.user.profile.name.use()`.
|
|
9
|
+
*
|
|
10
|
+
* @param storeApi - The underlying store API with path-based methods
|
|
11
|
+
* @param initialPath - Starting path segment (default: empty string for root)
|
|
12
|
+
* @returns A proxy that intercepts property access and returns nested proxies or state methods
|
|
13
|
+
*/
|
|
5
14
|
function createRootNode(storeApi, initialPath = '') {
|
|
6
15
|
const proxyCache = new Map();
|
|
7
16
|
return createNode(storeApi, initialPath, proxyCache);
|
|
8
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a proxy node for a specific path in the store.
|
|
20
|
+
*
|
|
21
|
+
* The proxy intercepts property access to provide state methods (use, set, value, etc.)
|
|
22
|
+
* and recursively creates child proxies for nested paths. Supports derived state
|
|
23
|
+
* transformations via the `from` and `to` parameters.
|
|
24
|
+
*
|
|
25
|
+
* @param storeApi - The underlying store API
|
|
26
|
+
* @param path - Dot-separated path to this node (e.g., "user.profile.name")
|
|
27
|
+
* @param cache - Shared cache to avoid recreating proxies for the same path
|
|
28
|
+
* @param extensions - Optional custom getters/setters (used by form handling)
|
|
29
|
+
* @param from - Transform function applied when reading values (for derived state)
|
|
30
|
+
* @param to - Transform function applied when writing values (for derived state)
|
|
31
|
+
* @returns A proxy implementing the State interface for the given path
|
|
32
|
+
*/
|
|
9
33
|
function createNode(storeApi, path, cache, extensions, from = unchanged, to = unchanged) {
|
|
10
34
|
const isDerived = from !== unchanged || to !== unchanged;
|
|
11
35
|
if (!isDerived && cache.has(path)) {
|
package/dist/root.d.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import type { FieldValues } from './path';
|
|
2
2
|
import type { StoreRoot } from './types';
|
|
3
3
|
export { createStoreRoot, type StoreOptions };
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for store creation.
|
|
6
|
+
*/
|
|
4
7
|
type StoreOptions = {
|
|
8
|
+
/** When true, the store only uses memory and does not persist to localStorage */
|
|
5
9
|
memoryOnly?: boolean;
|
|
6
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Creates the core store API with path-based methods.
|
|
13
|
+
*
|
|
14
|
+
* This is an internal function that sets up the subscription system, persistence,
|
|
15
|
+
* and provides the base API that the proxy wraps. The returned object contains
|
|
16
|
+
* methods like `use`, `set`, `value`, etc. that accept path strings.
|
|
17
|
+
*
|
|
18
|
+
* @param namespace - Unique identifier for the store
|
|
19
|
+
* @param defaultValue - Initial state merged with any persisted data
|
|
20
|
+
* @param options - Configuration options
|
|
21
|
+
* @returns The store API object with path-based methods
|
|
22
|
+
*/
|
|
7
23
|
declare function createStoreRoot<T extends FieldValues>(namespace: string, defaultValue: T, options?: StoreOptions): StoreRoot<T>;
|
package/dist/root.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { useCallback, useRef } from 'react';
|
|
2
2
|
import { getNestedValue, getSnapshot, joinPath, notifyListeners, produce, setLeaf, useDebounce, useObject, useSubscribe } from './impl';
|
|
3
3
|
export { createStoreRoot };
|
|
4
|
+
/**
|
|
5
|
+
* Creates the core store API with path-based methods.
|
|
6
|
+
*
|
|
7
|
+
* This is an internal function that sets up the subscription system, persistence,
|
|
8
|
+
* and provides the base API that the proxy wraps. The returned object contains
|
|
9
|
+
* methods like `use`, `set`, `value`, etc. that accept path strings.
|
|
10
|
+
*
|
|
11
|
+
* @param namespace - Unique identifier for the store
|
|
12
|
+
* @param defaultValue - Initial state merged with any persisted data
|
|
13
|
+
* @param options - Configuration options
|
|
14
|
+
* @returns The store API object with path-based methods
|
|
15
|
+
*/
|
|
4
16
|
function createStoreRoot(namespace, defaultValue, options = {}) {
|
|
5
17
|
const memoryOnly = options?.memoryOnly ?? false;
|
|
6
18
|
if (memoryOnly) {
|
package/dist/store.d.ts
CHANGED
|
@@ -16,4 +16,27 @@ export { createStore, type Store };
|
|
|
16
16
|
type Store<T extends FieldValues> = StoreRoot<T> & {
|
|
17
17
|
[K in keyof T]: NonNullable<T[K]> extends object ? DeepProxy<T[K]> : State<T[K]>;
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Creates a persistent, hierarchical store with localStorage backing and cross-tab synchronization.
|
|
21
|
+
*
|
|
22
|
+
* @param namespace - Unique identifier for the store, used as the localStorage key prefix
|
|
23
|
+
* @param defaultValue - Initial state shape; merged with any existing persisted data
|
|
24
|
+
* @param options - Configuration options
|
|
25
|
+
* @param options.memoryOnly - When true, disables localStorage persistence (default: false)
|
|
26
|
+
* @returns A proxy object providing both path-based and dynamic property access to the store
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const store = createStore('app', {
|
|
30
|
+
* user: { name: 'Guest' },
|
|
31
|
+
* todos: []
|
|
32
|
+
* })
|
|
33
|
+
*
|
|
34
|
+
* // Dynamic access
|
|
35
|
+
* store.user.name.use()
|
|
36
|
+
* store.todos.push({ text: 'New todo' })
|
|
37
|
+
*
|
|
38
|
+
* // Path-based access
|
|
39
|
+
* store.use('user.name')
|
|
40
|
+
* store.set('user.name', 'Alice')
|
|
41
|
+
*/
|
|
19
42
|
declare function createStore<T extends FieldValues>(namespace: string, defaultValue: T, options?: StoreOptions): Store<T>;
|
package/dist/store.js
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import { createRootNode } from './node';
|
|
2
2
|
import { createStoreRoot } from './root';
|
|
3
3
|
export { createStore };
|
|
4
|
+
/**
|
|
5
|
+
* Creates a persistent, hierarchical store with localStorage backing and cross-tab synchronization.
|
|
6
|
+
*
|
|
7
|
+
* @param namespace - Unique identifier for the store, used as the localStorage key prefix
|
|
8
|
+
* @param defaultValue - Initial state shape; merged with any existing persisted data
|
|
9
|
+
* @param options - Configuration options
|
|
10
|
+
* @param options.memoryOnly - When true, disables localStorage persistence (default: false)
|
|
11
|
+
* @returns A proxy object providing both path-based and dynamic property access to the store
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const store = createStore('app', {
|
|
15
|
+
* user: { name: 'Guest' },
|
|
16
|
+
* todos: []
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* // Dynamic access
|
|
20
|
+
* store.user.name.use()
|
|
21
|
+
* store.todos.push({ text: 'New todo' })
|
|
22
|
+
*
|
|
23
|
+
* // Path-based access
|
|
24
|
+
* store.use('user.name')
|
|
25
|
+
* store.set('user.name', 'Alice')
|
|
26
|
+
*/
|
|
4
27
|
function createStore(namespace, defaultValue, options = {}) {
|
|
5
28
|
const storeApi = createStoreRoot(namespace, defaultValue, options);
|
|
6
29
|
return new Proxy(storeApi, {
|