also looking at this
feat: add Linux and Windows named-window routing
#325
29 files
+2250
-200
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -140,6 +140,24 @@ describe('typed window-handle routing', () => { | ||
| 140 | 140 | expect(created.id).toBe(id) |
| 141 | 141 | }) |
| 142 | 142 | |
| 143 | it('uses the injected window envelope in WebView2 as well as WebKit', async () => { | |
| 144 | const host = globalThis.window as unknown as { | |
| 145 | webkit?: unknown | |
| 146 | chrome?: { webview: { postMessage: () => void } } | |
| 147 | } | |
| 148 | Reflect.deleteProperty(host, 'webkit') | |
| 149 | host.chrome = { webview: { postMessage: () => {} } } | |
| 150 | const id = fixtureId('webview2') | |
| 151 | const created = await windowManager.create({ id, html: '<h1>Windows</h1>' }) | |
| 152 | await created.setTitle('Windows') | |
| 153 | callResult = id | |
| 154 | ||
| 155 | expect(open).toHaveBeenCalledWith({ id, html: '<h1>Windows</h1>' }) | |
| 156 | expect(call).toHaveBeenCalledWith('setTitle', { title: 'Windows' }, id) | |
| 157 | expect(await windowManager.getFocused()).toBe(created) | |
| 158 | expect(call).toHaveBeenCalledWith('getFocused', undefined, 'main') | |
| 159 | }) | |
| 160 | ||
| 143 | 161 | it('refuses the local main alias before opening a child window', async () => { |
| 144 | 162 | await expect(windowManager.create({ id: 'main', html: '<h1>Orphan</h1>' })) |
| 145 | 163 | .rejects.toThrow('reserved for the current window') |
| @@ -5,7 +5,7 @@ | ||
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | 7 | import { getBridge } from '../bridge/core.js' |
| 8 | import { isWebKitHost } from '../bridge/webkit-pending.js' | |
| 8 | import { isDesktopWebViewHost } from '../bridge/webkit-pending.js' | |
| 9 | 9 | |
| 10 | 10 | interface InjectedWindowBridge { |
| 11 | 11 | _call<T>(action: string, data: Record<string, any> | undefined, windowId: string): Promise<T> |
| @@ -740,7 +740,7 @@ export class Window { | ||
| 740 | 740 | // ========================================================================== |
| 741 | 741 | |
| 742 | 742 | private async _call<T = void>(action: string, data?: Record<string, any>): Promise<T> { |
| 743 | if (isWebKitHost()) { | |
| 743 | if (isDesktopWebViewHost()) { | |
| 744 | 744 | const injected = getInjectedWindowBridge() |
| 745 | 745 | if (!injected?._call) { |
| 746 | 746 | throw new Error('Craft window bridge is unavailable') |
| @@ -813,7 +813,7 @@ class WindowManager { | ||
| 813 | 813 | } |
| 814 | 814 | const existing = this._windows.get(id) |
| 815 | 815 | |
| 816 | if (isWebKitHost()) { | |
| 816 | if (isDesktopWebViewHost()) { | |
| 817 | 817 | const injected = getInjectedWindowBridge() |
| 818 | 818 | if (!injected?.open) { |
| 819 | 819 | throw new Error('Craft window bridge is unavailable') |
| @@ -844,7 +844,7 @@ class WindowManager { | ||
| 844 | 844 | * Get focused window |
| 845 | 845 | */ |
| 846 | 846 | async getFocused(): Promise<Window | null> { |
| 847 | if (isWebKitHost()) { | |
| 847 | if (isDesktopWebViewHost()) { | |
| 848 | 848 | const injected = getInjectedWindowBridge() |
| 849 | 849 | if (!injected?._call) { |
| 850 | 850 | throw new Error('Craft window bridge is unavailable') |
| @@ -73,6 +73,14 @@ export function isWebKitHost(): boolean { | ||
| 73 | 73 | return typeof window !== 'undefined' && !!window.webkit?.messageHandlers?.craft |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | /** Desktop window handles use the injected Craft envelope on both WebKit and WebView2. */ | |
| 77 | export function isDesktopWebViewHost(): boolean { | |
| 78 | if (isWebKitHost()) return true | |
| 79 | if (typeof window === 'undefined') return false | |
| 80 | const host = window as Window & { chrome?: { webview?: { postMessage?: (message: unknown) => void } } } | |
| 81 | return typeof host.chrome?.webview?.postMessage === 'function' | |
| 82 | } | |
| 83 | ||
| 76 | 84 | /** |
| 77 | 85 | * Send a fire-and-forget message into the WKWebView host. Returns true if |
| 78 | 86 | * the message was delivered, false otherwise. |