juststore 0.0.7 → 0.1.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 CHANGED
@@ -291,7 +291,7 @@ function TemperatureInput() {
291
291
 
292
292
  ```tsx
293
293
  function TotalPrice() {
294
- const total = store.cart.items.compute(
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 | Description |
456
- | ------------------------ | ------------------------------------------------------- |
457
- | `.use()` | Subscribe and read value (triggers re-render on change) |
458
- | `.useDebounce(ms)` | Subscribe with debounced updates |
459
- | `.useState()` | Returns `[value, setValue]` tuple |
460
- | `.value` | Read without subscribing |
461
- | `.set(value)` | Update value |
462
- | `.set(fn)` | Functional update |
463
- | `.reset()` | Delete value at path |
464
- | `.subscribe(fn)` | Subscribe to changes (for effects) |
465
- | `.notify()` | Manually trigger subscribers |
466
- | `.compute(fn)` | Derive a computed value |
467
- | `.derived({ from, to })` | Create bidirectional transform |
468
- | `.Render` | Render prop component |
469
- | `.Show` | Conditional render component |
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 === 'compute') {
71
+ if (prop === 'useCompute') {
75
72
  return (fn) => {
76
- const initialValue = from(storeApi.value(path));
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>, R>(path: P, fn: (value: FieldPathValue<T, P>) => R) => R;
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
- compute: <R>(fn: (value: T) => R) => R;
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juststore",
3
- "version": "0.0.7",
3
+ "version": "0.1.1",
4
4
  "description": "A small, expressive, and type-safe state management library for React.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",