@pitboxdev/dynamic-store-zustand 0.0.3 โ†’ 0.0.4

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
@@ -29,7 +29,7 @@
29
29
  ## โšก Features
30
30
 
31
31
  - ๐Ÿ› ๏ธ **DX First (Zero Boilerplate):** Extremely simple API without boilerplate, keeping the standard React `useState` ergonomics.
32
- - ๐Ÿงน **Auto-Cleanup:** Built-in hooks for automatic store resets on unmount.
32
+ - ๐Ÿงน **Auto-Cleanup:** Built-in config flag `resetOnUnmount` for automatic store resets on unmount.
33
33
  - โšก **High Performance:** Subscription-free hooks available (`useDynamicStoreMethods`) to read and update state without component re-renders.
34
34
  - ๐Ÿ”„ **Functional Updaters:** Handles race conditions naturally with `setData(prev => ...)`.
35
35
  - ๐Ÿ›ก๏ธ **100% Type-safe:** Written in TypeScript with pristine type inference and autocomplete out of the box.
@@ -57,7 +57,6 @@ Whether you need to generate stores dynamically on the fly or just want the simp
57
57
  - [Quick Start](#quick-start)
58
58
  - [Functional updater (`setData`)](#functional-updater-setdata)
59
59
  - [Examples](#examples)
60
- - [`useDynamicStoreWithCleanup`](#usedynamicstorewithcleanup)
61
60
  - [`useDynamicStoreMethods` (No Subscription)](#usedynamicstoremethods-no-subscription)
62
61
  - [Imperative helpers (outside React)](#imperative-helpers-outside-react)
63
62
  - [Config options](#config-options)
@@ -76,7 +75,7 @@ Whether you need to generate stores dynamically on the fly or just want the simp
76
75
  |---|---|
77
76
  | **Dynamic initialization** | Stores are initialized just-in-time when the hook mounts |
78
77
  | **useState-like API** | `setData(obj)` or `setData((prev) => update)` |
79
- | **Auto-cleanup** | `useDynamicStoreWithCleanup` resets state on unmount |
78
+ | **Auto-cleanup** | `resetOnUnmount: true` resets state on unmount |
80
79
  | **Navigation reset** | Non-persistent stores reset via imperative API on route changes |
81
80
  | **Imperative helpers** | Modify and reset stores outside React components |
82
81
 
@@ -113,7 +112,7 @@ interface CounterState {
113
112
  const initial: CounterState = { value: 0, step: 1 };
114
113
 
115
114
  function Counter() {
116
- const { data, setData, reset } = useDynamicStore<CounterState>("counter", {
115
+ const { data, setData, reset, getData } = useDynamicStore<CounterState>("counter", {
117
116
  initialState: initial,
118
117
  });
119
118
 
@@ -239,25 +238,6 @@ function Cart() {
239
238
 
240
239
  ---
241
240
 
242
- ## `useDynamicStoreWithCleanup`
243
-
244
- `useDynamicStoreWithCleanup` works identically to `useDynamicStore` but resets the store when the component unmounts โ€” useful for modal dialogs, wizard steps, or edit forms.
245
-
246
- ```tsx
247
- import { useDynamicStoreWithCleanup } from "@pitboxdev/dynamic-store-zustand";
248
-
249
- function EditModal() {
250
- const { data, setData } = useDynamicStoreWithCleanup<FormState>(
251
- "editForm",
252
- { initialState: { name: "", email: "" }, resetOnUnmount: true }
253
- );
254
-
255
- // State is automatically reset when the modal closes
256
- }
257
- ```
258
-
259
- ---
260
-
261
241
  ## `useDynamicStoreMethods` (No Subscription)
262
242
 
263
243
  If you need to update or read the store **without subscribing to its changes** (to avoid component re-renders), you can use `useDynamicStoreMethods`:
@@ -267,7 +247,7 @@ import { useDynamicStoreMethods } from "@pitboxdev/dynamic-store-zustand";
267
247
 
268
248
  function Controls() {
269
249
  // This component will NOT re-render when 'counter' state changes!
270
- const { setData, reset, get } = useDynamicStoreMethods<CounterState>("counter");
250
+ const { setData, reset, getData } = useDynamicStoreMethods<CounterState>("counter");
271
251
 
272
252
  const increment = () => {
273
253
  // Both forms work just like in the regular hook:
@@ -275,7 +255,7 @@ function Controls() {
275
255
  };
276
256
 
277
257
  const logCurrent = () => {
278
- console.log("Current state:", get()); // Get current state without subscribing
258
+ console.log("Current state:", getData()); // Get current state without subscribing
279
259
  };
280
260
 
281
261
  return (
@@ -379,19 +359,13 @@ function RegistrationForm() {
379
359
  | `storeId` | `string` | Unique key identifying this store in the registry |
380
360
  | `config` | `StoreConfig<T>` | Optional config (see [Config options](#config-options)) |
381
361
 
382
- Returns `{ data: T, setData, reset }`.
383
-
384
- ---
385
-
386
- ### `useDynamicStoreWithCleanup<T>(storeId, config?)`
387
-
388
- Same signature as `useDynamicStore`. Calls `reset()` on component unmount when `config.resetOnUnmount` is `true`.
362
+ Returns `{ data: T, setData, reset, getData }`.
389
363
 
390
364
  ---
391
365
 
392
366
  ### `useDynamicStoreMethods<T>(storeId, config?)`
393
367
 
394
- Returns `{ setData, reset, get }` bound to the store, without subscribing the component to state changes.
368
+ Returns `{ setData, reset, getData }` bound to the store, without subscribing the component to state changes.
395
369
 
396
370
  ---
397
371
 
package/dist/index.d.mts CHANGED
@@ -32,12 +32,13 @@ type StoreState = Record<string, unknown>;
32
32
  interface UseDynamicStoreMethodsReturn<T extends StoreState> {
33
33
  setData: (updater: SetStateAction<T>) => void;
34
34
  reset: () => void;
35
- get: () => T;
35
+ getData: () => T;
36
36
  }
37
37
  interface UseDynamicStoreReturn<T extends StoreState> {
38
38
  data: T;
39
39
  setData: (updater: SetStateAction<T>) => void;
40
40
  reset: () => void;
41
+ getData: () => T;
41
42
  }
42
43
  /**
43
44
  * Hook that returns store methods (setData, reset, get) WITHOUT subscribing
@@ -66,19 +67,6 @@ declare function useDynamicStoreMethods<T extends StoreState>(storeId: string, c
66
67
  * ```
67
68
  */
68
69
  declare function useDynamicStore<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
69
- /**
70
- * Same as `useDynamicStore` but automatically resets state when the
71
- * component unmounts (when `config.resetOnUnmount` is `true`).
72
- *
73
- * @example
74
- * ```tsx
75
- * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(
76
- * 'editForm',
77
- * { initialState, resetOnUnmount: true },
78
- * );
79
- * ```
80
- */
81
- declare function useDynamicStoreWithCleanup<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
82
70
  /**
83
71
  * Update a dynamic store from outside a React component.
84
72
  */
@@ -101,4 +89,4 @@ declare const resetAllDynamicStores: () => void;
101
89
  */
102
90
  declare const resetNonPersistentDynamicStores: () => void;
103
91
 
104
- export { type DynamicStoreRegistry, type SetStateAction, type StoreConfig, type UseDynamicStoreMethodsReturn, type UseDynamicStoreReturn, getDynamicStoreData, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, useDynamicStoreMethods, useDynamicStoreWithCleanup };
92
+ export { type DynamicStoreRegistry, type SetStateAction, type StoreConfig, type UseDynamicStoreMethodsReturn, type UseDynamicStoreReturn, getDynamicStoreData, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, useDynamicStoreMethods };
package/dist/index.d.ts CHANGED
@@ -32,12 +32,13 @@ type StoreState = Record<string, unknown>;
32
32
  interface UseDynamicStoreMethodsReturn<T extends StoreState> {
33
33
  setData: (updater: SetStateAction<T>) => void;
34
34
  reset: () => void;
35
- get: () => T;
35
+ getData: () => T;
36
36
  }
37
37
  interface UseDynamicStoreReturn<T extends StoreState> {
38
38
  data: T;
39
39
  setData: (updater: SetStateAction<T>) => void;
40
40
  reset: () => void;
41
+ getData: () => T;
41
42
  }
42
43
  /**
43
44
  * Hook that returns store methods (setData, reset, get) WITHOUT subscribing
@@ -66,19 +67,6 @@ declare function useDynamicStoreMethods<T extends StoreState>(storeId: string, c
66
67
  * ```
67
68
  */
68
69
  declare function useDynamicStore<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
69
- /**
70
- * Same as `useDynamicStore` but automatically resets state when the
71
- * component unmounts (when `config.resetOnUnmount` is `true`).
72
- *
73
- * @example
74
- * ```tsx
75
- * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(
76
- * 'editForm',
77
- * { initialState, resetOnUnmount: true },
78
- * );
79
- * ```
80
- */
81
- declare function useDynamicStoreWithCleanup<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
82
70
  /**
83
71
  * Update a dynamic store from outside a React component.
84
72
  */
@@ -101,4 +89,4 @@ declare const resetAllDynamicStores: () => void;
101
89
  */
102
90
  declare const resetNonPersistentDynamicStores: () => void;
103
91
 
104
- export { type DynamicStoreRegistry, type SetStateAction, type StoreConfig, type UseDynamicStoreMethodsReturn, type UseDynamicStoreReturn, getDynamicStoreData, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, useDynamicStoreMethods, useDynamicStoreWithCleanup };
92
+ export { type DynamicStoreRegistry, type SetStateAction, type StoreConfig, type UseDynamicStoreMethodsReturn, type UseDynamicStoreReturn, getDynamicStoreData, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, useDynamicStoreMethods };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var zustand=require('zustand'),middleware=require('zustand/middleware'),react=require('react');var a=zustand.create()(middleware.devtools(e=>({stores:{},setStoreData:(t,r,o)=>{e(s=>{let i=s.stores[t],n={data:{...i?.data??o?.initialState??{},...r},config:o??i?.config??{},initialState:o?.initialState??i?.initialState??{}};return {stores:{...s.stores,[t]:n}}});},resetStore:t=>{e(r=>{let o=r.stores[t];return o?{stores:{...r.stores,[t]:{...o,data:{...o.initialState}}}}:r});},resetAllStores:()=>{e(t=>{let r={};for(let[o,s]of Object.entries(t.stores))r[o]={...s,data:{...s.initialState}};return {stores:r}});},resetNonPersistentStores:()=>{e(t=>{let r={};for(let[o,s]of Object.entries(t.stores))r[o]=s.config.persistOnNavigation===true?s:{...s,data:{...s.initialState}};return {stores:r}});}}),{name:"DynamicStoresManager"}));function c(e,t){let r=a(n=>n.setStoreData),o=a(n=>n.resetStore),s=()=>a.getState().stores[e]?.data??t?.initialState??{};return {setData:n=>{if(typeof n=="function"){let D=n(s());r(e,D,t);}else r(e,n,t);},reset:()=>{o(e);},get:s}}function d(e,t){let r=a(i=>i.stores[e]),o=c(e,t);return react.useEffect(()=>{!r&&t?.initialState!==void 0&&a.getState().setStoreData(e,{},t);},[e]),{data:r?.data??t?.initialState??{},setData:o.setData,reset:o.reset}}function g(e,t){let{data:r,setData:o,reset:s}=d(e,t);return react.useEffect(()=>()=>{t?.resetOnUnmount===true&&s();},[e,t?.resetOnUnmount]),{data:r,setData:o,reset:s}}var f=(e,t)=>{a.getState().setStoreData(e,t);},p=e=>a.getState().stores[e]?.data,l=e=>{a.getState().resetStore(e);},T=()=>{a.getState().resetAllStores();},x=()=>{a.getState().resetNonPersistentStores();};exports.getDynamicStoreData=p;exports.resetAllDynamicStores=T;exports.resetDynamicStore=l;exports.resetNonPersistentDynamicStores=x;exports.updateDynamicStore=f;exports.useDynamicStore=d;exports.useDynamicStoreMethods=c;exports.useDynamicStoreWithCleanup=g;//# sourceMappingURL=index.js.map
1
+ 'use strict';var zustand=require('zustand'),middleware=require('zustand/middleware'),react=require('react');var n=zustand.create()(middleware.devtools(e=>({stores:{},setStoreData:(t,o,r)=>{e(s=>{let i=s.stores[t],a={data:{...i?.data??r?.initialState??{},...o},config:r??i?.config??{},initialState:r?.initialState??i?.initialState??{}};return {stores:{...s.stores,[t]:a}}});},resetStore:t=>{e(o=>{let r=o.stores[t];return r?{stores:{...o.stores,[t]:{...r,data:{...r.initialState}}}}:o});},resetAllStores:()=>{e(t=>{let o={};for(let[r,s]of Object.entries(t.stores))o[r]={...s,data:{...s.initialState}};return {stores:o}});},resetNonPersistentStores:()=>{e(t=>{let o={};for(let[r,s]of Object.entries(t.stores))o[r]=s.config.persistOnNavigation===true?s:{...s,data:{...s.initialState}};return {stores:o}});}}),{name:"DynamicStoresManager"}));function c(e,t){let o=n(a=>a.setStoreData),r=n(a=>a.resetStore),s=()=>n.getState().stores[e]?.data??t?.initialState??{};return {setData:a=>{if(typeof a=="function"){let d=a(s());o(e,d,t);}else o(e,a,t);},reset:()=>{r(e);},getData:s}}function g(e,t){let o=n(i=>i.stores[e]),r=c(e,t);return react.useEffect(()=>{!o&&t?.initialState!==void 0&&n.getState().setStoreData(e,{},t);},[e]),react.useEffect(()=>()=>{t?.resetOnUnmount===true&&r.reset();},[e,t?.resetOnUnmount]),{data:o?.data??t?.initialState??{},setData:r.setData,reset:r.reset,getData:r.getData}}var u=(e,t)=>{n.getState().setStoreData(e,t);},f=e=>n.getState().stores[e]?.data,p=e=>{n.getState().resetStore(e);},l=()=>{n.getState().resetAllStores();},T=()=>{n.getState().resetNonPersistentStores();};exports.getDynamicStoreData=f;exports.resetAllDynamicStores=l;exports.resetDynamicStore=p;exports.resetNonPersistentDynamicStores=T;exports.updateDynamicStore=u;exports.useDynamicStore=g;exports.useDynamicStoreMethods=c;//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dynamicStore.ts"],"names":["useDynamicStoresManager","create","devtools","set","storeId","data","config","state","existingStore","entry","store","next","id","useDynamicStoreMethods","setStoreData","resetStore","get","updater","updates","useDynamicStore","storeRegistry","methods","useEffect","useDynamicStoreWithCleanup","setData","reset","updateDynamicStore","getDynamicStoreData","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"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","file":"index.js","sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useEffect } from \"react\";\nimport type {\n SetStateAction,\n StoreConfig,\n DynamicStoreRegistry,\n StoreState,\n} from \"./types\";\n\n// โ”€โ”€โ”€ Internal manager state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\ninterface DynamicStoresState {\n stores: Record<string, DynamicStoreRegistry>;\n setStoreData: (\n storeId: string,\n data: StoreState,\n config?: StoreConfig,\n ) => void;\n resetStore: (storeId: string) => void;\n resetAllStores: () => void;\n resetNonPersistentStores: () => void;\n}\n\nconst useDynamicStoresManager = create<DynamicStoresState>()(\n devtools(\n (set) => ({\n stores: {},\n\n setStoreData: (storeId, data, config) => {\n set((state) => {\n const existingStore = state.stores[storeId];\n const currentData: StoreState =\n existingStore?.data ?? config?.initialState ?? {};\n\n const entry: DynamicStoreRegistry = {\n data: { ...currentData, ...data },\n config: config ?? existingStore?.config ?? {},\n initialState:\n config?.initialState ?? existingStore?.initialState ?? {},\n };\n\n return {\n stores: { ...state.stores, [storeId]: entry },\n };\n });\n },\n\n resetStore: (storeId) => {\n set((state) => {\n const store = state.stores[storeId];\n if (!store) return state;\n\n return {\n stores: {\n ...state.stores,\n [storeId]: { ...store, data: { ...store.initialState } },\n },\n };\n });\n },\n\n resetAllStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] = { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n\n resetNonPersistentStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] =\n store.config.persistOnNavigation === true\n ? store\n : { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n }),\n { name: \"DynamicStoresManager\" },\n ),\n);\n\n// โ”€โ”€โ”€ Return types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nexport interface UseDynamicStoreMethodsReturn<T extends StoreState> {\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n get: () => T;\n}\n\nexport interface UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n}\n\n// โ”€โ”€โ”€ useDynamicStoreMethods โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook that returns store methods (setData, reset, get) WITHOUT subscribing\n * to state changes. Useful when you only need to update or read the store\n * imperatively without causing component re-renders.\n */\nexport function useDynamicStoreMethods<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreMethodsReturn<T> {\n const setStoreData = useDynamicStoresManager((state) => state.setStoreData);\n const resetStore = useDynamicStoresManager((state) => state.resetStore);\n\n const get = (): T => {\n const storeRegistry = useDynamicStoresManager.getState().stores[storeId];\n return (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n };\n\n const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const updates = updater(get());\n setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n resetStore(storeId);\n };\n\n return { setData, reset, get };\n}\n\n// โ”€โ”€โ”€ useDynamicStore โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook-based dynamic store keyed by `storeId`.\n *\n * `setData` accepts either a partial object **or** a function that receives\n * the previous state and returns a partial object โ€” exactly like React's\n * `useState` setter.\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStore<CounterState>('counter', {\n * initialState: { value: 0, step: 1 },\n * });\n *\n * // object update\n * setData({ value: 42 });\n *\n * // functional update โ€” safe for rapid successive calls\n * setData((prev) => ({ value: prev.value + prev.step }));\n * ```\n */\nexport function useDynamicStore<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const storeRegistry = useDynamicStoresManager((state) => state.stores[storeId]);\n const methods = useDynamicStoreMethods<T>(storeId, config);\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n useDynamicStoresManager.getState().setStoreData(\n storeId,\n {},\n config as StoreConfig,\n );\n }\n // Only run on mount / storeId change โ€” intentional dep list\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId]);\n\n const data = (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n\n return { data, setData: methods.setData, reset: methods.reset };\n}\n\n// โ”€โ”€โ”€ useDynamicStoreWithCleanup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Same as `useDynamicStore` but automatically resets state when the\n * component unmounts (when `config.resetOnUnmount` is `true`).\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(\n * 'editForm',\n * { initialState, resetOnUnmount: true },\n * );\n * ```\n */\nexport function useDynamicStoreWithCleanup<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const { data, setData, reset } = useDynamicStore<T>(storeId, config);\n\n useEffect(() => {\n return () => {\n if (config?.resetOnUnmount === true) {\n reset();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId, config?.resetOnUnmount]);\n\n return { data, setData, reset };\n}\n\n// โ”€โ”€โ”€ Imperative helpers (outside React) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Update a dynamic store from outside a React component.\n */\nexport const updateDynamicStore = (\n storeId: string,\n data: StoreState,\n): void => {\n useDynamicStoresManager.getState().setStoreData(storeId, data);\n};\n\n/**\n * Retrieve the current state of a dynamic store from outside a React component.\n * Fallbacks to empty object if store does not exist.\n */\nexport const getDynamicStoreData = <T extends StoreState = StoreState>(\n storeId: string,\n): T | undefined => {\n return useDynamicStoresManager.getState().stores[storeId]?.data as T | undefined;\n};\n\n/**\n * Reset a single dynamic store to its initial state from outside React.\n */\nexport const resetDynamicStore = (storeId: string): void => {\n useDynamicStoresManager.getState().resetStore(storeId);\n};\n\n/**\n * Reset all dynamic stores to their initial states from outside React.\n */\nexport const resetAllDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetAllStores();\n};\n\n/**\n * Reset only stores that do not have `persistOnNavigation: true`.\n */\nexport const resetNonPersistentDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetNonPersistentStores();\n};\n"]}
1
+ {"version":3,"sources":["../src/dynamicStore.ts"],"names":["useDynamicStoresManager","create","devtools","set","storeId","data","config","state","existingStore","entry","store","next","id","useDynamicStoreMethods","setStoreData","resetStore","getData","updater","updates","useDynamicStore","storeRegistry","methods","useEffect","updateDynamicStore","getDynamicStoreData","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"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","file":"index.js","sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useEffect } from \"react\";\nimport type {\n SetStateAction,\n StoreConfig,\n DynamicStoreRegistry,\n StoreState,\n} from \"./types\";\n\n// โ”€โ”€โ”€ Internal manager state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\ninterface DynamicStoresState {\n stores: Record<string, DynamicStoreRegistry>;\n setStoreData: (\n storeId: string,\n data: StoreState,\n config?: StoreConfig,\n ) => void;\n resetStore: (storeId: string) => void;\n resetAllStores: () => void;\n resetNonPersistentStores: () => void;\n}\n\nconst useDynamicStoresManager = create<DynamicStoresState>()(\n devtools(\n (set) => ({\n stores: {},\n\n setStoreData: (storeId, data, config) => {\n set((state) => {\n const existingStore = state.stores[storeId];\n const currentData: StoreState =\n existingStore?.data ?? config?.initialState ?? {};\n\n const entry: DynamicStoreRegistry = {\n data: { ...currentData, ...data },\n config: config ?? existingStore?.config ?? {},\n initialState:\n config?.initialState ?? existingStore?.initialState ?? {},\n };\n\n return {\n stores: { ...state.stores, [storeId]: entry },\n };\n });\n },\n\n resetStore: (storeId) => {\n set((state) => {\n const store = state.stores[storeId];\n if (!store) return state;\n\n return {\n stores: {\n ...state.stores,\n [storeId]: { ...store, data: { ...store.initialState } },\n },\n };\n });\n },\n\n resetAllStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] = { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n\n resetNonPersistentStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] =\n store.config.persistOnNavigation === true\n ? store\n : { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n }),\n { name: \"DynamicStoresManager\" },\n ),\n);\n\n// โ”€โ”€โ”€ Return types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nexport interface UseDynamicStoreMethodsReturn<T extends StoreState> {\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n getData: () => T;\n}\n\nexport interface UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n getData: () => T;\n}\n\n// โ”€โ”€โ”€ useDynamicStoreMethods โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook that returns store methods (setData, reset, get) WITHOUT subscribing\n * to state changes. Useful when you only need to update or read the store\n * imperatively without causing component re-renders.\n */\nexport function useDynamicStoreMethods<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreMethodsReturn<T> {\n const setStoreData = useDynamicStoresManager((state) => state.setStoreData);\n const resetStore = useDynamicStoresManager((state) => state.resetStore);\n\n const getData = (): T => {\n const storeRegistry = useDynamicStoresManager.getState().stores[storeId];\n return (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n };\n\n const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const updates = updater(getData());\n setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n resetStore(storeId);\n };\n\n return { setData, reset, getData };\n}\n\n// โ”€โ”€โ”€ useDynamicStore โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook-based dynamic store keyed by `storeId`.\n *\n * `setData` accepts either a partial object **or** a function that receives\n * the previous state and returns a partial object โ€” exactly like React's\n * `useState` setter.\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStore<CounterState>('counter', {\n * initialState: { value: 0, step: 1 },\n * });\n *\n * // object update\n * setData({ value: 42 });\n *\n * // functional update โ€” safe for rapid successive calls\n * setData((prev) => ({ value: prev.value + prev.step }));\n * ```\n */\nexport function useDynamicStore<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const storeRegistry = useDynamicStoresManager((state) => state.stores[storeId]);\n const methods = useDynamicStoreMethods<T>(storeId, config);\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n useDynamicStoresManager.getState().setStoreData(\n storeId,\n {},\n config as StoreConfig,\n );\n }\n // Only run on mount / storeId change โ€” intentional dep list\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId]);\n\n // Handle auto-cleanup on unmount if requested\n useEffect(() => {\n return () => {\n if (config?.resetOnUnmount === true) {\n methods.reset();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId, config?.resetOnUnmount]);\n\n const data = (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n\n return {\n data,\n setData: methods.setData,\n reset: methods.reset,\n getData: methods.getData,\n };\n}\n\n// โ”€โ”€โ”€ Imperative helpers (outside React) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Update a dynamic store from outside a React component.\n */\nexport const updateDynamicStore = (\n storeId: string,\n data: StoreState,\n): void => {\n useDynamicStoresManager.getState().setStoreData(storeId, data);\n};\n\n/**\n * Retrieve the current state of a dynamic store from outside a React component.\n * Fallbacks to empty object if store does not exist.\n */\nexport const getDynamicStoreData = <T extends StoreState = StoreState>(\n storeId: string,\n): T | undefined => {\n return useDynamicStoresManager.getState().stores[storeId]?.data as T | undefined;\n};\n\n/**\n * Reset a single dynamic store to its initial state from outside React.\n */\nexport const resetDynamicStore = (storeId: string): void => {\n useDynamicStoresManager.getState().resetStore(storeId);\n};\n\n/**\n * Reset all dynamic stores to their initial states from outside React.\n */\nexport const resetAllDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetAllStores();\n};\n\n/**\n * Reset only stores that do not have `persistOnNavigation: true`.\n */\nexport const resetNonPersistentDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetNonPersistentStores();\n};\n"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import {create}from'zustand';import {devtools}from'zustand/middleware';import {useEffect}from'react';var a=create()(devtools(e=>({stores:{},setStoreData:(t,r,o)=>{e(s=>{let i=s.stores[t],n={data:{...i?.data??o?.initialState??{},...r},config:o??i?.config??{},initialState:o?.initialState??i?.initialState??{}};return {stores:{...s.stores,[t]:n}}});},resetStore:t=>{e(r=>{let o=r.stores[t];return o?{stores:{...r.stores,[t]:{...o,data:{...o.initialState}}}}:r});},resetAllStores:()=>{e(t=>{let r={};for(let[o,s]of Object.entries(t.stores))r[o]={...s,data:{...s.initialState}};return {stores:r}});},resetNonPersistentStores:()=>{e(t=>{let r={};for(let[o,s]of Object.entries(t.stores))r[o]=s.config.persistOnNavigation===true?s:{...s,data:{...s.initialState}};return {stores:r}});}}),{name:"DynamicStoresManager"}));function c(e,t){let r=a(n=>n.setStoreData),o=a(n=>n.resetStore),s=()=>a.getState().stores[e]?.data??t?.initialState??{};return {setData:n=>{if(typeof n=="function"){let D=n(s());r(e,D,t);}else r(e,n,t);},reset:()=>{o(e);},get:s}}function d(e,t){let r=a(i=>i.stores[e]),o=c(e,t);return useEffect(()=>{!r&&t?.initialState!==void 0&&a.getState().setStoreData(e,{},t);},[e]),{data:r?.data??t?.initialState??{},setData:o.setData,reset:o.reset}}function g(e,t){let{data:r,setData:o,reset:s}=d(e,t);return useEffect(()=>()=>{t?.resetOnUnmount===true&&s();},[e,t?.resetOnUnmount]),{data:r,setData:o,reset:s}}var f=(e,t)=>{a.getState().setStoreData(e,t);},p=e=>a.getState().stores[e]?.data,l=e=>{a.getState().resetStore(e);},T=()=>{a.getState().resetAllStores();},x=()=>{a.getState().resetNonPersistentStores();};export{p as getDynamicStoreData,T as resetAllDynamicStores,l as resetDynamicStore,x as resetNonPersistentDynamicStores,f as updateDynamicStore,d as useDynamicStore,c as useDynamicStoreMethods,g as useDynamicStoreWithCleanup};//# sourceMappingURL=index.mjs.map
1
+ import {create}from'zustand';import {devtools}from'zustand/middleware';import {useEffect}from'react';var n=create()(devtools(e=>({stores:{},setStoreData:(t,o,r)=>{e(s=>{let i=s.stores[t],a={data:{...i?.data??r?.initialState??{},...o},config:r??i?.config??{},initialState:r?.initialState??i?.initialState??{}};return {stores:{...s.stores,[t]:a}}});},resetStore:t=>{e(o=>{let r=o.stores[t];return r?{stores:{...o.stores,[t]:{...r,data:{...r.initialState}}}}:o});},resetAllStores:()=>{e(t=>{let o={};for(let[r,s]of Object.entries(t.stores))o[r]={...s,data:{...s.initialState}};return {stores:o}});},resetNonPersistentStores:()=>{e(t=>{let o={};for(let[r,s]of Object.entries(t.stores))o[r]=s.config.persistOnNavigation===true?s:{...s,data:{...s.initialState}};return {stores:o}});}}),{name:"DynamicStoresManager"}));function c(e,t){let o=n(a=>a.setStoreData),r=n(a=>a.resetStore),s=()=>n.getState().stores[e]?.data??t?.initialState??{};return {setData:a=>{if(typeof a=="function"){let d=a(s());o(e,d,t);}else o(e,a,t);},reset:()=>{r(e);},getData:s}}function g(e,t){let o=n(i=>i.stores[e]),r=c(e,t);return useEffect(()=>{!o&&t?.initialState!==void 0&&n.getState().setStoreData(e,{},t);},[e]),useEffect(()=>()=>{t?.resetOnUnmount===true&&r.reset();},[e,t?.resetOnUnmount]),{data:o?.data??t?.initialState??{},setData:r.setData,reset:r.reset,getData:r.getData}}var u=(e,t)=>{n.getState().setStoreData(e,t);},f=e=>n.getState().stores[e]?.data,p=e=>{n.getState().resetStore(e);},l=()=>{n.getState().resetAllStores();},T=()=>{n.getState().resetNonPersistentStores();};export{f as getDynamicStoreData,l as resetAllDynamicStores,p as resetDynamicStore,T as resetNonPersistentDynamicStores,u as updateDynamicStore,g as useDynamicStore,c as useDynamicStoreMethods};//# sourceMappingURL=index.mjs.map
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dynamicStore.ts"],"names":["useDynamicStoresManager","create","devtools","set","storeId","data","config","state","existingStore","entry","store","next","id","useDynamicStoreMethods","setStoreData","resetStore","get","updater","updates","useDynamicStore","storeRegistry","methods","useEffect","useDynamicStoreWithCleanup","setData","reset","updateDynamicStore","getDynamicStoreData","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"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","file":"index.mjs","sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useEffect } from \"react\";\nimport type {\n SetStateAction,\n StoreConfig,\n DynamicStoreRegistry,\n StoreState,\n} from \"./types\";\n\n// โ”€โ”€โ”€ Internal manager state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\ninterface DynamicStoresState {\n stores: Record<string, DynamicStoreRegistry>;\n setStoreData: (\n storeId: string,\n data: StoreState,\n config?: StoreConfig,\n ) => void;\n resetStore: (storeId: string) => void;\n resetAllStores: () => void;\n resetNonPersistentStores: () => void;\n}\n\nconst useDynamicStoresManager = create<DynamicStoresState>()(\n devtools(\n (set) => ({\n stores: {},\n\n setStoreData: (storeId, data, config) => {\n set((state) => {\n const existingStore = state.stores[storeId];\n const currentData: StoreState =\n existingStore?.data ?? config?.initialState ?? {};\n\n const entry: DynamicStoreRegistry = {\n data: { ...currentData, ...data },\n config: config ?? existingStore?.config ?? {},\n initialState:\n config?.initialState ?? existingStore?.initialState ?? {},\n };\n\n return {\n stores: { ...state.stores, [storeId]: entry },\n };\n });\n },\n\n resetStore: (storeId) => {\n set((state) => {\n const store = state.stores[storeId];\n if (!store) return state;\n\n return {\n stores: {\n ...state.stores,\n [storeId]: { ...store, data: { ...store.initialState } },\n },\n };\n });\n },\n\n resetAllStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] = { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n\n resetNonPersistentStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] =\n store.config.persistOnNavigation === true\n ? store\n : { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n }),\n { name: \"DynamicStoresManager\" },\n ),\n);\n\n// โ”€โ”€โ”€ Return types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nexport interface UseDynamicStoreMethodsReturn<T extends StoreState> {\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n get: () => T;\n}\n\nexport interface UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n}\n\n// โ”€โ”€โ”€ useDynamicStoreMethods โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook that returns store methods (setData, reset, get) WITHOUT subscribing\n * to state changes. Useful when you only need to update or read the store\n * imperatively without causing component re-renders.\n */\nexport function useDynamicStoreMethods<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreMethodsReturn<T> {\n const setStoreData = useDynamicStoresManager((state) => state.setStoreData);\n const resetStore = useDynamicStoresManager((state) => state.resetStore);\n\n const get = (): T => {\n const storeRegistry = useDynamicStoresManager.getState().stores[storeId];\n return (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n };\n\n const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const updates = updater(get());\n setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n resetStore(storeId);\n };\n\n return { setData, reset, get };\n}\n\n// โ”€โ”€โ”€ useDynamicStore โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook-based dynamic store keyed by `storeId`.\n *\n * `setData` accepts either a partial object **or** a function that receives\n * the previous state and returns a partial object โ€” exactly like React's\n * `useState` setter.\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStore<CounterState>('counter', {\n * initialState: { value: 0, step: 1 },\n * });\n *\n * // object update\n * setData({ value: 42 });\n *\n * // functional update โ€” safe for rapid successive calls\n * setData((prev) => ({ value: prev.value + prev.step }));\n * ```\n */\nexport function useDynamicStore<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const storeRegistry = useDynamicStoresManager((state) => state.stores[storeId]);\n const methods = useDynamicStoreMethods<T>(storeId, config);\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n useDynamicStoresManager.getState().setStoreData(\n storeId,\n {},\n config as StoreConfig,\n );\n }\n // Only run on mount / storeId change โ€” intentional dep list\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId]);\n\n const data = (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n\n return { data, setData: methods.setData, reset: methods.reset };\n}\n\n// โ”€โ”€โ”€ useDynamicStoreWithCleanup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Same as `useDynamicStore` but automatically resets state when the\n * component unmounts (when `config.resetOnUnmount` is `true`).\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(\n * 'editForm',\n * { initialState, resetOnUnmount: true },\n * );\n * ```\n */\nexport function useDynamicStoreWithCleanup<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const { data, setData, reset } = useDynamicStore<T>(storeId, config);\n\n useEffect(() => {\n return () => {\n if (config?.resetOnUnmount === true) {\n reset();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId, config?.resetOnUnmount]);\n\n return { data, setData, reset };\n}\n\n// โ”€โ”€โ”€ Imperative helpers (outside React) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Update a dynamic store from outside a React component.\n */\nexport const updateDynamicStore = (\n storeId: string,\n data: StoreState,\n): void => {\n useDynamicStoresManager.getState().setStoreData(storeId, data);\n};\n\n/**\n * Retrieve the current state of a dynamic store from outside a React component.\n * Fallbacks to empty object if store does not exist.\n */\nexport const getDynamicStoreData = <T extends StoreState = StoreState>(\n storeId: string,\n): T | undefined => {\n return useDynamicStoresManager.getState().stores[storeId]?.data as T | undefined;\n};\n\n/**\n * Reset a single dynamic store to its initial state from outside React.\n */\nexport const resetDynamicStore = (storeId: string): void => {\n useDynamicStoresManager.getState().resetStore(storeId);\n};\n\n/**\n * Reset all dynamic stores to their initial states from outside React.\n */\nexport const resetAllDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetAllStores();\n};\n\n/**\n * Reset only stores that do not have `persistOnNavigation: true`.\n */\nexport const resetNonPersistentDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetNonPersistentStores();\n};\n"]}
1
+ {"version":3,"sources":["../src/dynamicStore.ts"],"names":["useDynamicStoresManager","create","devtools","set","storeId","data","config","state","existingStore","entry","store","next","id","useDynamicStoreMethods","setStoreData","resetStore","getData","updater","updates","useDynamicStore","storeRegistry","methods","useEffect","updateDynamicStore","getDynamicStoreData","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"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","file":"index.mjs","sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useEffect } from \"react\";\nimport type {\n SetStateAction,\n StoreConfig,\n DynamicStoreRegistry,\n StoreState,\n} from \"./types\";\n\n// โ”€โ”€โ”€ Internal manager state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\ninterface DynamicStoresState {\n stores: Record<string, DynamicStoreRegistry>;\n setStoreData: (\n storeId: string,\n data: StoreState,\n config?: StoreConfig,\n ) => void;\n resetStore: (storeId: string) => void;\n resetAllStores: () => void;\n resetNonPersistentStores: () => void;\n}\n\nconst useDynamicStoresManager = create<DynamicStoresState>()(\n devtools(\n (set) => ({\n stores: {},\n\n setStoreData: (storeId, data, config) => {\n set((state) => {\n const existingStore = state.stores[storeId];\n const currentData: StoreState =\n existingStore?.data ?? config?.initialState ?? {};\n\n const entry: DynamicStoreRegistry = {\n data: { ...currentData, ...data },\n config: config ?? existingStore?.config ?? {},\n initialState:\n config?.initialState ?? existingStore?.initialState ?? {},\n };\n\n return {\n stores: { ...state.stores, [storeId]: entry },\n };\n });\n },\n\n resetStore: (storeId) => {\n set((state) => {\n const store = state.stores[storeId];\n if (!store) return state;\n\n return {\n stores: {\n ...state.stores,\n [storeId]: { ...store, data: { ...store.initialState } },\n },\n };\n });\n },\n\n resetAllStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] = { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n\n resetNonPersistentStores: () => {\n set((state) => {\n const next: Record<string, DynamicStoreRegistry> = {};\n\n for (const [id, store] of Object.entries(state.stores)) {\n next[id] =\n store.config.persistOnNavigation === true\n ? store\n : { ...store, data: { ...store.initialState } };\n }\n\n return { stores: next };\n });\n },\n }),\n { name: \"DynamicStoresManager\" },\n ),\n);\n\n// โ”€โ”€โ”€ Return types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nexport interface UseDynamicStoreMethodsReturn<T extends StoreState> {\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n getData: () => T;\n}\n\nexport interface UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\n getData: () => T;\n}\n\n// โ”€โ”€โ”€ useDynamicStoreMethods โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook that returns store methods (setData, reset, get) WITHOUT subscribing\n * to state changes. Useful when you only need to update or read the store\n * imperatively without causing component re-renders.\n */\nexport function useDynamicStoreMethods<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreMethodsReturn<T> {\n const setStoreData = useDynamicStoresManager((state) => state.setStoreData);\n const resetStore = useDynamicStoresManager((state) => state.resetStore);\n\n const getData = (): T => {\n const storeRegistry = useDynamicStoresManager.getState().stores[storeId];\n return (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n };\n\n const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const updates = updater(getData());\n setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n resetStore(storeId);\n };\n\n return { setData, reset, getData };\n}\n\n// โ”€โ”€โ”€ useDynamicStore โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Hook-based dynamic store keyed by `storeId`.\n *\n * `setData` accepts either a partial object **or** a function that receives\n * the previous state and returns a partial object โ€” exactly like React's\n * `useState` setter.\n *\n * @example\n * ```tsx\n * const { data, setData, reset } = useDynamicStore<CounterState>('counter', {\n * initialState: { value: 0, step: 1 },\n * });\n *\n * // object update\n * setData({ value: 42 });\n *\n * // functional update โ€” safe for rapid successive calls\n * setData((prev) => ({ value: prev.value + prev.step }));\n * ```\n */\nexport function useDynamicStore<T extends StoreState>(\n storeId: string,\n config?: StoreConfig<T>,\n): UseDynamicStoreReturn<T> {\n const storeRegistry = useDynamicStoresManager((state) => state.stores[storeId]);\n const methods = useDynamicStoreMethods<T>(storeId, config);\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n useDynamicStoresManager.getState().setStoreData(\n storeId,\n {},\n config as StoreConfig,\n );\n }\n // Only run on mount / storeId change โ€” intentional dep list\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId]);\n\n // Handle auto-cleanup on unmount if requested\n useEffect(() => {\n return () => {\n if (config?.resetOnUnmount === true) {\n methods.reset();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storeId, config?.resetOnUnmount]);\n\n const data = (storeRegistry?.data ?? config?.initialState ?? {}) as T;\n\n return {\n data,\n setData: methods.setData,\n reset: methods.reset,\n getData: methods.getData,\n };\n}\n\n// โ”€โ”€โ”€ Imperative helpers (outside React) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Update a dynamic store from outside a React component.\n */\nexport const updateDynamicStore = (\n storeId: string,\n data: StoreState,\n): void => {\n useDynamicStoresManager.getState().setStoreData(storeId, data);\n};\n\n/**\n * Retrieve the current state of a dynamic store from outside a React component.\n * Fallbacks to empty object if store does not exist.\n */\nexport const getDynamicStoreData = <T extends StoreState = StoreState>(\n storeId: string,\n): T | undefined => {\n return useDynamicStoresManager.getState().stores[storeId]?.data as T | undefined;\n};\n\n/**\n * Reset a single dynamic store to its initial state from outside React.\n */\nexport const resetDynamicStore = (storeId: string): void => {\n useDynamicStoresManager.getState().resetStore(storeId);\n};\n\n/**\n * Reset all dynamic stores to their initial states from outside React.\n */\nexport const resetAllDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetAllStores();\n};\n\n/**\n * Reset only stores that do not have `persistOnNavigation: true`.\n */\nexport const resetNonPersistentDynamicStores = (): void => {\n useDynamicStoresManager.getState().resetNonPersistentStores();\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pitboxdev/dynamic-store-zustand",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Dynamic store factory built on top of Zustand for scalable state management",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",