@apogeelabs/beacon-react-utils 1.0.0 → 1.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/dist/index.cjs ADDED
@@ -0,0 +1,96 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let lodash = require("lodash");
30
+ lodash = __toESM(lodash);
31
+ let mobx = require("mobx");
32
+ let react = require("react");
33
+
34
+ //#region src/useStoreWatcher.ts
35
+ /**
36
+ * A custom React hook to watch for state changes in a beacon store.
37
+ *
38
+ * @template TState - The type of the store's state, extending BeaconState.
39
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
40
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
41
+ * @template T - The type returned by the selector function, inferred from the selector.
42
+ *
43
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
44
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
45
+ * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
46
+ * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
47
+ */
48
+ function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
49
+ const stableSelector = (0, react.useEffectEvent)(selector);
50
+ const stableOnChange = (0, react.useEffectEvent)(onChange);
51
+ (0, react.useEffect)(() => {
52
+ const disposer = (0, mobx.reaction)(() => {
53
+ return (0, mobx.toJS)(stableSelector(store));
54
+ }, (value, previousValue) => {
55
+ if (!previousValue || !lodash.default.isEqual(value, previousValue)) stableOnChange(value);
56
+ }, { fireImmediately });
57
+ store.registerCleanup(() => {
58
+ disposer();
59
+ });
60
+ return () => {
61
+ disposer();
62
+ };
63
+ }, [store, fireImmediately]);
64
+ }
65
+
66
+ //#endregion
67
+ //#region src/useStoreState.ts
68
+ /**
69
+ * A React hook that subscribes to a Beacon store and returns a selected value as React state.
70
+ *
71
+ * Use this hook when you need a store value to participate in React's state lifecycle —
72
+ * for example, to drive React Query parameters, to pass into hooks that don't understand
73
+ * MobX observables, or to feed non-observer child components.
74
+ *
75
+ * For normal component rendering, prefer wrapping your component with `observer` from
76
+ * `mobx-react-lite` and reading store values directly. That's simpler and more performant.
77
+ *
78
+ * @template TState - The type of the store's state, extending BeaconState.
79
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
80
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>.
81
+ * @template T - The type returned by the selector function, inferred from the selector.
82
+ *
83
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
84
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
85
+ * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
86
+ */
87
+ function useStoreState(store, selector) {
88
+ const [value, setValue] = (0, react.useState)(() => (0, mobx.toJS)(selector(store)));
89
+ useStoreWatcher(store, selector, setValue);
90
+ return value;
91
+ }
92
+
93
+ //#endregion
94
+ exports.useStoreState = useStoreState;
95
+ exports.useStoreWatcher = useStoreWatcher;
96
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["_"],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n const disposer = reaction(\n () => {\n // toJS strips MobX observable wrappers so React sees plain values\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // MobX selectors can return new object references even when the underlying\n // data hasn't changed. Deep comparison prevents spurious re-renders.\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // If the store is disposed externally, clean up the reaction too\n store.registerCleanup(() => {\n disposer();\n });\n\n return () => {\n disposer();\n };\n // stableSelector and stableOnChange are omitted from deps intentionally —\n // useEffectEvent keeps them stable across renders without needing to re-run the effect\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n","import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport { toJS } from \"mobx\";\nimport { useState } from \"react\";\nimport { useStoreWatcher } from \"./useStoreWatcher\";\n\n/**\n * A React hook that subscribes to a Beacon store and returns a selected value as React state.\n *\n * Use this hook when you need a store value to participate in React's state lifecycle —\n * for example, to drive React Query parameters, to pass into hooks that don't understand\n * MobX observables, or to feed non-observer child components.\n *\n * For normal component rendering, prefer wrapping your component with `observer` from\n * `mobx-react-lite` and reading store values directly. That's simpler and more performant.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.\n * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.\n */\nexport function useStoreState<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n): T {\n // Initializer function so the selector only runs once on mount, not on every render\n const [value, setValue] = useState<T>(() => toJS(selector(store)));\n\n // Wires MobX reactivity to React state — store changes call setValue, triggering a re-render\n useStoreWatcher(store, selector, setValue);\n\n return value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;CAGJ,MAAM,2CAAgC,SAAS;CAC/C,MAAM,2CAAgC,SAAS;AAE/C,4BAAgB;EACZ,MAAM,oCACI;AAEF,yBAAY,eAAe,MAAM,CAAC;MAErC,OAAO,kBAAkB;AAGtB,OAAI,CAAC,iBAAiB,CAACA,eAAE,QAAQ,OAAO,cAAc,CAClD,gBAAe,MAAM;KAG7B,EAAE,iBAAiB,CACtB;AAGD,QAAM,sBAAsB;AACxB,aAAU;IACZ;AAEF,eAAa;AACT,aAAU;;IAIf,CAAC,OAAO,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;ACpChC,SAAgB,cAMZ,OACA,UACC;CAED,MAAM,CAAC,OAAO,qDAAmC,SAAS,MAAM,CAAC,CAAC;AAGlE,iBAAgB,OAAO,UAAU,SAAS;AAE1C,QAAO"}
@@ -0,0 +1,42 @@
1
+ import { BeaconActions, BeaconDerived, BeaconState, Store } from "@apogeelabs/beacon";
2
+
3
+ //#region src/useStoreWatcher.d.ts
4
+ /**
5
+ * A custom React hook to watch for state changes in a beacon store.
6
+ *
7
+ * @template TState - The type of the store's state, extending BeaconState.
8
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
9
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
10
+ * @template T - The type returned by the selector function, inferred from the selector.
11
+ *
12
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
13
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
14
+ * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
15
+ * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
16
+ */
17
+ declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
18
+ //#endregion
19
+ //#region src/useStoreState.d.ts
20
+ /**
21
+ * A React hook that subscribes to a Beacon store and returns a selected value as React state.
22
+ *
23
+ * Use this hook when you need a store value to participate in React's state lifecycle —
24
+ * for example, to drive React Query parameters, to pass into hooks that don't understand
25
+ * MobX observables, or to feed non-observer child components.
26
+ *
27
+ * For normal component rendering, prefer wrapping your component with `observer` from
28
+ * `mobx-react-lite` and reading store values directly. That's simpler and more performant.
29
+ *
30
+ * @template TState - The type of the store's state, extending BeaconState.
31
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
32
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>.
33
+ * @template T - The type returned by the selector function, inferred from the selector.
34
+ *
35
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
36
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
37
+ * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
38
+ */
39
+ declare function useStoreState<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T): T;
40
+ //#endregion
41
+ export { useStoreState, useStoreWatcher };
42
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"mappings":";;;;;AAkBA;;;;;;;;;;;iBAAgB,eAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,EACxD,QAAA,GAAW,KAAA,EAAO,CAAA,WAClB,eAAA;;;;;AATJ;;;;;;;;;;;;;;;;;iBCMgB,aAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,GACzD,CAAA"}
package/dist/index.d.mts CHANGED
@@ -1,18 +1,42 @@
1
- import { BeaconState, BeaconDerived, BeaconActions, Store } from '@apogeelabs/beacon';
1
+ import { BeaconActions, BeaconDerived, BeaconState, Store } from "@apogeelabs/beacon";
2
2
 
3
+ //#region src/useStoreWatcher.d.ts
3
4
  /**
4
- * A custom React hook to watch for state changes in a beacon store.
5
- *
6
- * @template TState - The type of the store's state, extending BeaconState.
7
- * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
8
- * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
9
- * @template T - The type returned by the selector function, inferred from the selector.
10
- *
11
- * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
12
- * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
13
- * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
14
- * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
15
- */
5
+ * A custom React hook to watch for state changes in a beacon store.
6
+ *
7
+ * @template TState - The type of the store's state, extending BeaconState.
8
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
9
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
10
+ * @template T - The type returned by the selector function, inferred from the selector.
11
+ *
12
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
13
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
14
+ * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
15
+ * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
16
+ */
16
17
  declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
17
-
18
- export { useStoreWatcher };
18
+ //#endregion
19
+ //#region src/useStoreState.d.ts
20
+ /**
21
+ * A React hook that subscribes to a Beacon store and returns a selected value as React state.
22
+ *
23
+ * Use this hook when you need a store value to participate in React's state lifecycle —
24
+ * for example, to drive React Query parameters, to pass into hooks that don't understand
25
+ * MobX observables, or to feed non-observer child components.
26
+ *
27
+ * For normal component rendering, prefer wrapping your component with `observer` from
28
+ * `mobx-react-lite` and reading store values directly. That's simpler and more performant.
29
+ *
30
+ * @template TState - The type of the store's state, extending BeaconState.
31
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
32
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>.
33
+ * @template T - The type returned by the selector function, inferred from the selector.
34
+ *
35
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
36
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
37
+ * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
38
+ */
39
+ declare function useStoreState<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T): T;
40
+ //#endregion
41
+ export { useStoreState, useStoreWatcher };
42
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"mappings":";;;;;AAkBA;;;;;;;;;;;iBAAgB,eAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,EACxD,QAAA,GAAW,KAAA,EAAO,CAAA,WAClB,eAAA;;;;;AATJ;;;;;;;;;;;;;;;;;iBCMgB,aAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,GACzD,CAAA"}
package/dist/index.mjs CHANGED
@@ -1,32 +1,66 @@
1
- import _ from 'lodash';
2
- import { reaction, toJS } from 'mobx';
3
- import { useEffectEvent, useEffect } from 'react';
1
+ import _ from "lodash";
2
+ import { reaction, toJS } from "mobx";
3
+ import { useEffect, useEffectEvent, useState } from "react";
4
4
 
5
- // src/useStoreWatcher.ts
5
+ //#region src/useStoreWatcher.ts
6
+ /**
7
+ * A custom React hook to watch for state changes in a beacon store.
8
+ *
9
+ * @template TState - The type of the store's state, extending BeaconState.
10
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
11
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
12
+ * @template T - The type returned by the selector function, inferred from the selector.
13
+ *
14
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
15
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
16
+ * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
17
+ * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
18
+ */
6
19
  function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
7
- const stableSelector = useEffectEvent(selector);
8
- const stableOnChange = useEffectEvent(onChange);
9
- useEffect(() => {
10
- const disposer = reaction(
11
- () => {
12
- return toJS(stableSelector(store));
13
- },
14
- (value, previousValue) => {
15
- if (!previousValue || !_.isEqual(value, previousValue)) {
16
- stableOnChange(value);
17
- }
18
- },
19
- { fireImmediately }
20
- );
21
- store.registerCleanup(() => {
22
- disposer();
23
- });
24
- return () => {
25
- disposer();
26
- };
27
- }, [store, fireImmediately]);
20
+ const stableSelector = useEffectEvent(selector);
21
+ const stableOnChange = useEffectEvent(onChange);
22
+ useEffect(() => {
23
+ const disposer = reaction(() => {
24
+ return toJS(stableSelector(store));
25
+ }, (value, previousValue) => {
26
+ if (!previousValue || !_.isEqual(value, previousValue)) stableOnChange(value);
27
+ }, { fireImmediately });
28
+ store.registerCleanup(() => {
29
+ disposer();
30
+ });
31
+ return () => {
32
+ disposer();
33
+ };
34
+ }, [store, fireImmediately]);
28
35
  }
29
36
 
30
- export { useStoreWatcher };
31
- //# sourceMappingURL=out.js.map
37
+ //#endregion
38
+ //#region src/useStoreState.ts
39
+ /**
40
+ * A React hook that subscribes to a Beacon store and returns a selected value as React state.
41
+ *
42
+ * Use this hook when you need a store value to participate in React's state lifecycle —
43
+ * for example, to drive React Query parameters, to pass into hooks that don't understand
44
+ * MobX observables, or to feed non-observer child components.
45
+ *
46
+ * For normal component rendering, prefer wrapping your component with `observer` from
47
+ * `mobx-react-lite` and reading store values directly. That's simpler and more performant.
48
+ *
49
+ * @template TState - The type of the store's state, extending BeaconState.
50
+ * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
51
+ * @template TActions - The type of the store's actions, extending BeaconActions<TState>.
52
+ * @template T - The type returned by the selector function, inferred from the selector.
53
+ *
54
+ * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
55
+ * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
56
+ * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
57
+ */
58
+ function useStoreState(store, selector) {
59
+ const [value, setValue] = useState(() => toJS(selector(store)));
60
+ useStoreWatcher(store, selector, setValue);
61
+ return value;
62
+ }
63
+
64
+ //#endregion
65
+ export { useStoreState, useStoreWatcher };
32
66
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useStoreWatcher.ts"],"names":[],"mappings":";AACA,OAAO,OAAO;AACd,SAAS,UAAU,YAAY;AAC/B,SAAS,WAAW,sBAAsB;AAenC,SAAS,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;AAGJ,QAAM,iBAAiB,eAAe,QAAQ;AAC9C,QAAM,iBAAiB,eAAe,QAAQ;AAE9C,YAAU,MAAM;AAEZ,UAAM,WAAW;AAAA,MACb,MAAM;AAEF,eAAO,KAAK,eAAe,KAAK,CAAC;AAAA,MACrC;AAAA,MACA,CAAC,OAAO,kBAAkB;AAEtB,YAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,OAAO,aAAa,GAAG;AACpD,yBAAe,KAAK;AAAA,QACxB;AAAA,MACJ;AAAA,MACA,EAAE,gBAAgB;AAAA,IACtB;AAGA,UAAM,gBAAgB,MAAM;AACxB,eAAS;AAAA,IACb,CAAC;AAGD,WAAO,MAAM;AACT,eAAS;AAAA,IACb;AAAA,EACJ,GAAG,CAAC,OAAO,eAAe,CAAC;AAC/B","sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n // Set up a MobX reaction to watch the selected state\n const disposer = reaction(\n () => {\n // Convert to plain JS to strip MobX observable properties\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // Only trigger if the value actually changed using deep comparison\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // Register the disposer with the store for cleanup\n store.registerCleanup(() => {\n disposer();\n });\n\n // Cleanup when the component unmounts or dependencies change\n return () => {\n disposer();\n };\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n"]}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n const disposer = reaction(\n () => {\n // toJS strips MobX observable wrappers so React sees plain values\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // MobX selectors can return new object references even when the underlying\n // data hasn't changed. Deep comparison prevents spurious re-renders.\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // If the store is disposed externally, clean up the reaction too\n store.registerCleanup(() => {\n disposer();\n });\n\n return () => {\n disposer();\n };\n // stableSelector and stableOnChange are omitted from deps intentionally —\n // useEffectEvent keeps them stable across renders without needing to re-run the effect\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n","import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport { toJS } from \"mobx\";\nimport { useState } from \"react\";\nimport { useStoreWatcher } from \"./useStoreWatcher\";\n\n/**\n * A React hook that subscribes to a Beacon store and returns a selected value as React state.\n *\n * Use this hook when you need a store value to participate in React's state lifecycle —\n * for example, to drive React Query parameters, to pass into hooks that don't understand\n * MobX observables, or to feed non-observer child components.\n *\n * For normal component rendering, prefer wrapping your component with `observer` from\n * `mobx-react-lite` and reading store values directly. That's simpler and more performant.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.\n * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.\n */\nexport function useStoreState<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n): T {\n // Initializer function so the selector only runs once on mount, not on every render\n const [value, setValue] = useState<T>(() => toJS(selector(store)));\n\n // Wires MobX reactivity to React state — store changes call setValue, triggering a re-render\n useStoreWatcher(store, selector, setValue);\n\n return value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;CAGJ,MAAM,iBAAiB,eAAe,SAAS;CAC/C,MAAM,iBAAiB,eAAe,SAAS;AAE/C,iBAAgB;EACZ,MAAM,WAAW,eACP;AAEF,UAAO,KAAK,eAAe,MAAM,CAAC;MAErC,OAAO,kBAAkB;AAGtB,OAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,OAAO,cAAc,CAClD,gBAAe,MAAM;KAG7B,EAAE,iBAAiB,CACtB;AAGD,QAAM,sBAAsB;AACxB,aAAU;IACZ;AAEF,eAAa;AACT,aAAU;;IAIf,CAAC,OAAO,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;ACpChC,SAAgB,cAMZ,OACA,UACC;CAED,MAAM,CAAC,OAAO,YAAY,eAAkB,KAAK,SAAS,MAAM,CAAC,CAAC;AAGlE,iBAAgB,OAAO,UAAU,SAAS;AAE1C,QAAO"}
package/package.json CHANGED
@@ -6,20 +6,20 @@
6
6
  "name": "Jim Cowart"
7
7
  }
8
8
  ],
9
- "version": "1.0.0",
9
+ "version": "1.1.0",
10
10
  "license": "ISC",
11
- "description": "beacon middleware for react-query integration with beacon stores",
11
+ "description": "React hooks and utilities for Beacon stores",
12
12
  "engines": {
13
13
  "node": ">=18"
14
14
  },
15
- "main": "dist/index.js",
15
+ "main": "dist/index.cjs",
16
16
  "module": "dist/index.mjs",
17
- "types": "dist/index.d.ts",
17
+ "types": "dist/index.d.cts",
18
18
  "exports": {
19
19
  ".": {
20
- "require": "./dist/index.js",
20
+ "types": "./dist/index.d.mts",
21
21
  "import": "./dist/index.mjs",
22
- "types": "./dist/index.d.ts"
22
+ "require": "./dist/index.cjs"
23
23
  }
24
24
  },
25
25
  "files": [
@@ -40,7 +40,7 @@
40
40
  "lodash": "4.17.16",
41
41
  "mobx": "^6.13.7",
42
42
  "react": "^19.2.3",
43
- "@apogeelabs/beacon": "1.0.0"
43
+ "@apogeelabs/beacon": "1.1.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/jest": "^29.5.5",
@@ -53,12 +53,12 @@
53
53
  "eslint-plugin-promise": "^6.0.0",
54
54
  "jest": "^29.7.0",
55
55
  "ts-jest": "^29.1.1",
56
- "tsup": "^7.2.0",
56
+ "tsdown": "^0.20.3",
57
57
  "typescript": "^5.2.2"
58
58
  },
59
59
  "scripts": {
60
- "dev": "tsup --watch",
61
- "build": "tsup",
60
+ "dev": "tsdown --watch",
61
+ "build": "tsdown",
62
62
  "test": "jest",
63
63
  "test:watch": "jest --watch --collect-coverage",
64
64
  "lint": "eslint --config ../../.eslintrc.js 'src/**/*.{ts,tsx}'"
package/dist/index.d.ts DELETED
@@ -1,18 +0,0 @@
1
- import { BeaconState, BeaconDerived, BeaconActions, Store } from '@apogeelabs/beacon';
2
-
3
- /**
4
- * A custom React hook to watch for state changes in a beacon store.
5
- *
6
- * @template TState - The type of the store's state, extending BeaconState.
7
- * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
8
- * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
9
- * @template T - The type returned by the selector function, inferred from the selector.
10
- *
11
- * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
12
- * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
13
- * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
14
- * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
15
- */
16
- declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
17
-
18
- export { useStoreWatcher };
package/dist/index.js DELETED
@@ -1,38 +0,0 @@
1
- 'use strict';
2
-
3
- var _ = require('lodash');
4
- var mobx = require('mobx');
5
- var react = require('react');
6
-
7
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
-
9
- var ___default = /*#__PURE__*/_interopDefault(_);
10
-
11
- // src/useStoreWatcher.ts
12
- function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
13
- const stableSelector = react.useEffectEvent(selector);
14
- const stableOnChange = react.useEffectEvent(onChange);
15
- react.useEffect(() => {
16
- const disposer = mobx.reaction(
17
- () => {
18
- return mobx.toJS(stableSelector(store));
19
- },
20
- (value, previousValue) => {
21
- if (!previousValue || !___default.default.isEqual(value, previousValue)) {
22
- stableOnChange(value);
23
- }
24
- },
25
- { fireImmediately }
26
- );
27
- store.registerCleanup(() => {
28
- disposer();
29
- });
30
- return () => {
31
- disposer();
32
- };
33
- }, [store, fireImmediately]);
34
- }
35
-
36
- exports.useStoreWatcher = useStoreWatcher;
37
- //# sourceMappingURL=out.js.map
38
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/useStoreWatcher.ts"],"names":[],"mappings":";AACA,OAAO,OAAO;AACd,SAAS,UAAU,YAAY;AAC/B,SAAS,WAAW,sBAAsB;AAenC,SAAS,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;AAGJ,QAAM,iBAAiB,eAAe,QAAQ;AAC9C,QAAM,iBAAiB,eAAe,QAAQ;AAE9C,YAAU,MAAM;AAEZ,UAAM,WAAW;AAAA,MACb,MAAM;AAEF,eAAO,KAAK,eAAe,KAAK,CAAC;AAAA,MACrC;AAAA,MACA,CAAC,OAAO,kBAAkB;AAEtB,YAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,OAAO,aAAa,GAAG;AACpD,yBAAe,KAAK;AAAA,QACxB;AAAA,MACJ;AAAA,MACA,EAAE,gBAAgB;AAAA,IACtB;AAGA,UAAM,gBAAgB,MAAM;AACxB,eAAS;AAAA,IACb,CAAC;AAGD,WAAO,MAAM;AACT,eAAS;AAAA,IACb;AAAA,EACJ,GAAG,CAAC,OAAO,eAAe,CAAC;AAC/B","sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n // Set up a MobX reaction to watch the selected state\n const disposer = reaction(\n () => {\n // Convert to plain JS to strip MobX observable properties\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // Only trigger if the value actually changed using deep comparison\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // Register the disposer with the store for cleanup\n store.registerCleanup(() => {\n disposer();\n });\n\n // Cleanup when the component unmounts or dependencies change\n return () => {\n disposer();\n };\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n"]}