@chromahq/store 0.1.1 → 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,57 +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: (partial) => {
260
- store.setState((state) => ({ ...state, ...partial }));
261
- },
262
- updateWith: (updater) => {
263
- store.setState((state) => ({ ...state, ...updater(state) }));
264
- },
265
- replace: (newState) => {
266
- store.setState(newState, true);
267
- },
268
- setState: store.setState.bind(store)
269
- }),
270
- [store]
271
- );
272
- }
273
- function createStoreHooks() {
274
- const StoreContext = React.createContext(null);
275
- function StoreProvider({ store, children }) {
276
- const storeRef = React.useRef(store);
277
- return React__namespace.createElement(StoreContext.Provider, { value: storeRef.current }, children);
278
- }
279
- function useStore(selector) {
280
- const store = React.useContext(StoreContext);
281
- if (!store) throw new Error("useStore must be used within a StoreProvider");
282
- return useCentralStore(store, selector);
283
- }
284
- function useStoreInstance() {
285
- const store = React.useContext(StoreContext);
286
- if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
287
- return store;
288
- }
289
- function useActions() {
290
- const store = useStoreInstance();
291
- return useStoreActions(store);
292
- }
293
- function useAction(actionKey) {
294
- const store = useStoreInstance();
295
- const action = useCentralStore(store, (state) => state[actionKey]);
296
- return action;
297
- }
298
- return {
299
- StoreProvider,
300
- useStore,
301
- useStoreInstance,
302
- useActions,
303
- useAction
304
- };
305
- }
306
-
307
329
  function autoRegisterStoreHandlers(store) {
308
330
  if (!store) {
309
331
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
@@ -392,6 +414,7 @@ if (typeof globalThis !== "undefined") {
392
414
  exports.BridgeStore = BridgeStore;
393
415
  exports.StoreBuilder = StoreBuilder;
394
416
  exports.chromeStoragePersist = chromeStoragePersist;
417
+ exports.createActionHookForStore = createActionHookForStore;
395
418
  exports.createBridgeStore = createBridgeStore;
396
419
  exports.createStore = createStore;
397
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;
@@ -64,6 +64,50 @@ declare class BridgeStore<T> implements CentralStore<T> {
64
64
  }
65
65
  declare function createBridgeStore<T>(bridge: BridgeWithEvents, initialState?: T, storeName?: string): CentralStore<T>;
66
66
 
67
+ /**
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.
75
+ */
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;
77
+
78
+ /**
79
+ * Store actions helper: exposes update, updateWith, replace, setState
80
+ * Actions should be defined in your slice and accessed via useActions.
81
+ */
82
+ declare function useStoreActions<T extends Record<string, any>>(store: CentralStore<T>): {
83
+ update: (partial: Partial<T>) => void;
84
+ updateWith: (updater: (state: T) => Partial<T>) => void;
85
+ replace: (newState: T) => void;
86
+ setState: {
87
+ (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: false): void;
88
+ (state: T | ((state: T) => T), replace: true): void;
89
+ };
90
+ };
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;
93
+ StoreProvider: ({ store, children }: {
94
+ store: CentralStore<T>;
95
+ children: ReactNode;
96
+ }) => React.FunctionComponentElement<React.ProviderProps<CentralStore<T> | null>>;
97
+ useStore: <U>(selector: (state: T) => U) => U;
98
+ useStoreInstance: () => CentralStore<T>;
99
+ useActions: () => {
100
+ update: (partial: Partial<T>) => void;
101
+ updateWith: (updater: (state: T) => Partial<T>) => void;
102
+ replace: (newState: T) => void;
103
+ setState: {
104
+ (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: false): void;
105
+ (state: T | ((state: T) => T), replace: true): void;
106
+ };
107
+ };
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];
109
+ };
110
+
67
111
  /**
68
112
  * Core store builder with fluent API
69
113
  */
@@ -90,28 +134,5 @@ declare class StoreBuilder<T = any> {
90
134
  */
91
135
  declare function createStore<T = any>(name?: string): StoreBuilder<T>;
92
136
 
93
- /**
94
- * Create store hooks for context-based state and actions.
95
- * Use useStore for state selection and useActions for auto-wired actions.
96
- */
97
- declare function createStoreHooks<T extends Record<string, any>>(): {
98
- StoreProvider: ({ store, children }: {
99
- store: CentralStore<T>;
100
- children: ReactNode;
101
- }) => React.FunctionComponentElement<React.ProviderProps<CentralStore<T> | null>>;
102
- useStore: <U>(selector: (state: T) => U) => U;
103
- useStoreInstance: () => CentralStore<T>;
104
- useActions: () => {
105
- update: (partial: Partial<T>) => void;
106
- updateWith: (updater: (state: T) => Partial<T>) => void;
107
- replace: (newState: T) => void;
108
- setState: {
109
- (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: false): void;
110
- (state: T | ((state: T) => T), replace: true): void;
111
- };
112
- };
113
- useAction: <K extends keyof T>(actionKey: K) => T[K];
114
- };
115
-
116
- export { BridgeStore, StoreBuilder, chromeStoragePersist, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
137
+ export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, useCentralDispatch, useCentralStore };
117
138
  export type { Bridge, BridgeWithEvents, BridgeWithHandlers, CentralStore, ExtractSliceState, MergeSlices, PersistOptions, SliceCreator, StoreConfig, StoreDefinition };
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { useSyncExternalStore, createContext, useContext, useRef, useMemo } from 'react';
2
+ import { useSyncExternalStore, createContext, useMemo, useContext, useRef } from 'react';
3
3
  import { createStore as createStore$1 } from 'zustand/vanilla';
4
4
 
5
5
  function chromeStoragePersist(options) {
@@ -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,57 +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: (partial) => {
240
- store.setState((state) => ({ ...state, ...partial }));
241
- },
242
- updateWith: (updater) => {
243
- store.setState((state) => ({ ...state, ...updater(state) }));
244
- },
245
- replace: (newState) => {
246
- store.setState(newState, true);
247
- },
248
- setState: store.setState.bind(store)
249
- }),
250
- [store]
251
- );
252
- }
253
- function createStoreHooks() {
254
- const StoreContext = createContext(null);
255
- function StoreProvider({ store, children }) {
256
- const storeRef = useRef(store);
257
- return React.createElement(StoreContext.Provider, { value: storeRef.current }, children);
258
- }
259
- function useStore(selector) {
260
- const store = useContext(StoreContext);
261
- if (!store) throw new Error("useStore must be used within a StoreProvider");
262
- return useCentralStore(store, selector);
263
- }
264
- function useStoreInstance() {
265
- const store = useContext(StoreContext);
266
- if (!store) throw new Error("useStoreInstance must be used within a StoreProvider");
267
- return store;
268
- }
269
- function useActions() {
270
- const store = useStoreInstance();
271
- return useStoreActions(store);
272
- }
273
- function useAction(actionKey) {
274
- const store = useStoreInstance();
275
- const action = useCentralStore(store, (state) => state[actionKey]);
276
- return action;
277
- }
278
- return {
279
- StoreProvider,
280
- useStore,
281
- useStoreInstance,
282
- useActions,
283
- useAction
284
- };
285
- }
286
-
287
309
  function autoRegisterStoreHandlers(store) {
288
310
  if (!store) {
289
311
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
@@ -369,4 +391,4 @@ if (typeof globalThis !== "undefined") {
369
391
  globalThis.initStores = init;
370
392
  }
371
393
 
372
- 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.1",
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",