@pitboxdev/dynamic-store-zustand 0.0.2 → 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
@@ -26,33 +26,41 @@
26
26
 
27
27
  ---
28
28
 
29
- ## Features
29
+ ## Features
30
30
 
31
- - **Zero Boilerplate:** No more complex setups or switch-statements.
32
- - 🧹 **Auto-Cleanup:** Built-in hooks for automatic store resets on unmount.
31
+ - 🛠️ **DX First (Zero Boilerplate):** Extremely simple API without boilerplate, keeping the standard React `useState` ergonomics.
32
+ - 🧹 **Auto-Cleanup:** Built-in config flag `resetOnUnmount` for automatic store resets on unmount.
33
+ - ⚡ **High Performance:** Subscription-free hooks available (`useDynamicStoreMethods`) to read and update state without component re-renders.
33
34
  - 🔄 **Functional Updaters:** Handles race conditions naturally with `setData(prev => ...)`.
34
- - 🛡️ **Fully Typed:** Inferred TypeScript definitions out of the box with strict mode support.
35
+ - 🛡️ **100% Type-safe:** Written in TypeScript with pristine type inference and autocomplete out of the box.
35
36
  - 🪶 **Tiny Footprint:** Minimal addition to your bundle size.
36
37
 
37
38
  ---
38
39
 
40
+ ## ❓ Motivation
41
+
42
+ Modern frontend applications often suffer from state management boilerplate and bloated global stores. Setting up stores usually requires defining schemas upfront, creating actions, and wiring things together.
43
+
44
+ The main motivation behind this package is to **drastically reduce boilerplate and simplify store management for maximum efficiency**.
45
+
46
+ Whether you need to generate stores dynamically on the fly or just want the simplicity of `useState` with the power of a scalable global store, this API delivers a seamless, hassle-free experience.
47
+
48
+ ---
49
+
39
50
  ## Table of Contents
40
51
 
41
- - [Features](#features)
52
+ - [Features](#-features)
53
+ - [❓ Motivation](#-motivation)
42
54
  - [Overview](#overview)
43
55
  - [Installation](#installation)
44
- - [API 1 — `createDynamicStore`](#api-1--createdynamicstore)
56
+ - [`useDynamicStore`](#usedynamicstore)
45
57
  - [Quick Start](#quick-start)
46
- - [Outside React](#outside-react)
47
- - [TypeScript](#typescript)
48
- - [API 2 — `useDynamicStore`](#api-2--usedynamicstore)
49
- - [Quick Start](#quick-start-1)
50
58
  - [Functional updater (`setData`)](#functional-updater-setdata)
51
- - [Auto-cleanup with `useDynamicStoreWithCleanup`](#auto-cleanup-with-usedynamicstorewithcleanup)
52
- - [Imperative helpers (outside React)](#imperative-helpers-outside-react)
53
- - [Config options](#config-options)
54
- - [TypeScript](#typescript-1)
55
- - [When to use which API](#when-to-use-which-api)
59
+ - [Examples](#examples)
60
+ - [`useDynamicStoreMethods` (No Subscription)](#usedynamicstoremethods-no-subscription)
61
+ - [Imperative helpers (outside React)](#imperative-helpers-outside-react)
62
+ - [Config options](#config-options)
63
+ - [TypeScript](#typescript)
56
64
  - [Full API Reference](#full-api-reference)
57
65
  - [Contributing](#contributing)
58
66
  - [License](#license)
@@ -61,17 +69,15 @@
61
69
 
62
70
  ## Overview
63
71
 
64
- The package ships **two independent APIs** that can be used separately or together:
72
+ `@pitboxdev/dynamic-store-zustand` provides dynamic store management for React applications. It is built on top of [Zustand](https://github.com/pmndrs/zustand) and exposes a hook API that feels exactly like React's `useState`, with the addition that stores are stored globally in a single shared registry keyed by a string `storeId`.
65
73
 
66
- | | `createDynamicStore` | `useDynamicStore` |
67
- |---|---|---|
68
- | Style | Factory function | React hook |
69
- | Stores | One Zustand store per call | All stores live in a single registry |
70
- | Actions | Explicit, typed | Implicit via `setData` |
71
- | Functional updater | Via `set((s) => …)` in actions | Built-in `setData((prev) => …)` |
72
- | Auto-cleanup | | `useDynamicStoreWithCleanup` |
73
- | Navigation persistence | — | `persistOnNavigation` config flag |
74
- | Best for | Permanent, feature-level stores | Page/form/modal scoped state |
74
+ | Feature | Description |
75
+ |---|---|
76
+ | **Dynamic initialization** | Stores are initialized just-in-time when the hook mounts |
77
+ | **useState-like API** | `setData(obj)` or `setData((prev) => update)` |
78
+ | **Auto-cleanup** | `resetOnUnmount: true` resets state on unmount |
79
+ | **Navigation reset** | Non-persistent stores reset via imperative API on route changes |
80
+ | **Imperative helpers** | Modify and reset stores outside React components |
75
81
 
76
82
  ---
77
83
 
@@ -89,99 +95,7 @@ pnpm add @pitboxdev/dynamic-store-zustand zustand
89
95
 
90
96
  ---
91
97
 
92
- ## API 1 — `createDynamicStore`
93
-
94
- A factory function that creates a standalone, fully typed Zustand store from a configuration object with explicit actions.
95
-
96
- ### Quick Start
97
-
98
- ```tsx
99
- import { createDynamicStore } from "@pitboxdev/dynamic-store-zustand";
100
-
101
- const { useStore } = createDynamicStore({
102
- initialState: { count: 0 },
103
- actions: (set) => ({
104
- increment: () => set((s) => ({ count: s.count + 1 })),
105
- decrement: () => set((s) => ({ count: s.count - 1 })),
106
- reset: () => set({ count: 0 }),
107
- }),
108
- });
109
-
110
- function Counter() {
111
- const count = useStore((s) => s.count);
112
- const { increment, decrement, reset } = useStore();
113
-
114
- return (
115
- <div>
116
- <button onClick={decrement}>-</button>
117
- <span>{count}</span>
118
- <button onClick={increment}>+</button>
119
- <button onClick={reset}>Reset</button>
120
- </div>
121
- );
122
- }
123
- ```
124
-
125
- ### Outside React
126
-
127
- ```ts
128
- const { store } = createDynamicStore({ initialState: { count: 0 }, actions: (set) => ({
129
- increment: () => set((s) => ({ count: s.count + 1 })),
130
- }) });
131
-
132
- // Read
133
- const count = store.getState().count;
134
-
135
- // Write
136
- store.setState({ count: 42 });
137
-
138
- // Subscribe
139
- const unsub = store.subscribe((state) => console.log(state.count));
140
- unsub();
141
- ```
142
-
143
- ### TypeScript
144
-
145
- All types are inferred automatically. You can also define them explicitly:
146
-
147
- ```ts
148
- import {
149
- createDynamicStore,
150
- type DynamicStoreConfig,
151
- } from "@pitboxdev/dynamic-store-zustand";
152
-
153
- interface CounterState { count: number }
154
- interface CounterActions {
155
- increment: () => void;
156
- decrement: () => void;
157
- reset: () => void;
158
- }
159
-
160
- const config: DynamicStoreConfig<CounterState, CounterActions> = {
161
- initialState: { count: 0 },
162
- actions: (set) => ({
163
- increment: () => set((s) => ({ count: s.count + 1 })),
164
- decrement: () => set((s) => ({ count: s.count - 1 })),
165
- reset: () => set({ count: 0 }),
166
- }),
167
- };
168
-
169
- const { useStore, store } = createDynamicStore(config);
170
- ```
171
-
172
- Using multiple selectors with shallow equality:
173
-
174
- ```ts
175
- import { useShallow } from "zustand/react/shallow";
176
-
177
- const { count, increment } = useStore(
178
- useShallow((s) => ({ count: s.count, increment: s.increment }))
179
- );
180
- ```
181
-
182
- ---
183
-
184
- ## API 2 — `useDynamicStore`
98
+ ## `useDynamicStore`
185
99
 
186
100
  A hook that stores state in a single shared registry keyed by a string `storeId`. `setData` works exactly like React's `useState` setter — it accepts either a partial object or a function that receives the previous state.
187
101
 
@@ -198,7 +112,7 @@ interface CounterState {
198
112
  const initial: CounterState = { value: 0, step: 1 };
199
113
 
200
114
  function Counter() {
201
- const { data, setData, reset } = useDynamicStore<CounterState>("counter", {
115
+ const { data, setData, reset, getData } = useDynamicStore<CounterState>("counter", {
202
116
  initialState: initial,
203
117
  });
204
118
 
@@ -250,6 +164,8 @@ setData((prev) => ({ value: prev.value + 1 }));
250
164
 
251
165
  Always prefer the functional form when the new state depends on the old state.
252
166
 
167
+ ### Examples
168
+
253
169
  #### Todo list example
254
170
 
255
171
  ```tsx
@@ -320,24 +236,41 @@ function Cart() {
320
236
  }
321
237
  ```
322
238
 
323
- ### Auto-cleanup with `useDynamicStoreWithCleanup`
239
+ ---
240
+
241
+ ## `useDynamicStoreMethods` (No Subscription)
324
242
 
325
- `useDynamicStoreWithCleanup` works identically to `useDynamicStore` but resets the store when the component unmounts useful for modal dialogs, wizard steps, or edit forms.
243
+ If you need to update or read the store **without subscribing to its changes** (to avoid component re-renders), you can use `useDynamicStoreMethods`:
326
244
 
327
245
  ```tsx
328
- import { useDynamicStoreWithCleanup } from "@pitboxdev/dynamic-store-zustand";
246
+ import { useDynamicStoreMethods } from "@pitboxdev/dynamic-store-zustand";
329
247
 
330
- function EditModal() {
331
- const { data, setData } = useDynamicStoreWithCleanup<FormState>(
332
- "editForm",
333
- { initialState: { name: "", email: "" }, resetOnUnmount: true }
334
- );
248
+ function Controls() {
249
+ // This component will NOT re-render when 'counter' state changes!
250
+ const { setData, reset, getData } = useDynamicStoreMethods<CounterState>("counter");
251
+
252
+ const increment = () => {
253
+ // Both forms work just like in the regular hook:
254
+ setData((prev) => ({ value: prev.value + 1 }));
255
+ };
335
256
 
336
- // State is automatically reset when the modal closes
257
+ const logCurrent = () => {
258
+ console.log("Current state:", getData()); // Get current state without subscribing
259
+ };
260
+
261
+ return (
262
+ <div>
263
+ <button onClick={increment}>Increment</button>
264
+ <button onClick={logCurrent}>Log State</button>
265
+ <button onClick={reset}>Reset</button>
266
+ </div>
267
+ );
337
268
  }
338
269
  ```
339
270
 
340
- ### Imperative helpers (outside React)
271
+ ---
272
+
273
+ ## Imperative helpers (outside React)
341
274
 
342
275
  All helpers call into the shared manager directly — no hook required.
343
276
 
@@ -362,7 +295,9 @@ resetAllDynamicStores();
362
295
  resetNonPersistentDynamicStores();
363
296
  ```
364
297
 
365
- ### Config options
298
+ ---
299
+
300
+ ## Config options
366
301
 
367
302
  | Option | Type | Default | Description |
368
303
  |---|---|---|---|
@@ -370,7 +305,9 @@ resetNonPersistentDynamicStores();
370
305
  | `persistOnNavigation` | `boolean` | `false` | Skip reset when `resetNonPersistentDynamicStores()` is called |
371
306
  | `resetOnUnmount` | `boolean` | `false` | Auto-reset when the component unmounts (`useDynamicStoreWithCleanup` only) |
372
307
 
373
- ### TypeScript
308
+ ---
309
+
310
+ ## TypeScript
374
311
 
375
312
  ```ts
376
313
  import {
@@ -413,56 +350,8 @@ function RegistrationForm() {
413
350
 
414
351
  ---
415
352
 
416
- ## When to use which API
417
-
418
- ### Use `createDynamicStore` when you need:
419
-
420
- - A **permanent, feature-level store** (auth, theme, user profile, global UI)
421
- - **Explicit, named actions** that encapsulate business logic
422
- - **Fine-grained selectors** and subscriptions outside React
423
- - The full Zustand API (middleware, persist, devtools, subscribe)
424
-
425
- ```ts
426
- // auth.store.ts
427
- export const { useStore: useAuthStore, store: authStore } = createDynamicStore({
428
- initialState: { user: null as User | null, token: "" },
429
- actions: (set) => ({
430
- login: (user: User, token: string) => set({ user, token }),
431
- logout: () => set({ user: null, token: "" }),
432
- }),
433
- });
434
- ```
435
-
436
- ### Use `useDynamicStore` when you need:
437
-
438
- - **Page / route / modal scoped state** with optional auto-cleanup
439
- - **useState-like ergonomics** without boilerplate action definitions
440
- - **Multiple stores** managed centrally with shared reset helpers
441
- - Quick iteration when action interfaces aren't stable yet
442
-
443
- ```tsx
444
- // Inside a wizard step component
445
- const { data, setData } = useDynamicStoreWithCleanup<StepState>(
446
- "wizard-step-2",
447
- { initialState: { selection: null }, resetOnUnmount: true }
448
- );
449
- ```
450
-
451
- ---
452
-
453
353
  ## Full API Reference
454
354
 
455
- ### `createDynamicStore(config)`
456
-
457
- | Parameter | Type | Description |
458
- |---|---|---|
459
- | `config.initialState` | `TState` | Plain object representing the initial state |
460
- | `config.actions` | `(set, get) => TActions` | Factory that returns named action implementations |
461
-
462
- Returns `{ useStore, store }`.
463
-
464
- ---
465
-
466
355
  ### `useDynamicStore<T>(storeId, config?)`
467
356
 
468
357
  | Parameter | Type | Description |
@@ -470,13 +359,13 @@ Returns `{ useStore, store }`.
470
359
  | `storeId` | `string` | Unique key identifying this store in the registry |
471
360
  | `config` | `StoreConfig<T>` | Optional config (see [Config options](#config-options)) |
472
361
 
473
- Returns `{ data: T, setData, reset }`.
362
+ Returns `{ data: T, setData, reset, getData }`.
474
363
 
475
364
  ---
476
365
 
477
- ### `useDynamicStoreWithCleanup<T>(storeId, config?)`
366
+ ### `useDynamicStoreMethods<T>(storeId, config?)`
478
367
 
479
- Same signature as `useDynamicStore`. Calls `reset()` on component unmount when `config.resetOnUnmount` is `true`.
368
+ Returns `{ setData, reset, getData }` bound to the store, without subscribing the component to state changes.
480
369
 
481
370
  ---
482
371
 
@@ -485,6 +374,7 @@ Same signature as `useDynamicStore`. Calls `reset()` on component unmount when `
485
374
  | Function | Signature | Description |
486
375
  |---|---|---|
487
376
  | `updateDynamicStore` | `(storeId, data) => void` | Merge data into a store from outside React |
377
+ | `getDynamicStoreData` | `(storeId) => T \| undefined` | Retrieve a store's current state from outside React |
488
378
  | `resetDynamicStore` | `(storeId) => void` | Reset one store to its `initialState` |
489
379
  | `resetAllDynamicStores` | `() => void` | Reset every registered store |
490
380
  | `resetNonPersistentDynamicStores` | `() => void` | Reset stores where `persistOnNavigation` is not `true` |
@@ -496,14 +386,11 @@ Same signature as `useDynamicStore`. Calls `reset()` on component unmount when `
496
386
  | Type | Description |
497
387
  |---|---|
498
388
  | `StoreState` | `Record<string, unknown>` — base constraint for state objects |
499
- | `StoreActions` | `Record<string, (...args) => unknown>` — base constraint for action maps |
500
- | `DynamicStoreConfig<TState, TActions>` | Config type for `createDynamicStore` |
501
- | `DynamicStore<TState, TActions>` | Return type of `createDynamicStore` |
502
- | `StoreSlice<TState, TActions>` | Merged state + actions type |
503
389
  | `StoreConfig<T>` | Config type for `useDynamicStore` |
504
390
  | `SetStateAction<T>` | `Partial<T> \| ((prev: T) => Partial<T>)` — setter argument type |
505
391
  | `DynamicStoreRegistry` | Internal registry entry (advanced use) |
506
392
  | `UseDynamicStoreReturn<T>` | Return type of `useDynamicStore` |
393
+ | `UseDynamicStoreMethodsReturn<T>` | Return type of `useDynamicStoreMethods` |
507
394
 
508
395
  ---
509
396
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,3 @@
1
- import { UseBoundStore, StoreApi } from 'zustand';
2
-
3
1
  /**
4
2
  * Updater argument for setData — either a partial object or a function
5
3
  * that receives the previous state and returns a partial object.
@@ -30,55 +28,24 @@ interface DynamicStoreRegistry {
30
28
  * Keys are strings, values can be anything.
31
29
  */
32
30
  type StoreState = Record<string, unknown>;
33
- /**
34
- * Actions are functions attached to the store.
35
- */
36
- type StoreActions = Record<string, (...args: unknown[]) => unknown>;
37
- /**
38
- * Full store slice = state + actions.
39
- */
40
- type StoreSlice<TState extends StoreState = StoreState, TActions extends StoreActions = StoreActions> = TState & TActions;
41
- /**
42
- * Configuration object passed to createDynamicStore.
43
- */
44
- interface DynamicStoreConfig<TState extends StoreState, TActions extends StoreActions> {
45
- /** Initial state values */
46
- initialState: TState;
47
- /** Factory that receives `set` and `get` and returns action implementations */
48
- actions: (set: StoreApi<StoreSlice<TState, TActions>>["setState"], get: StoreApi<StoreSlice<TState, TActions>>["getState"]) => TActions;
49
- }
50
- /**
51
- * The return type of createDynamicStore.
52
- */
53
- interface DynamicStore<TState extends StoreState, TActions extends StoreActions> {
54
- /** Zustand React hook */
55
- useStore: UseBoundStore<StoreApi<StoreSlice<TState, TActions>>>;
56
- /** Direct access to the underlying Zustand store API */
57
- store: StoreApi<StoreSlice<TState, TActions>>;
58
- }
59
-
60
- /**
61
- * Creates a dynamic Zustand store from a configuration object.
62
- *
63
- * @example
64
- * ```ts
65
- * const { useStore } = createDynamicStore({
66
- * initialState: { count: 0 },
67
- * actions: (set) => ({
68
- * increment: () => set((s) => ({ count: s.count + 1 })),
69
- * decrement: () => set((s) => ({ count: s.count - 1 })),
70
- * reset: () => set({ count: 0 }),
71
- * }),
72
- * });
73
- * ```
74
- */
75
- declare function createDynamicStore<TState extends StoreState, TActions extends StoreActions>(config: DynamicStoreConfig<TState, TActions>): DynamicStore<TState, TActions>;
76
31
 
32
+ interface UseDynamicStoreMethodsReturn<T extends StoreState> {
33
+ setData: (updater: SetStateAction<T>) => void;
34
+ reset: () => void;
35
+ getData: () => T;
36
+ }
77
37
  interface UseDynamicStoreReturn<T extends StoreState> {
78
38
  data: T;
79
39
  setData: (updater: SetStateAction<T>) => void;
80
40
  reset: () => void;
41
+ getData: () => T;
81
42
  }
43
+ /**
44
+ * Hook that returns store methods (setData, reset, get) WITHOUT subscribing
45
+ * to state changes. Useful when you only need to update or read the store
46
+ * imperatively without causing component re-renders.
47
+ */
48
+ declare function useDynamicStoreMethods<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreMethodsReturn<T>;
82
49
  /**
83
50
  * Hook-based dynamic store keyed by `storeId`.
84
51
  *
@@ -100,23 +67,15 @@ interface UseDynamicStoreReturn<T extends StoreState> {
100
67
  * ```
101
68
  */
102
69
  declare function useDynamicStore<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
103
- /**
104
- * Same as `useDynamicStore` but automatically resets state when the
105
- * component unmounts (when `config.resetOnUnmount` is `true`).
106
- *
107
- * @example
108
- * ```tsx
109
- * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(
110
- * 'editForm',
111
- * { initialState, resetOnUnmount: true },
112
- * );
113
- * ```
114
- */
115
- declare function useDynamicStoreWithCleanup<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
116
70
  /**
117
71
  * Update a dynamic store from outside a React component.
118
72
  */
119
73
  declare const updateDynamicStore: (storeId: string, data: StoreState) => void;
74
+ /**
75
+ * Retrieve the current state of a dynamic store from outside a React component.
76
+ * Fallbacks to empty object if store does not exist.
77
+ */
78
+ declare const getDynamicStoreData: <T extends StoreState = StoreState>(storeId: string) => T | undefined;
120
79
  /**
121
80
  * Reset a single dynamic store to its initial state from outside React.
122
81
  */
@@ -130,4 +89,4 @@ declare const resetAllDynamicStores: () => void;
130
89
  */
131
90
  declare const resetNonPersistentDynamicStores: () => void;
132
91
 
133
- export { type DynamicStore, type DynamicStoreConfig, type DynamicStoreRegistry, type SetStateAction, type StoreActions, type StoreConfig, type StoreSlice, type StoreState, type UseDynamicStoreReturn, createDynamicStore, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, 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
@@ -1,5 +1,3 @@
1
- import { UseBoundStore, StoreApi } from 'zustand';
2
-
3
1
  /**
4
2
  * Updater argument for setData — either a partial object or a function
5
3
  * that receives the previous state and returns a partial object.
@@ -30,55 +28,24 @@ interface DynamicStoreRegistry {
30
28
  * Keys are strings, values can be anything.
31
29
  */
32
30
  type StoreState = Record<string, unknown>;
33
- /**
34
- * Actions are functions attached to the store.
35
- */
36
- type StoreActions = Record<string, (...args: unknown[]) => unknown>;
37
- /**
38
- * Full store slice = state + actions.
39
- */
40
- type StoreSlice<TState extends StoreState = StoreState, TActions extends StoreActions = StoreActions> = TState & TActions;
41
- /**
42
- * Configuration object passed to createDynamicStore.
43
- */
44
- interface DynamicStoreConfig<TState extends StoreState, TActions extends StoreActions> {
45
- /** Initial state values */
46
- initialState: TState;
47
- /** Factory that receives `set` and `get` and returns action implementations */
48
- actions: (set: StoreApi<StoreSlice<TState, TActions>>["setState"], get: StoreApi<StoreSlice<TState, TActions>>["getState"]) => TActions;
49
- }
50
- /**
51
- * The return type of createDynamicStore.
52
- */
53
- interface DynamicStore<TState extends StoreState, TActions extends StoreActions> {
54
- /** Zustand React hook */
55
- useStore: UseBoundStore<StoreApi<StoreSlice<TState, TActions>>>;
56
- /** Direct access to the underlying Zustand store API */
57
- store: StoreApi<StoreSlice<TState, TActions>>;
58
- }
59
-
60
- /**
61
- * Creates a dynamic Zustand store from a configuration object.
62
- *
63
- * @example
64
- * ```ts
65
- * const { useStore } = createDynamicStore({
66
- * initialState: { count: 0 },
67
- * actions: (set) => ({
68
- * increment: () => set((s) => ({ count: s.count + 1 })),
69
- * decrement: () => set((s) => ({ count: s.count - 1 })),
70
- * reset: () => set({ count: 0 }),
71
- * }),
72
- * });
73
- * ```
74
- */
75
- declare function createDynamicStore<TState extends StoreState, TActions extends StoreActions>(config: DynamicStoreConfig<TState, TActions>): DynamicStore<TState, TActions>;
76
31
 
32
+ interface UseDynamicStoreMethodsReturn<T extends StoreState> {
33
+ setData: (updater: SetStateAction<T>) => void;
34
+ reset: () => void;
35
+ getData: () => T;
36
+ }
77
37
  interface UseDynamicStoreReturn<T extends StoreState> {
78
38
  data: T;
79
39
  setData: (updater: SetStateAction<T>) => void;
80
40
  reset: () => void;
41
+ getData: () => T;
81
42
  }
43
+ /**
44
+ * Hook that returns store methods (setData, reset, get) WITHOUT subscribing
45
+ * to state changes. Useful when you only need to update or read the store
46
+ * imperatively without causing component re-renders.
47
+ */
48
+ declare function useDynamicStoreMethods<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreMethodsReturn<T>;
82
49
  /**
83
50
  * Hook-based dynamic store keyed by `storeId`.
84
51
  *
@@ -100,23 +67,15 @@ interface UseDynamicStoreReturn<T extends StoreState> {
100
67
  * ```
101
68
  */
102
69
  declare function useDynamicStore<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
103
- /**
104
- * Same as `useDynamicStore` but automatically resets state when the
105
- * component unmounts (when `config.resetOnUnmount` is `true`).
106
- *
107
- * @example
108
- * ```tsx
109
- * const { data, setData, reset } = useDynamicStoreWithCleanup<FormState>(
110
- * 'editForm',
111
- * { initialState, resetOnUnmount: true },
112
- * );
113
- * ```
114
- */
115
- declare function useDynamicStoreWithCleanup<T extends StoreState>(storeId: string, config?: StoreConfig<T>): UseDynamicStoreReturn<T>;
116
70
  /**
117
71
  * Update a dynamic store from outside a React component.
118
72
  */
119
73
  declare const updateDynamicStore: (storeId: string, data: StoreState) => void;
74
+ /**
75
+ * Retrieve the current state of a dynamic store from outside a React component.
76
+ * Fallbacks to empty object if store does not exist.
77
+ */
78
+ declare const getDynamicStoreData: <T extends StoreState = StoreState>(storeId: string) => T | undefined;
120
79
  /**
121
80
  * Reset a single dynamic store to its initial state from outside React.
122
81
  */
@@ -130,4 +89,4 @@ declare const resetAllDynamicStores: () => void;
130
89
  */
131
90
  declare const resetNonPersistentDynamicStores: () => void;
132
91
 
133
- export { type DynamicStore, type DynamicStoreConfig, type DynamicStoreRegistry, type SetStateAction, type StoreActions, type StoreConfig, type StoreSlice, type StoreState, type UseDynamicStoreReturn, createDynamicStore, resetAllDynamicStores, resetDynamicStore, resetNonPersistentDynamicStores, updateDynamicStore, useDynamicStore, 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');function d(r){let{initialState:t,actions:e}=r,o=zustand.create()((n,s)=>({...t,...e(n,s)}));return {useStore:o,store:o}}var i=zustand.create()(middleware.devtools(r=>({stores:{},setStoreData:(t,e,o)=>{r(n=>{let s=n.stores[t],a={data:{...s?.data??o?.initialState??{},...e},config:o??s?.config??{},initialState:o?.initialState??s?.initialState??{}};return {stores:{...n.stores,[t]:a}}});},resetStore:t=>{r(e=>{let o=e.stores[t];return o?{stores:{...e.stores,[t]:{...o,data:{...o.initialState}}}}:e});},resetAllStores:()=>{r(t=>{let e={};for(let[o,n]of Object.entries(t.stores))e[o]={...n,data:{...n.initialState}};return {stores:e}});},resetNonPersistentStores:()=>{r(t=>{let e={};for(let[o,n]of Object.entries(t.stores))e[o]=n.config.persistOnNavigation===true?n:{...n,data:{...n.initialState}};return {stores:e}});}}),{name:"DynamicStoresManager"}));function c(r,t){let e=i(),o=e.stores[r];return react.useEffect(()=>{!o&&t?.initialState!==void 0&&e.setStoreData(r,{},t);},[r]),{data:o?.data??t?.initialState??{},setData:a=>{if(typeof a=="function"){let y=e.stores[r]?.data??t?.initialState??{},D=a(y);e.setStoreData(r,D,t);}else e.setStoreData(r,a,t);},reset:()=>{e.resetStore(r);}}}function g(r,t){let{data:e,setData:o,reset:n}=c(r,t);return react.useEffect(()=>()=>{t?.resetOnUnmount===true&&n();},[r,t?.resetOnUnmount]),{data:e,setData:o,reset:n}}var l=(r,t)=>{i.getState().setStoreData(r,t);},x=r=>{i.getState().resetStore(r);},T=()=>{i.getState().resetAllStores();},A=()=>{i.getState().resetNonPersistentStores();};exports.createDynamicStore=d;exports.resetAllDynamicStores=T;exports.resetDynamicStore=x;exports.resetNonPersistentDynamicStores=A;exports.updateDynamicStore=l;exports.useDynamicStore=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/createDynamicStore.ts","../src/dynamicStore.ts"],"names":["createDynamicStore","config","initialState","actions","store","create","set","get","useDynamicStoresManager","devtools","storeId","data","state","existingStore","entry","next","id","useDynamicStore","storesManager","storeRegistry","useEffect","updater","currentData","updates","useDynamicStoreWithCleanup","setData","reset","updateDynamicStore","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"4GAwBO,SAASA,EAIdC,CAAAA,CACgC,CAChC,GAAM,CAAE,YAAA,CAAAC,CAAAA,CAAc,QAAAC,CAAQ,CAAA,CAAIF,EAE5BG,CAAAA,CAAQC,cAAAA,GAAuC,CAACC,CAAAA,CAAKC,CAAAA,IAAS,CAClE,GAAGL,CAAAA,CACH,GAAGC,CAAAA,CAAQG,CAAAA,CAAKC,CAAG,CACrB,CAAA,CAAE,EAEF,OAAO,CACL,QAAA,CAAUH,CAAAA,CACV,KAAA,CAAAA,CACF,CACF,CCjBA,IAAMI,CAAAA,CAA0BH,cAAAA,GAC9BI,mBAAAA,CACGH,CAAAA,GAAS,CACR,MAAA,CAAQ,EAAC,CAET,YAAA,CAAc,CAACI,CAAAA,CAASC,EAAMV,CAAAA,GAAW,CACvCK,CAAAA,CAAKM,CAAAA,EAAU,CACb,IAAMC,EAAgBD,CAAAA,CAAM,MAAA,CAAOF,CAAO,CAAA,CAIpCI,CAAAA,CAA8B,CAClC,KAAM,CAAE,GAHRD,GAAe,IAAA,EAAQZ,CAAAA,EAAQ,cAAgB,EAAC,CAGxB,GAAGU,CAAK,CAAA,CAChC,MAAA,CAAQV,GAAUY,CAAAA,EAAe,MAAA,EAAU,EAAC,CAC5C,YAAA,CACEZ,CAAAA,EAAQ,cAAgBY,CAAAA,EAAe,YAAA,EAAgB,EAC3D,CAAA,CAEA,OAAO,CACL,MAAA,CAAQ,CAAE,GAAGD,CAAAA,CAAM,MAAA,CAAQ,CAACF,CAAO,EAAGI,CAAM,CAC9C,CACF,CAAC,EACH,CAAA,CAEA,UAAA,CAAaJ,CAAAA,EAAY,CACvBJ,CAAAA,CAAKM,CAAAA,EAAU,CACb,IAAMR,CAAAA,CAAQQ,CAAAA,CAAM,MAAA,CAAOF,CAAO,CAAA,CAClC,OAAKN,CAAAA,CAEE,CACL,OAAQ,CACN,GAAGQ,EAAM,MAAA,CACT,CAACF,CAAO,EAAG,CAAE,GAAGN,EAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CACzD,CACF,CAAA,CAPmBQ,CAQrB,CAAC,EACH,CAAA,CAEA,eAAgB,IAAM,CACpBN,EAAKM,CAAAA,EAAU,CACb,IAAMG,CAAAA,CAA6C,EAAC,CAEpD,IAAA,GAAW,CAACC,CAAAA,CAAIZ,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQQ,CAAAA,CAAM,MAAM,CAAA,CACnDG,EAAKC,CAAE,CAAA,CAAI,CAAE,GAAGZ,CAAAA,CAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CAAA,CAGzD,OAAO,CAAE,MAAA,CAAQW,CAAK,CACxB,CAAC,EACH,EAEA,wBAAA,CAA0B,IAAM,CAC9BT,CAAAA,CAAKM,CAAAA,EAAU,CACb,IAAMG,CAAAA,CAA6C,EAAC,CAEpD,IAAA,GAAW,CAACC,CAAAA,CAAIZ,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQQ,CAAAA,CAAM,MAAM,EACnDG,CAAAA,CAAKC,CAAE,CAAA,CACLZ,CAAAA,CAAM,MAAA,CAAO,mBAAA,GAAwB,KACjCA,CAAAA,CACA,CAAE,GAAGA,CAAAA,CAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CAAA,CAGpD,OAAO,CAAE,OAAQW,CAAK,CACxB,CAAC,EACH,CACF,GACA,CAAE,IAAA,CAAM,sBAAuB,CACjC,CACF,CAAA,CAgCO,SAASE,CAAAA,CACdP,CAAAA,CACAT,CAAAA,CAC0B,CAC1B,IAAMiB,CAAAA,CAAgBV,GAAwB,CACxCW,CAAAA,CAAgBD,CAAAA,CAAc,MAAA,CAAOR,CAAO,CAAA,CAGlD,OAAAU,eAAAA,CAAU,IAAM,CACV,CAACD,CAAAA,EAAiBlB,GAAQ,YAAA,GAAiB,MAAA,EAC7CiB,CAAAA,CAAc,YAAA,CAAaR,CAAAA,CAAS,GAAIT,CAAqB,EAIjE,CAAA,CAAG,CAACS,CAAO,CAAC,EA4BL,CAAE,IAAA,CA1BKS,CAAAA,EAAe,IAAA,EAAQlB,CAAAA,EAAQ,YAAA,EAAgB,EAAC,CA0B/C,OAAA,CAxBEoB,GAAqC,CACpD,GAAI,OAAOA,CAAAA,EAAY,UAAA,CAAY,CACjC,IAAMC,CAAAA,CACJJ,CAAAA,CAAc,OAAOR,CAAO,CAAA,EAAG,IAAA,EAAQT,CAAAA,EAAQ,YAAA,EAAgB,GAE3DsB,CAAAA,CAAUF,CAAAA,CAAQC,CAAW,CAAA,CACnCJ,CAAAA,CAAc,YAAA,CACZR,EACAa,CAAAA,CACAtB,CACF,EACF,CAAA,KACEiB,CAAAA,CAAc,aACZR,CAAAA,CACAW,CAAAA,CACApB,CACF,EAEJ,CAAA,CAMwB,KAAA,CAJV,IAAY,CACxBiB,CAAAA,CAAc,UAAA,CAAWR,CAAO,EAClC,CAE8B,CAChC,CAgBO,SAASc,CAAAA,CACdd,CAAAA,CACAT,CAAAA,CAC0B,CAC1B,GAAM,CAAE,IAAA,CAAAU,EAAM,OAAA,CAAAc,CAAAA,CAAS,MAAAC,CAAM,CAAA,CAAIT,CAAAA,CAAmBP,CAAAA,CAAST,CAAM,CAAA,CAEnE,OAAAmB,eAAAA,CAAU,IACD,IAAM,CACPnB,CAAAA,EAAQ,cAAA,GAAmB,MAC7ByB,CAAAA,GAEJ,CAAA,CAEC,CAAChB,CAAAA,CAAST,CAAAA,EAAQ,cAAc,CAAC,CAAA,CAE7B,CAAE,IAAA,CAAAU,CAAAA,CAAM,QAAAc,CAAAA,CAAS,KAAA,CAAAC,CAAM,CAChC,CAOO,IAAMC,EAAqB,CAChCjB,CAAAA,CACAC,CAAAA,GACS,CACTH,CAAAA,CAAwB,QAAA,GAAW,YAAA,CAAaE,CAAAA,CAASC,CAAI,EAC/D,CAAA,CAKaiB,CAAAA,CAAqBlB,GAA0B,CAC1DF,CAAAA,CAAwB,UAAS,CAAE,UAAA,CAAWE,CAAO,EACvD,CAAA,CAKamB,CAAAA,CAAwB,IAAY,CAC/CrB,CAAAA,CAAwB,UAAS,CAAE,cAAA,GACrC,CAAA,CAKasB,CAAAA,CAAkC,IAAY,CACzDtB,CAAAA,CAAwB,QAAA,EAAS,CAAE,wBAAA,GACrC","file":"index.js","sourcesContent":["import { create } from \"zustand\";\nimport type {\n DynamicStore,\n DynamicStoreConfig,\n StoreActions,\n StoreState,\n StoreSlice,\n} from \"./types\";\n\n/**\n * Creates a dynamic Zustand store from a configuration object.\n *\n * @example\n * ```ts\n * const { useStore } = createDynamicStore({\n * initialState: { count: 0 },\n * actions: (set) => ({\n * increment: () => set((s) => ({ count: s.count + 1 })),\n * decrement: () => set((s) => ({ count: s.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * });\n * ```\n */\nexport function createDynamicStore<\n TState extends StoreState,\n TActions extends StoreActions,\n>(\n config: DynamicStoreConfig<TState, TActions>,\n): DynamicStore<TState, TActions> {\n const { initialState, actions } = config;\n\n const store = create<StoreSlice<TState, TActions>>()((set, get) => ({\n ...initialState,\n ...actions(set, get),\n }));\n\n return {\n useStore: store,\n store,\n };\n}\n","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 UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\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 storesManager = useDynamicStoresManager();\n const storeRegistry = storesManager.stores[storeId];\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n storesManager.setStoreData(storeId, {}, config as StoreConfig);\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 const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const currentData = (\n storesManager.stores[storeId]?.data ?? config?.initialState ?? {}\n ) as T;\n const updates = updater(currentData);\n storesManager.setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n storesManager.setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n storesManager.resetStore(storeId);\n };\n\n return { data, setData, 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 * 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';function d(r){let{initialState:t,actions:e}=r,o=create()((n,s)=>({...t,...e(n,s)}));return {useStore:o,store:o}}var i=create()(devtools(r=>({stores:{},setStoreData:(t,e,o)=>{r(n=>{let s=n.stores[t],a={data:{...s?.data??o?.initialState??{},...e},config:o??s?.config??{},initialState:o?.initialState??s?.initialState??{}};return {stores:{...n.stores,[t]:a}}});},resetStore:t=>{r(e=>{let o=e.stores[t];return o?{stores:{...e.stores,[t]:{...o,data:{...o.initialState}}}}:e});},resetAllStores:()=>{r(t=>{let e={};for(let[o,n]of Object.entries(t.stores))e[o]={...n,data:{...n.initialState}};return {stores:e}});},resetNonPersistentStores:()=>{r(t=>{let e={};for(let[o,n]of Object.entries(t.stores))e[o]=n.config.persistOnNavigation===true?n:{...n,data:{...n.initialState}};return {stores:e}});}}),{name:"DynamicStoresManager"}));function c(r,t){let e=i(),o=e.stores[r];return useEffect(()=>{!o&&t?.initialState!==void 0&&e.setStoreData(r,{},t);},[r]),{data:o?.data??t?.initialState??{},setData:a=>{if(typeof a=="function"){let y=e.stores[r]?.data??t?.initialState??{},D=a(y);e.setStoreData(r,D,t);}else e.setStoreData(r,a,t);},reset:()=>{e.resetStore(r);}}}function g(r,t){let{data:e,setData:o,reset:n}=c(r,t);return useEffect(()=>()=>{t?.resetOnUnmount===true&&n();},[r,t?.resetOnUnmount]),{data:e,setData:o,reset:n}}var l=(r,t)=>{i.getState().setStoreData(r,t);},x=r=>{i.getState().resetStore(r);},T=()=>{i.getState().resetAllStores();},A=()=>{i.getState().resetNonPersistentStores();};export{d as createDynamicStore,T as resetAllDynamicStores,x as resetDynamicStore,A as resetNonPersistentDynamicStores,l as updateDynamicStore,c as useDynamicStore,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/createDynamicStore.ts","../src/dynamicStore.ts"],"names":["createDynamicStore","config","initialState","actions","store","create","set","get","useDynamicStoresManager","devtools","storeId","data","state","existingStore","entry","next","id","useDynamicStore","storesManager","storeRegistry","useEffect","updater","currentData","updates","useDynamicStoreWithCleanup","setData","reset","updateDynamicStore","resetDynamicStore","resetAllDynamicStores","resetNonPersistentDynamicStores"],"mappings":"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","file":"index.mjs","sourcesContent":["import { create } from \"zustand\";\nimport type {\n DynamicStore,\n DynamicStoreConfig,\n StoreActions,\n StoreState,\n StoreSlice,\n} from \"./types\";\n\n/**\n * Creates a dynamic Zustand store from a configuration object.\n *\n * @example\n * ```ts\n * const { useStore } = createDynamicStore({\n * initialState: { count: 0 },\n * actions: (set) => ({\n * increment: () => set((s) => ({ count: s.count + 1 })),\n * decrement: () => set((s) => ({ count: s.count - 1 })),\n * reset: () => set({ count: 0 }),\n * }),\n * });\n * ```\n */\nexport function createDynamicStore<\n TState extends StoreState,\n TActions extends StoreActions,\n>(\n config: DynamicStoreConfig<TState, TActions>,\n): DynamicStore<TState, TActions> {\n const { initialState, actions } = config;\n\n const store = create<StoreSlice<TState, TActions>>()((set, get) => ({\n ...initialState,\n ...actions(set, get),\n }));\n\n return {\n useStore: store,\n store,\n };\n}\n","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 UseDynamicStoreReturn<T extends StoreState> {\n data: T;\n setData: (updater: SetStateAction<T>) => void;\n reset: () => void;\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 storesManager = useDynamicStoresManager();\n const storeRegistry = storesManager.stores[storeId];\n\n // Initialize the store entry on first use\n useEffect(() => {\n if (!storeRegistry && config?.initialState !== undefined) {\n storesManager.setStoreData(storeId, {}, config as StoreConfig);\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 const setData = (updater: SetStateAction<T>): void => {\n if (typeof updater === \"function\") {\n const currentData = (\n storesManager.stores[storeId]?.data ?? config?.initialState ?? {}\n ) as T;\n const updates = updater(currentData);\n storesManager.setStoreData(\n storeId,\n updates as StoreState,\n config as StoreConfig | undefined,\n );\n } else {\n storesManager.setStoreData(\n storeId,\n updater as StoreState,\n config as StoreConfig | undefined,\n );\n }\n };\n\n const reset = (): void => {\n storesManager.resetStore(storeId);\n };\n\n return { data, setData, 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 * 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":"qGAwBA,IAAMA,CAAAA,CAA0BC,QAA2B,CACzDC,QAAAA,CACGC,IAAS,CACR,MAAA,CAAQ,EAAC,CAET,YAAA,CAAc,CAACC,EAASC,CAAAA,CAAMC,CAAAA,GAAW,CACvCH,CAAAA,CAAKI,CAAAA,EAAU,CACb,IAAMC,CAAAA,CAAgBD,CAAAA,CAAM,MAAA,CAAOH,CAAO,CAAA,CAIpCK,EAA8B,CAClC,IAAA,CAAM,CAAE,GAHRD,CAAAA,EAAe,MAAQF,CAAAA,EAAQ,YAAA,EAAgB,EAAC,CAGxB,GAAGD,CAAK,EAChC,MAAA,CAAQC,CAAAA,EAAUE,GAAe,MAAA,EAAU,GAC3C,YAAA,CACEF,CAAAA,EAAQ,YAAA,EAAgBE,CAAAA,EAAe,YAAA,EAAgB,EAC3D,CAAA,CAEA,OAAO,CACL,MAAA,CAAQ,CAAE,GAAGD,CAAAA,CAAM,MAAA,CAAQ,CAACH,CAAO,EAAGK,CAAM,CAC9C,CACF,CAAC,EACH,CAAA,CAEA,UAAA,CAAaL,GAAY,CACvBD,CAAAA,CAAKI,CAAAA,EAAU,CACb,IAAMG,CAAAA,CAAQH,EAAM,MAAA,CAAOH,CAAO,EAClC,OAAKM,CAAAA,CAEE,CACL,MAAA,CAAQ,CACN,GAAGH,CAAAA,CAAM,MAAA,CACT,CAACH,CAAO,EAAG,CAAE,GAAGM,CAAAA,CAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CACzD,CACF,EAPmBH,CAQrB,CAAC,EACH,CAAA,CAEA,cAAA,CAAgB,IAAM,CACpBJ,CAAAA,CAAKI,CAAAA,EAAU,CACb,IAAMI,CAAAA,CAA6C,EAAC,CAEpD,IAAA,GAAW,CAACC,CAAAA,CAAIF,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQH,CAAAA,CAAM,MAAM,CAAA,CACnDI,CAAAA,CAAKC,CAAE,CAAA,CAAI,CAAE,GAAGF,CAAAA,CAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CAAA,CAGzD,OAAO,CAAE,MAAA,CAAQC,CAAK,CACxB,CAAC,EACH,EAEA,wBAAA,CAA0B,IAAM,CAC9BR,CAAAA,CAAKI,CAAAA,EAAU,CACb,IAAMI,CAAAA,CAA6C,GAEnD,IAAA,GAAW,CAACC,EAAIF,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQH,CAAAA,CAAM,MAAM,EACnDI,CAAAA,CAAKC,CAAE,EACLF,CAAAA,CAAM,MAAA,CAAO,sBAAwB,IAAA,CACjCA,CAAAA,CACA,CAAE,GAAGA,CAAAA,CAAO,IAAA,CAAM,CAAE,GAAGA,CAAAA,CAAM,YAAa,CAAE,CAAA,CAGpD,OAAO,CAAE,MAAA,CAAQC,CAAK,CACxB,CAAC,EACH,CACF,CAAA,CAAA,CACA,CAAE,KAAM,sBAAuB,CACjC,CACF,CAAA,CAwBO,SAASE,EACdT,CAAAA,CACAE,CAAAA,CACiC,CACjC,IAAMQ,CAAAA,CAAed,EAAyBO,CAAAA,EAAUA,CAAAA,CAAM,YAAY,CAAA,CACpEQ,CAAAA,CAAaf,CAAAA,CAAyBO,CAAAA,EAAUA,CAAAA,CAAM,UAAU,EAEhES,CAAAA,CAAU,IACQhB,EAAwB,QAAA,EAAS,CAAE,OAAOI,CAAO,CAAA,EAChD,IAAA,EAAQE,CAAAA,EAAQ,YAAA,EAAgB,GAwBzD,OAAO,CAAE,QArBQW,CAAAA,EAAqC,CACpD,GAAI,OAAOA,CAAAA,EAAY,UAAA,CAAY,CACjC,IAAMC,CAAAA,CAAUD,EAAQD,CAAAA,EAAS,EACjCF,CAAAA,CACEV,CAAAA,CACAc,EACAZ,CACF,EACF,CAAA,KACEQ,CAAAA,CACEV,CAAAA,CACAa,CAAAA,CACAX,CACF,EAEJ,CAAA,CAMkB,MAJJ,IAAY,CACxBS,EAAWX,CAAO,EACpB,CAAA,CAEyB,OAAA,CAAAY,CAAQ,CACnC,CAwBO,SAASG,CAAAA,CACdf,EACAE,CAAAA,CAC0B,CAC1B,IAAMc,CAAAA,CAAgBpB,CAAAA,CAAyBO,CAAAA,EAAUA,CAAAA,CAAM,MAAA,CAAOH,CAAO,CAAC,CAAA,CACxEiB,CAAAA,CAAUR,EAA0BT,CAAAA,CAASE,CAAM,EAGzD,OAAAgB,SAAAA,CAAU,IAAM,CACV,CAACF,CAAAA,EAAiBd,GAAQ,YAAA,GAAiB,MAAA,EAC7CN,EAAwB,QAAA,EAAS,CAAE,aACjCI,CAAAA,CACA,EAAC,CACDE,CACF,EAIJ,CAAA,CAAG,CAACF,CAAO,CAAC,EAGZkB,SAAAA,CAAU,IACD,IAAM,CACPhB,CAAAA,EAAQ,cAAA,GAAmB,IAAA,EAC7Be,CAAAA,CAAQ,KAAA,GAEZ,CAAA,CAEC,CAACjB,EAASE,CAAAA,EAAQ,cAAc,CAAC,CAAA,CAI7B,CACL,IAAA,CAHYc,CAAAA,EAAe,IAAA,EAAQd,CAAAA,EAAQ,cAAgB,EAAC,CAI5D,QAASe,CAAAA,CAAQ,OAAA,CACjB,MAAOA,CAAAA,CAAQ,KAAA,CACf,OAAA,CAASA,CAAAA,CAAQ,OACnB,CACF,CAOO,IAAME,CAAAA,CAAqB,CAChCnB,CAAAA,CACAC,CAAAA,GACS,CACTL,CAAAA,CAAwB,QAAA,EAAS,CAAE,YAAA,CAAaI,CAAAA,CAASC,CAAI,EAC/D,CAAA,CAMamB,CAAAA,CACXpB,GAEOJ,CAAAA,CAAwB,QAAA,GAAW,MAAA,CAAOI,CAAO,CAAA,EAAG,IAAA,CAMhDqB,CAAAA,CAAqBrB,CAAAA,EAA0B,CAC1DJ,CAAAA,CAAwB,QAAA,GAAW,UAAA,CAAWI,CAAO,EACvD,CAAA,CAKasB,CAAAA,CAAwB,IAAY,CAC/C1B,CAAAA,CAAwB,QAAA,GAAW,cAAA,GACrC,EAKa2B,CAAAA,CAAkC,IAAY,CACzD3B,CAAAA,CAAwB,QAAA,EAAS,CAAE,wBAAA,GACrC","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.2",
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",