@chromahq/store 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -196,6 +196,79 @@ function createBridgeStore(bridge, initialState, storeName = "default") {
196
196
  return new BridgeStore(bridge, initialState, storeName);
197
197
  }
198
198
 
199
+ function createActionHookForStore(store, actionsFactory) {
200
+ return function useCustomActions() {
201
+ const baseActions = useStoreActions(store);
202
+ return React.useMemo(() => actionsFactory(baseActions), [baseActions]);
203
+ };
204
+ }
205
+ function useStoreActions(store) {
206
+ return React.useMemo(
207
+ () => ({
208
+ update: (partial) => {
209
+ store.setState((state) => ({ ...state, ...partial }));
210
+ },
211
+ updateWith: (updater) => {
212
+ store.setState((state) => ({ ...state, ...updater(state) }));
213
+ },
214
+ replace: (newState) => {
215
+ store.setState(newState, true);
216
+ },
217
+ setState: store.setState.bind(store)
218
+ }),
219
+ [store]
220
+ );
221
+ }
222
+ function createStoreHooks() {
223
+ const StoreContext = React.createContext(null);
224
+ function StoreProvider({ store, children }) {
225
+ const storeRef = React.useRef(store);
226
+ return React__namespace.createElement(StoreContext.Provider, { value: storeRef.current }, children);
227
+ }
228
+ function useStore(selector) {
229
+ const store = React.useContext(StoreContext);
230
+ if (!store) throw new Error("useStore must be used within a StoreProvider");
231
+ return useCentralStore(store, selector);
232
+ }
233
+ function useStoreInstance() {
234
+ const store = React.useContext(StoreContext);
235
+ if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
236
+ return store;
237
+ }
238
+ function useActions() {
239
+ const store = useStoreInstance();
240
+ return useStoreActions(store);
241
+ }
242
+ function useAction(actionKey) {
243
+ const store = useStoreInstance();
244
+ return React__namespace.useCallback(
245
+ (...args) => {
246
+ const fn = store.getState()[actionKey];
247
+ if (typeof fn !== "function") {
248
+ throw new Error("useAction only supports function actions");
249
+ }
250
+ return fn(...args);
251
+ },
252
+ [store, actionKey]
253
+ );
254
+ }
255
+ function createActionHook(actionsFactory) {
256
+ return function useCustomActions() {
257
+ const store = useStoreInstance();
258
+ const baseActions = useStoreActions(store);
259
+ return React.useMemo(() => actionsFactory(baseActions), [baseActions]);
260
+ };
261
+ }
262
+ return {
263
+ createActionHook,
264
+ StoreProvider,
265
+ useStore,
266
+ useStoreInstance,
267
+ useActions,
268
+ useAction
269
+ };
270
+ }
271
+
199
272
  class StoreBuilder {
200
273
  constructor(name = "default") {
201
274
  this.config = {
@@ -253,63 +326,6 @@ function createStore(name) {
253
326
  return new StoreBuilder(name);
254
327
  }
255
328
 
256
- function useStoreActions(store) {
257
- return React.useMemo(
258
- () => ({
259
- // Update state with partial data
260
- update: (partial) => {
261
- store.setState((state) => ({ ...state, ...partial }));
262
- },
263
- // Update state with a function
264
- updateWith: (updater) => {
265
- store.setState((state) => ({ ...state, ...updater(state) }));
266
- },
267
- // Replace entire state
268
- replace: (newState) => {
269
- store.setState(newState, true);
270
- },
271
- // Direct access to setState
272
- setState: store.setState.bind(store)
273
- }),
274
- [store]
275
- );
276
- }
277
- function createStoreHooks() {
278
- const StoreContext = React.createContext(null);
279
- function StoreProvider({ store, children }) {
280
- const storeRef = React.useRef(store);
281
- return React__namespace.createElement(StoreContext.Provider, { value: storeRef.current }, children);
282
- }
283
- function useStore(selector) {
284
- const store = React.useContext(StoreContext);
285
- if (!store) throw new Error("useStore must be used within a StoreProvider");
286
- return useCentralStore(store, selector);
287
- }
288
- function useStoreInstance() {
289
- const store = React.useContext(StoreContext);
290
- if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
291
- return store;
292
- }
293
- function useActions() {
294
- const store = useStoreInstance();
295
- return useStoreActions(store);
296
- }
297
- function createActionHook(actionsFactory) {
298
- return function useCustomActions() {
299
- const store = useStoreInstance();
300
- const baseActions = useStoreActions(store);
301
- return React.useMemo(() => actionsFactory(baseActions), [baseActions]);
302
- };
303
- }
304
- return {
305
- StoreProvider,
306
- useStore,
307
- useStoreInstance,
308
- useActions,
309
- createActionHook
310
- };
311
- }
312
-
313
329
  function autoRegisterStoreHandlers(store) {
314
330
  if (!store) {
315
331
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
@@ -398,6 +414,7 @@ if (typeof globalThis !== "undefined") {
398
414
  exports.BridgeStore = BridgeStore;
399
415
  exports.StoreBuilder = StoreBuilder;
400
416
  exports.chromeStoragePersist = chromeStoragePersist;
417
+ exports.createActionHookForStore = createActionHookForStore;
401
418
  exports.createBridgeStore = createBridgeStore;
402
419
  exports.createStore = createStore;
403
420
  exports.createStoreHooks = createStoreHooks;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { StoreApi, StateCreator } from 'zustand';
2
- import { StateCreator as StateCreator$1 } from 'zustand/vanilla';
3
2
  import * as React from 'react';
4
3
  import { ReactNode } from 'react';
4
+ import { StateCreator as StateCreator$1 } from 'zustand/vanilla';
5
5
 
6
6
  type PersistOptions = {
7
7
  name: string;
@@ -65,33 +65,19 @@ declare class BridgeStore<T> implements CentralStore<T> {
65
65
  declare function createBridgeStore<T>(bridge: BridgeWithEvents, initialState?: T, storeName?: string): CentralStore<T>;
66
66
 
67
67
  /**
68
- * Core store builder with fluent API
69
- */
70
- declare class StoreBuilder<T = any> {
71
- private config;
72
- constructor(name?: string);
73
- /**
74
- * Add state slices to the store
75
- */
76
- withSlices(...slices: StateCreator$1<any, [], [], any>[]): this;
77
- /**
78
- * Attach a bridge for cross-context communication
79
- */
80
- withBridge(bridge?: BridgeWithEvents): this;
81
- /**
82
- * Create the store
83
- */
84
- create(): Promise<CentralStore<T>>;
85
- private createBaseStore;
86
- private createServiceWorkerStore;
87
- }
88
- /**
89
- * Create a new store builder
68
+ * Generic action hook factory for any store instance.
69
+ * Usage:
70
+ * const store = createStore(mergeSlices(sliceA, sliceB));
71
+ * <StoreProvider store={store}> ... </StoreProvider>
72
+ * export const useWalletActions = createActionHookForStore(store, walletActions);
73
+ * export const useCounterActions = createActionHookForStore(store, counterActions);
74
+ * All hooks and actions share the same StoreProvider/context.
90
75
  */
91
- declare function createStore<T = any>(name?: string): StoreBuilder<T>;
76
+ declare function createActionHookForStore<S extends Record<string, any>, ActionMap extends Record<string, (...args: any[]) => void>>(store: CentralStore<S>, actionsFactory: (actions: ReturnType<typeof useStoreActions<S>>) => ActionMap): () => ActionMap;
92
77
 
93
78
  /**
94
- * Store actions helper (inlined from actions.ts)
79
+ * Store actions helper: exposes update, updateWith, replace, setState
80
+ * Actions should be defined in your slice and accessed via useActions.
95
81
  */
96
82
  declare function useStoreActions<T extends Record<string, any>>(store: CentralStore<T>): {
97
83
  update: (partial: Partial<T>) => void;
@@ -102,11 +88,8 @@ declare function useStoreActions<T extends Record<string, any>>(store: CentralSt
102
88
  (state: T | ((state: T) => T), replace: true): void;
103
89
  };
104
90
  };
105
- /**
106
- * Create a complete store hook factory with typed providers and action creators
107
- * This prevents confusion by providing only the hooks you need, not global ones
108
- */
109
91
  declare function createStoreHooks<T extends Record<string, any>>(): {
92
+ createActionHook: <ActionMap extends Record<string, (...args: any[]) => void>>(actionsFactory: (actions: ReturnType<typeof useStoreActions<T>>) => ActionMap) => () => ActionMap;
110
93
  StoreProvider: ({ store, children }: {
111
94
  store: CentralStore<T>;
112
95
  children: ReactNode;
@@ -122,8 +105,34 @@ declare function createStoreHooks<T extends Record<string, any>>(): {
122
105
  (state: T | ((state: T) => T), replace: true): void;
123
106
  };
124
107
  };
125
- createActionHook: <ActionMap extends Record<string, (...args: any[]) => void>>(actionsFactory: (actions: ReturnType<typeof useStoreActions<T>>) => ActionMap) => () => ActionMap;
108
+ useAction: <K extends { [K_1 in keyof T]: T[K_1] extends (...args: any[]) => any ? K_1 : never; }[keyof T]>(actionKey: K) => T[K];
126
109
  };
127
110
 
128
- export { BridgeStore, StoreBuilder, chromeStoragePersist, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
111
+ /**
112
+ * Core store builder with fluent API
113
+ */
114
+ declare class StoreBuilder<T = any> {
115
+ private config;
116
+ constructor(name?: string);
117
+ /**
118
+ * Add state slices to the store
119
+ */
120
+ withSlices(...slices: StateCreator$1<any, [], [], any>[]): this;
121
+ /**
122
+ * Attach a bridge for cross-context communication
123
+ */
124
+ withBridge(bridge?: BridgeWithEvents): this;
125
+ /**
126
+ * Create the store
127
+ */
128
+ create(): Promise<CentralStore<T>>;
129
+ private createBaseStore;
130
+ private createServiceWorkerStore;
131
+ }
132
+ /**
133
+ * Create a new store builder
134
+ */
135
+ declare function createStore<T = any>(name?: string): StoreBuilder<T>;
136
+
137
+ export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
129
138
  export type { Bridge, BridgeWithEvents, BridgeWithHandlers, CentralStore, ExtractSliceState, MergeSlices, PersistOptions, SliceCreator, StoreConfig, StoreDefinition };
package/dist/index.es.js CHANGED
@@ -176,6 +176,79 @@ function createBridgeStore(bridge, initialState, storeName = "default") {
176
176
  return new BridgeStore(bridge, initialState, storeName);
177
177
  }
178
178
 
179
+ function createActionHookForStore(store, actionsFactory) {
180
+ return function useCustomActions() {
181
+ const baseActions = useStoreActions(store);
182
+ return useMemo(() => actionsFactory(baseActions), [baseActions]);
183
+ };
184
+ }
185
+ function useStoreActions(store) {
186
+ return useMemo(
187
+ () => ({
188
+ update: (partial) => {
189
+ store.setState((state) => ({ ...state, ...partial }));
190
+ },
191
+ updateWith: (updater) => {
192
+ store.setState((state) => ({ ...state, ...updater(state) }));
193
+ },
194
+ replace: (newState) => {
195
+ store.setState(newState, true);
196
+ },
197
+ setState: store.setState.bind(store)
198
+ }),
199
+ [store]
200
+ );
201
+ }
202
+ function createStoreHooks() {
203
+ const StoreContext = createContext(null);
204
+ function StoreProvider({ store, children }) {
205
+ const storeRef = useRef(store);
206
+ return React.createElement(StoreContext.Provider, { value: storeRef.current }, children);
207
+ }
208
+ function useStore(selector) {
209
+ const store = useContext(StoreContext);
210
+ if (!store) throw new Error("useStore must be used within a StoreProvider");
211
+ return useCentralStore(store, selector);
212
+ }
213
+ function useStoreInstance() {
214
+ const store = useContext(StoreContext);
215
+ if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
216
+ return store;
217
+ }
218
+ function useActions() {
219
+ const store = useStoreInstance();
220
+ return useStoreActions(store);
221
+ }
222
+ function useAction(actionKey) {
223
+ const store = useStoreInstance();
224
+ return React.useCallback(
225
+ (...args) => {
226
+ const fn = store.getState()[actionKey];
227
+ if (typeof fn !== "function") {
228
+ throw new Error("useAction only supports function actions");
229
+ }
230
+ return fn(...args);
231
+ },
232
+ [store, actionKey]
233
+ );
234
+ }
235
+ function createActionHook(actionsFactory) {
236
+ return function useCustomActions() {
237
+ const store = useStoreInstance();
238
+ const baseActions = useStoreActions(store);
239
+ return useMemo(() => actionsFactory(baseActions), [baseActions]);
240
+ };
241
+ }
242
+ return {
243
+ createActionHook,
244
+ StoreProvider,
245
+ useStore,
246
+ useStoreInstance,
247
+ useActions,
248
+ useAction
249
+ };
250
+ }
251
+
179
252
  class StoreBuilder {
180
253
  constructor(name = "default") {
181
254
  this.config = {
@@ -233,63 +306,6 @@ function createStore(name) {
233
306
  return new StoreBuilder(name);
234
307
  }
235
308
 
236
- function useStoreActions(store) {
237
- return useMemo(
238
- () => ({
239
- // Update state with partial data
240
- update: (partial) => {
241
- store.setState((state) => ({ ...state, ...partial }));
242
- },
243
- // Update state with a function
244
- updateWith: (updater) => {
245
- store.setState((state) => ({ ...state, ...updater(state) }));
246
- },
247
- // Replace entire state
248
- replace: (newState) => {
249
- store.setState(newState, true);
250
- },
251
- // Direct access to setState
252
- setState: store.setState.bind(store)
253
- }),
254
- [store]
255
- );
256
- }
257
- function createStoreHooks() {
258
- const StoreContext = createContext(null);
259
- function StoreProvider({ store, children }) {
260
- const storeRef = useRef(store);
261
- return React.createElement(StoreContext.Provider, { value: storeRef.current }, children);
262
- }
263
- function useStore(selector) {
264
- const store = useContext(StoreContext);
265
- if (!store) throw new Error("useStore must be used within a StoreProvider");
266
- return useCentralStore(store, selector);
267
- }
268
- function useStoreInstance() {
269
- const store = useContext(StoreContext);
270
- if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
271
- return store;
272
- }
273
- function useActions() {
274
- const store = useStoreInstance();
275
- return useStoreActions(store);
276
- }
277
- function createActionHook(actionsFactory) {
278
- return function useCustomActions() {
279
- const store = useStoreInstance();
280
- const baseActions = useStoreActions(store);
281
- return useMemo(() => actionsFactory(baseActions), [baseActions]);
282
- };
283
- }
284
- return {
285
- StoreProvider,
286
- useStore,
287
- useStoreInstance,
288
- useActions,
289
- createActionHook
290
- };
291
- }
292
-
293
309
  function autoRegisterStoreHandlers(store) {
294
310
  if (!store) {
295
311
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
@@ -375,4 +391,4 @@ if (typeof globalThis !== "undefined") {
375
391
  globalThis.initStores = init;
376
392
  }
377
393
 
378
- export { BridgeStore, StoreBuilder, chromeStoragePersist, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
394
+ export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromahq/store",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Centralized, persistent store for Chrome extensions using zustand, accessible from service workers and React, with chrome.storage.local persistence.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",