diff --git a/docs/getting-started.md b/docs/getting-started.md index 9e97cdb..90c5e66 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -22,12 +22,15 @@ store = createStore()(() => initialState); #### Initialize Bridge in Main process -In the main process, the bridge needs your store and an array of BrowserWindow objects for your app, so for a single window application: +In the main process, the bridge needs your store and an array of window or view objects for your app. `BrowserWindow`, `BrowserView` and `WebContentsView` objects are supported. + +So, for a single window application: ```ts import { mainZustandBridge } from 'zutron/main'; // create mainWindow +const mainWindow = new BrowserWindow(windowConfig); const { unsubscribe } = mainZustandBridge(store, [mainWindow]); @@ -51,7 +54,7 @@ contextBridge.exposeInMainWorld('zutron', handlers); #### Create hook in Renderer process -Finally, in the renderer process you will need to create the useStore hook: +Finally, in the renderer process you will need to create the `useStore` hook: `/renderer/hooks/useStore.ts` diff --git a/packages/zutron/src/main.ts b/packages/zutron/src/main.ts index e6cf494..f69c1ee 100644 --- a/packages/zutron/src/main.ts +++ b/packages/zutron/src/main.ts @@ -1,11 +1,11 @@ -import { type BrowserWindow, ipcMain, type IpcMainEvent } from 'electron'; +import { type BrowserWindow, type WebContentsView, type BrowserView, ipcMain, type IpcMainEvent } from 'electron'; import type { StoreApi } from 'zustand'; import type { Action, AnyState, Handler, MainZustandBridgeOpts, Thunk } from './index.js'; export type MainZustandBridge = >( store: Store, - windows: BrowserWindow[], + windows: (BrowserWindow | WebContentsView | BrowserView)[], options?: MainZustandBridgeOpts, ) => { unsubscribe: () => void }; @@ -55,7 +55,7 @@ export const mainZustandBridge: MainZustandBridge = (store, windows, options) => const dispatch = createDispatch(store, options); ipcMain.on('subscribe', async (state: unknown) => { for (const window of windows) { - if (window?.isDestroyed()) { + if (window.webContents.isDestroyed()) { break; } window?.webContents?.send('subscribe', sanitizeState(state as AnyState)); diff --git a/packages/zutron/test/main.spec.ts b/packages/zutron/test/main.spec.ts index 9a6a066..d85a2f2 100644 --- a/packages/zutron/test/main.spec.ts +++ b/packages/zutron/test/main.spec.ts @@ -107,7 +107,7 @@ describe('createDispatch', () => { describe('mainZustandBridge', () => { let options: { handlers?: Record }; let mockStore: Record; - let mockWindows: Record[]; + let mockWindows: Record[]; beforeEach(() => { mockStore = { @@ -115,7 +115,7 @@ describe('mainZustandBridge', () => { setState: vi.fn(), subscribe: vi.fn(), }; - mockWindows = [{ isDestroyed: vi.fn().mockReturnValue(false), webContents: { send: vi.fn() } }]; + mockWindows = [{ webContents: { send: vi.fn(), isDestroyed: vi.fn().mockReturnValue(false) } }]; options = {}; }); @@ -174,8 +174,8 @@ describe('mainZustandBridge', () => { it('should handle multiple windows', async () => { mockWindows = [ - { isDestroyed: vi.fn().mockReturnValue(false), webContents: { send: vi.fn() } }, - { isDestroyed: vi.fn().mockReturnValue(false), webContents: { send: vi.fn() } }, + { webContents: { send: vi.fn(), isDestroyed: vi.fn().mockReturnValue(false) } }, + { webContents: { send: vi.fn(), isDestroyed: vi.fn().mockReturnValue(false) } }, ]; const browserWindows = mockWindows as unknown as Electron.BrowserWindow[]; @@ -191,8 +191,8 @@ describe('mainZustandBridge', () => { it('should handle destroyed windows', async () => { mockWindows = [ - { isDestroyed: vi.fn().mockReturnValue(false), webContents: { send: vi.fn() } }, - { isDestroyed: vi.fn().mockReturnValue(true), webContents: { send: vi.fn() } }, + { webContents: { send: vi.fn(), isDestroyed: vi.fn().mockReturnValue(false) } }, + { webContents: { send: vi.fn(), isDestroyed: vi.fn().mockReturnValue(true) } }, ]; const browserWindows = mockWindows as unknown as Electron.BrowserWindow[];