juststore 0.0.7 → 0.1.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/README.md +35 -16
- package/dist/node.js +2 -13
- package/dist/root.js +13 -2
- package/dist/types.d.ts +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -291,7 +291,7 @@ function TemperatureInput() {
|
|
|
291
291
|
|
|
292
292
|
```tsx
|
|
293
293
|
function TotalPrice() {
|
|
294
|
-
const total = store.cart.items.
|
|
294
|
+
const total = store.cart.items.useCompute(
|
|
295
295
|
items => items?.reduce((sum, item) => sum + item.price * item.qty, 0) ?? 0
|
|
296
296
|
)
|
|
297
297
|
return <span>Total: ${total}</span>
|
|
@@ -450,23 +450,42 @@ Creates a component-scoped store that doesn't persist.
|
|
|
450
450
|
|
|
451
451
|
Creates a form store with validation support.
|
|
452
452
|
|
|
453
|
+
### Root Node Methods
|
|
454
|
+
|
|
455
|
+
The store root provides path-based methods for dynamic access:
|
|
456
|
+
|
|
457
|
+
| Method | Description |
|
|
458
|
+
| ------------------------------- | ------------------------------------------------------- |
|
|
459
|
+
| `.use(path)` | Subscribe and read value (triggers re-render on change) |
|
|
460
|
+
| `.useDebounce(path, ms)` | Subscribe with debounced updates |
|
|
461
|
+
| `.useState(path)` | Returns `[value, setValue]` tuple |
|
|
462
|
+
| `.value(path)` | Read without subscribing |
|
|
463
|
+
| `.set(path, value)` | Update value |
|
|
464
|
+
| `.set(path, fn)` | Functional update |
|
|
465
|
+
| `.reset(path)` | Delete value at path |
|
|
466
|
+
| `.subscribe(path, fn)` | Subscribe to changes (for effects) |
|
|
467
|
+
| `.notify(path)` | Manually trigger subscribers |
|
|
468
|
+
| `.useCompute(path, fn)` | Derive a computed value |
|
|
469
|
+
| `.Render({ path, children })` | Render prop component |
|
|
470
|
+
| `.Show({ path, children, on })` | Conditional render component |
|
|
471
|
+
|
|
453
472
|
### State Methods
|
|
454
473
|
|
|
455
|
-
| Method
|
|
456
|
-
|
|
|
457
|
-
| `.use()`
|
|
458
|
-
| `.useDebounce(ms)`
|
|
459
|
-
| `.useState()`
|
|
460
|
-
| `.value`
|
|
461
|
-
| `.set(value)`
|
|
462
|
-
| `.set(fn)`
|
|
463
|
-
| `.reset()`
|
|
464
|
-
| `.subscribe(fn)`
|
|
465
|
-
| `.notify()`
|
|
466
|
-
| `.
|
|
467
|
-
| `.derived({ from, to })`
|
|
468
|
-
| `.Render`
|
|
469
|
-
| `.Show`
|
|
474
|
+
| Method | Description |
|
|
475
|
+
| ------------------------- | ------------------------------------------------------- |
|
|
476
|
+
| `.use()` | Subscribe and read value (triggers re-render on change) |
|
|
477
|
+
| `.useDebounce(ms)` | Subscribe with debounced updates |
|
|
478
|
+
| `.useState()` | Returns `[value, setValue]` tuple |
|
|
479
|
+
| `.value` | Read without subscribing |
|
|
480
|
+
| `.set(value)` | Update value |
|
|
481
|
+
| `.set(fn)` | Functional update |
|
|
482
|
+
| `.reset()` | Delete value at path |
|
|
483
|
+
| `.subscribe(fn)` | Subscribe to changes (for effects) |
|
|
484
|
+
| `.notify()` | Manually trigger subscribers |
|
|
485
|
+
| `.useCompute(fn)` | Derive a computed value |
|
|
486
|
+
| `.derived({ from, to })` | Create bidirectional transform |
|
|
487
|
+
| `.Render({ children })` | Render prop component |
|
|
488
|
+
| `.Show({ children, on })` | Conditional render component |
|
|
470
489
|
|
|
471
490
|
## License
|
|
472
491
|
|
package/dist/node.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { isEqual } from './impl';
|
|
4
1
|
export { createNode, createRootNode };
|
|
5
2
|
/**
|
|
6
3
|
* Creates the root proxy node for dynamic path access.
|
|
@@ -71,17 +68,9 @@ function createNode(storeApi, path, cache, extensions, from = unchanged, to = un
|
|
|
71
68
|
if (prop === 'Show') {
|
|
72
69
|
return ({ children, on }) => storeApi.Show({ path, children, on: value => on(from(value)) });
|
|
73
70
|
}
|
|
74
|
-
if (prop === '
|
|
71
|
+
if (prop === 'useCompute') {
|
|
75
72
|
return (fn) => {
|
|
76
|
-
|
|
77
|
-
const [computedValue, setComputedValue] = useState(() => fn(initialValue));
|
|
78
|
-
storeApi.subscribe(path, value => {
|
|
79
|
-
const newValue = fn(from(value));
|
|
80
|
-
if (!isEqual(computedValue, newValue)) {
|
|
81
|
-
setComputedValue(newValue);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
return computedValue;
|
|
73
|
+
return storeApi.useCompute(path, value => fn(from(value)));
|
|
85
74
|
};
|
|
86
75
|
}
|
|
87
76
|
if (prop === 'derived') {
|
package/dist/root.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCallback, useRef } from 'react';
|
|
2
|
-
import { getNestedValue, getSnapshot, joinPath, notifyListeners, produce, setLeaf, useDebounce, useObject, useSubscribe } from './impl';
|
|
1
|
+
import { useCallback, useRef, useState } from 'react';
|
|
2
|
+
import { getNestedValue, getSnapshot, isEqual, joinPath, notifyListeners, produce, setLeaf, useDebounce, useObject, useSubscribe } from './impl';
|
|
3
3
|
export { createStoreRoot };
|
|
4
4
|
/**
|
|
5
5
|
* Creates the core store API with path-based methods.
|
|
@@ -34,6 +34,17 @@ function createStoreRoot(namespace, defaultValue, options = {}) {
|
|
|
34
34
|
subscribe: (path, listener) =>
|
|
35
35
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
36
36
|
useSubscribe(joinPath(namespace, path), listener),
|
|
37
|
+
useCompute: (path, fn) => {
|
|
38
|
+
const initialValue = getSnapshot(joinPath(namespace, path));
|
|
39
|
+
const [computedValue, setComputedValue] = useState(() => fn(initialValue));
|
|
40
|
+
useSubscribe(path, value => {
|
|
41
|
+
const newValue = fn(value);
|
|
42
|
+
if (!isEqual(computedValue, newValue)) {
|
|
43
|
+
setComputedValue(newValue);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return computedValue;
|
|
47
|
+
},
|
|
37
48
|
notify: (path) => {
|
|
38
49
|
const value = getNestedValue(getSnapshot(namespace), path);
|
|
39
50
|
return notifyListeners(joinPath(namespace, path), value, value, true, true);
|
package/dist/types.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ type StoreRoot<T extends FieldValues> = {
|
|
|
43
43
|
reset: <P extends FieldPath<T>>(path: P) => void;
|
|
44
44
|
/** Subscribe to changes at path and invoke listener with the new value. */
|
|
45
45
|
subscribe: <P extends FieldPath<T>>(path: P, listener: (value: FieldPathValue<T, P>) => void) => void;
|
|
46
|
+
/** Compute a derived value from the current value, similar to useState + useMemo */
|
|
47
|
+
useCompute: <P extends FieldPath<T>>(path: P, fn: (value: FieldPathValue<T, P>) => FieldPathValue<T, P>) => FieldPathValue<T, P>;
|
|
46
48
|
/** Notify listeners at path. */
|
|
47
49
|
notify: <P extends FieldPath<T>>(path: P) => void;
|
|
48
50
|
/** Convenience hook returning [value, setValue] for the path. */
|
|
@@ -71,7 +73,7 @@ type State<T> = {
|
|
|
71
73
|
/** Subscribe to changes at path and invoke listener with the new value. */
|
|
72
74
|
subscribe(listener: (value: T) => void): void;
|
|
73
75
|
/** Compute a derived value from the current value, similar to useState + useMemo */
|
|
74
|
-
|
|
76
|
+
useCompute: <R>(fn: (value: T) => R) => R;
|
|
75
77
|
/** Virtual state derived from the current value. */
|
|
76
78
|
derived: <R>({ from, to }: {
|
|
77
79
|
from: (value: T | undefined) => R;
|