UNPKG

@zubridge/electron

Version:

A streamlined state management library for Electron applications using Zustand.

477 lines (333 loc) 14 kB
# API Reference This document provides a comprehensive reference for the `@zubridge/electron` API. ## Backend (Main Process) APIs ### Bridge APIs #### `createCoreBridge(stateManager, windows?)` Creates a core bridge between the main process and renderer processes, using any state manager that implements the `StateManager` interface. This is useful for creating custom bridges with state management libraries not directly supported by Zubridge. ##### Parameters: - `stateManager`: Implementation of the `StateManager<State>` interface - `windows?`: Optional array of `BrowserWindow`, `BrowserView`, `WebContentsView`, or `WebContents` instances to subscribe to the store. Can be empty or undefined. ##### Returns: A `CoreBridge` object with: - `subscribe(windows)`: Function to subscribe additional windows to the state updates. Returns an object with an `unsubscribe` method. - `unsubscribe(windows?)`: Function to unsubscribe windows from updates. When called without arguments, unsubscribes all windows. - `getSubscribedWindows()`: Function to get all currently subscribed window IDs. - `destroy()`: Function to clean up resources used by the bridge. ##### Example: ```ts import { app, BrowserWindow } from 'electron'; import { createCoreBridge } from '@zubridge/electron/main'; import { myStateManager } from './state-manager'; const mainWindow = new BrowserWindow({ /* options */ }); // Create bridge without initial windows (subscribe later) const bridge = createCoreBridge(myStateManager); // Or create with initial windows const bridgeWithWindows = createCoreBridge(myStateManager, [mainWindow]); // Subscribe additional windows later const secondWindow = new BrowserWindow(/* options */); const subscription = bridge.subscribe([secondWindow]); // Unsubscribe when quitting app.on('quit', bridge.unsubscribe); ``` #### `createZustandBridge(store, windows?, options?)` Creates a bridge between a Zustand store in the main process and renderer processes. This is the recommended way to integrate a Zustand store with Electron's IPC system. ##### Parameters: - `store`: The Zustand store to bridge - `windows?`: Optional array of `BrowserWindow`, `BrowserView`, `WebContentsView`, or `WebContents` instances to subscribe to the store. Can be empty or undefined. - `options`: Optional configuration object - `handlers`: Optional object containing store handler functions - `reducer`: Optional root reducer function for Redux-style state management ##### Returns: A `ZustandBridge` object with: - `subscribe(windows)`: Function to subscribe additional windows to the store updates. Returns an object with an `unsubscribe` method. - `unsubscribe(windows?)`: Function to unsubscribe windows from the store. When called without arguments, unsubscribes all windows. - `getSubscribedWindows()`: Function to get all currently subscribed window IDs. - `dispatch`: Function to dispatch actions to the store. - `destroy()`: Function to clean up resources used by the bridge. ##### Example: ```ts import { app, BrowserWindow } from 'electron'; import { createZustandBridge } from '@zubridge/electron/main'; import { store } from './store'; const mainWindow = new BrowserWindow({ /* options */ }); // Create bridge with initial windows const { unsubscribe, subscribe, dispatch } = createZustandBridge(store, [mainWindow]); // Or create without windows and subscribe later const bridge = createZustandBridge(store); const subscription = bridge.subscribe([mainWindow]); // Using with handlers option const bridgeWithHandlers = createZustandBridge(store, [mainWindow], { handlers: { CUSTOM_ACTION: (payload) => { console.log('Custom action received:', payload); store.setState((state) => ({ ...state, customValue: payload })); }, }, }); // Using with reducer option const bridgeWithReducer = createZustandBridge(store, [mainWindow], { reducer: (state, action) => { switch (action.type) { case 'SET_VALUE': return { ...state, value: action.payload }; default: return state; } }, }); // Dispatch actions from the main process dispatch('INCREMENT'); // Unsubscribe when quitting app.on('quit', unsubscribe); ``` #### `createReduxBridge(store, windows?, options?)` Creates a bridge between a Redux store in the main process and renderer processes. This is the recommended way to integrate a Redux store with Electron's IPC system. ##### Parameters: - `store`: The Redux store to bridge - `windows?`: Optional array of `BrowserWindow`, `BrowserView`, `WebContentsView`, or `WebContents` instances to subscribe to the store. Can be empty or undefined. - `options`: Optional configuration object for customizing store integration ##### Returns: A `ReduxBridge` object with: - `subscribe(windows)`: Function to subscribe additional windows to the store updates. Returns an object with an `unsubscribe` method. - `unsubscribe(windows?)`: Function to unsubscribe windows from the store. When called without arguments, unsubscribes all windows. - `getSubscribedWindows()`: Function to get all currently subscribed window IDs. - `dispatch`: Function to dispatch actions to the store. - `destroy()`: Function to clean up resources used by the bridge. ##### Example: ```ts import { app, BrowserWindow } from 'electron'; import { createReduxBridge } from '@zubridge/electron/main'; import { store } from './redux-store'; const mainWindow = new BrowserWindow({ /* options */ }); // Create bridge with initial windows const { unsubscribe, subscribe, dispatch } = createReduxBridge(store, [mainWindow]); // Or create without windows and subscribe later const bridge = createReduxBridge(store); const subscription = bridge.subscribe([mainWindow]); // Dispatch actions from the main process dispatch({ type: 'INCREMENT' }); // Unsubscribe when quitting app.on('quit', unsubscribe); ``` #### `mainZustandBridge(store, windows, options?)` (Deprecated) **Deprecated:** This is now an alias for `createZustandBridge` and uses the new IPC channels. Please migrate to `createZustandBridge`. ##### Parameters and returns: Same as `createZustandBridge`. ### Dispatch APIs #### `createDispatch(store, options?)` Creates a dispatch function that can be used in the main process to dispatch actions to the store. This function supports both Zustand and Redux stores. ##### Parameters: - `store`: Either a Zustand store (`StoreApi<State>`) or Redux store (`Store<State>`) - `options?`: Optional configuration object - For Zustand stores: can include `handlers` or `reducer` options - For Redux stores: can include Redux-specific integration options ##### Returns: A function that can dispatch actions to the store. This dispatch function supports: - String action types with optional payload - Action objects with type and payload - Thunk functions for complex logic ##### Example: ```ts import { createDispatch } from '@zubridge/electron/main'; import { myStore } from './store'; // Create dispatch function export const dispatch = createDispatch(myStore); // Use the dispatch function dispatch('INCREMENT'); // Dispatch with a payload dispatch('SET_VALUE', 42); // Dispatch an action object dispatch({ type: 'SET_VALUE', payload: 42 }); // Dispatch a thunk function dispatch((getState, dispatch) => { const currentState = getState(); if (currentState.counter < 10) { dispatch('INCREMENT'); } }); ``` ##### Internal API: createDispatch with StateManager There's also an internal overload that accepts a state manager directly, but this is primarily for internal use by bridge implementations. ## Frontend (Renderer Process) APIs ### Preload Script APIs #### `preloadBridge()` Creates handlers for the renderer process to interact with the main process through the backend contract. ##### Returns: An object with a `handlers` property that should be exposed to the renderer process. ##### Example: ```ts // preload.js import { contextBridge } from 'electron'; import { preloadBridge } from '@zubridge/electron/preload'; const { handlers } = preloadBridge(); // Expose the handlers to the renderer process contextBridge.exposeInMainWorld('zubridge', handlers); ``` #### `preloadZustandBridge()` (Deprecated) **Deprecated:** This is now an alias for `preloadBridge` and uses the new IPC channels. Please migrate to `preloadBridge`. ##### Returns: Same as `preloadBridge`. ### Renderer Process Hooks #### `createUseStore<State>(customHandlers?)` Function that creates a hook to access the store state in the renderer process. ##### Parameters: - `customHandlers`: Optional custom handlers to use instead of `window.zubridge` - `State`: Type parameter representing your application state ##### Returns: A hook that can be used to select state from the store. ##### Example: ```ts // hooks/useStore.ts import { createUseStore } from '@zubridge/electron'; import type { AppState } from '../types'; export const useStore = createUseStore<AppState>(); // Component.tsx import { useStore } from './hooks/useStore'; function Counter() { const counter = useStore(state => state.counter); return <div>{counter}</div>; } ``` #### `useDispatch<State>(customHandlers?)` Hook to dispatch actions to the store from the renderer process. ##### Parameters: - `customHandlers`: Optional custom handlers to use instead of `window.zubridge` - `State`: Type parameter representing your application state - `ActionTypes`: Optional generic type parameter for typed action objects ##### Returns: A dispatch function that can be used to send actions to the main process. ##### Example: ```ts import { useDispatch } from '@zubridge/electron'; import type { AppState } from '../types'; function Counter() { const dispatch = useDispatch<AppState>(); // Dispatch a string action const handleIncrement = () => dispatch('INCREMENT'); // Dispatch an action with payload const handleSetCounter = (value) => dispatch('SET_COUNTER', value); // Dispatch an action object const handleCustomIncrement = (amount) => dispatch({ type: 'INCREMENT_BY', payload: amount }); // Dispatch with typed actions const typedDispatch = useDispatch<AppState, { 'SET_COUNTER': number }>(); const handleTypedSetCounter = (value: number) => typedDispatch({ type: 'SET_COUNTER', payload: value // Type checked to be a number }); // Dispatch a thunk for complex logic const handleFetchAndUpdate = () => dispatch(async (getState, dispatch) => { const response = await fetch('/api/counter'); const data = await response.json(); dispatch('SET_COUNTER', data.value); }); return ( <div> <button onClick={handleIncrement}>+1</button> <button onClick={() => handleSetCounter(0)}>Reset</button> <button onClick={() => handleCustomIncrement(5)}>+5</button> <button onClick={() => handleTypedSetCounter(10)}>Set to 10 (Typed)</button> <button onClick={handleFetchAndUpdate}>Fetch</button> </div> ); } ``` ## Type Definitions and Interfaces ### `StateManager<State>` Interface that defines the contract for state managers used with the bridge. Any state management solution can be integrated with the bridge system by implementing this interface. ```ts interface StateManager<State> { getState: () => State; subscribe: (listener: (state: State) => void) => () => void; processAction: (action: Action) => void; } ``` ### `CoreBridge` Interface for the bridge created by `createCoreBridge`. ```ts interface CoreBridge extends BaseBridge<number> { subscribe: (wrappers: WebContentsWrapper[]) => { unsubscribe: () => void }; unsubscribe: (wrappers?: WebContentsWrapper[]) => void; getSubscribedWindows: () => number[]; destroy: () => void; } ``` ### `ZustandBridge` Interface for the bridge created by `createZustandBridge`. ```ts interface ZustandBridge extends BackendBridge<number> { subscribe: (windows: WrapperOrWebContents[]) => { unsubscribe: () => void }; unsubscribe: (windows?: WrapperOrWebContents[]) => void; getSubscribedWindows: () => number[]; dispatch: Dispatch<S>; destroy: () => void; } ``` ### `ReduxBridge` Interface for the bridge created by `createReduxBridge`. ```ts interface ReduxBridge extends BackendBridge<number> { subscribe: (windows: WrapperOrWebContents[]) => { unsubscribe: () => void }; unsubscribe: (windows?: WrapperOrWebContents[]) => void; getSubscribedWindows: () => number[]; dispatch: Dispatch<S>; destroy: () => void; } ``` ### `BaseBridge<WindowId>` Base interface that all bridge implementations extend. ```ts interface BaseBridge<WindowId> { unsubscribe: (...args: any[]) => void; getSubscribedWindows: () => WindowId[]; } ``` ### `Action` Represents a Redux-style action with a type and optional payload. ```ts type Action<T extends string = string> = { type: T; payload: unknown; }; ``` ### `Thunk<State>` Represents a thunk function for handling asynchronous logic. ```ts type Thunk<State> = (getState: StoreApi<State>['getState'], dispatch: Dispatch<State>) => void; ``` ### `ZustandOptions<State>` Configuration options for the Zustand bridge. ```ts type ZustandOptions<State extends AnyState> = { handlers?: Record<string, Handler>; reducer?: RootReducer<State>; }; ``` ### `ReduxOptions<State>` Configuration options for the Redux bridge. ```ts type ReduxOptions<State extends AnyState> = { // Custom options for Redux integration }; ``` ### `WebContentsWrapper` Represents any Electron object that has WebContents. This includes BrowserWindow, BrowserView, and WebContentsView. ```ts type WrapperOrWebContents = WebContents | { webContents: WebContents; isDestroyed?: () => boolean }; ``` ### `Handlers<State>` Interface for the handlers exposed to the renderer process. ```ts interface Handlers<State extends AnyState> extends BaseHandler<State> { getState(): Promise<State>; subscribe(callback: (newState: State) => void): () => void; } ```