Keep focus in Orca when parking webviews (#2362)
- Move focus back to the renderer before detaching a focused webview, including when it is parked rather than destroyed. - Cover focused, descendant-focused, and unfocused detach cases.
This commit is contained in:
parent
49b504dc45
commit
b6f2b6eed4
|
|
@ -75,6 +75,7 @@ import {
|
|||
destroyPersistentWebview,
|
||||
getHiddenContainer,
|
||||
MAX_PARKED_WEBVIEWS,
|
||||
moveFocusToRendererBeforeWebviewDetach,
|
||||
parkedAtByTabId,
|
||||
registerPersistentWebview,
|
||||
registeredWebContentsIds,
|
||||
|
|
@ -3571,6 +3572,7 @@ function BrowserPagePane({
|
|||
}
|
||||
|
||||
if (webviewRegistry.get(browserTab.id) === webview) {
|
||||
moveFocusToRendererBeforeWebviewDetach(webview)
|
||||
getHiddenContainer().appendChild(webview)
|
||||
parkedAtByTabId.set(browserTab.id, Date.now())
|
||||
evictParkedWebviews(browserTab.id)
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ type ListenerRecord = {
|
|||
options?: boolean | AddEventListenerOptions
|
||||
}
|
||||
|
||||
function createWebview(): Electron.WebviewTag {
|
||||
function createWebview(overrides: Partial<Electron.WebviewTag> = {}): Electron.WebviewTag {
|
||||
return {
|
||||
style: {},
|
||||
blur: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
contains: vi.fn(() => false)
|
||||
contains: vi.fn(() => false),
|
||||
...overrides
|
||||
} as unknown as Electron.WebviewTag
|
||||
}
|
||||
|
||||
|
|
@ -96,4 +98,39 @@ describe('webview registry drag listeners', () => {
|
|||
|
||||
expect(addedListeners).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('moves focus back to the renderer before detaching the focused webview', async () => {
|
||||
const { moveFocusToRendererBeforeWebviewDetach } = await import('./webview-registry')
|
||||
const webview = createWebview()
|
||||
vi.stubGlobal('document', { activeElement: webview })
|
||||
|
||||
moveFocusToRendererBeforeWebviewDetach(webview)
|
||||
|
||||
expect(webview.blur).toHaveBeenCalledTimes(1)
|
||||
expect(window.focus).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('moves focus back to the renderer before detaching a webview that contains focus', async () => {
|
||||
const { moveFocusToRendererBeforeWebviewDetach } = await import('./webview-registry')
|
||||
const activeElement = { blur: vi.fn() } as unknown as HTMLElement
|
||||
const webview = createWebview({ contains: vi.fn(() => true) })
|
||||
vi.stubGlobal('document', { activeElement })
|
||||
|
||||
moveFocusToRendererBeforeWebviewDetach(webview)
|
||||
|
||||
expect(activeElement.blur).toHaveBeenCalledTimes(1)
|
||||
expect(window.focus).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('leaves focus alone before detaching an unfocused webview', async () => {
|
||||
const { moveFocusToRendererBeforeWebviewDetach } = await import('./webview-registry')
|
||||
const activeElement = { blur: vi.fn() } as unknown as HTMLElement
|
||||
const webview = createWebview()
|
||||
vi.stubGlobal('document', { activeElement })
|
||||
|
||||
moveFocusToRendererBeforeWebviewDetach(webview)
|
||||
|
||||
expect(activeElement.blur).not.toHaveBeenCalled()
|
||||
expect(window.focus).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -100,6 +100,17 @@ export function unregisterPersistentWebview(browserTabId: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function moveFocusToRendererBeforeWebviewDetach(webview: Electron.WebviewTag): void {
|
||||
// Why: if this webview currently owns focus, removing it lets macOS hand
|
||||
// activation back to the previously-active app (Slack, etc.) because the
|
||||
// focused webContents is gone with no replacement. Move focus back into the
|
||||
// main renderer first so Electron keeps focus inside the Orca window.
|
||||
if (webview === document.activeElement || webview.contains(document.activeElement)) {
|
||||
;(document.activeElement as HTMLElement | null)?.blur?.()
|
||||
window.focus()
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyPersistentWebview(browserTabId: string): void {
|
||||
const webview = webviewRegistry.get(browserTabId)
|
||||
if (!webview) {
|
||||
|
|
@ -109,14 +120,7 @@ export function destroyPersistentWebview(browserTabId: string): void {
|
|||
return
|
||||
}
|
||||
void window.api.browser.unregisterGuest({ browserPageId: browserTabId })
|
||||
// Why: if this webview currently owns focus, removing it lets macOS hand
|
||||
// activation back to the previously-active app (Slack, etc.) because the
|
||||
// focused webContents is gone with no replacement. Move focus back into the
|
||||
// main renderer first so Electron keeps focus inside the Orca window.
|
||||
if (webview === document.activeElement || webview.contains(document.activeElement)) {
|
||||
;(document.activeElement as HTMLElement | null)?.blur?.()
|
||||
window.focus()
|
||||
}
|
||||
moveFocusToRendererBeforeWebviewDetach(webview)
|
||||
webview.remove()
|
||||
unregisterPersistentWebview(browserTabId)
|
||||
registeredWebContentsIds.delete(browserTabId)
|
||||
|
|
|
|||
Loading…
Reference in New Issue