Files
orca/src/preload/browser-find-subscriptions.ts
T
5165cd1e19 fix(browser): scope Cmd/Ctrl+F find to the focused split (#11348) (#11351)
* fix(browser): scope Cmd/Ctrl+F find to the focused split (#11348)

The browser pane's renderer-path Find handler is a window-global
capture-phase keydown listener, but it armed on `isActive` (the active
tab within its own group) rather than on whether its split holds focus.
In a terminal+browser split, the browser was therefore `isActive` even
while the terminal held keyboard focus, so it swallowed Cmd/Ctrl+F and
opened find-in-page in the browser instead of find-in-terminal.

Thread a focused-split signal (`isFocused`) from BrowserPaneOverlayLayer
— derived from `activeGroupIdByWorktree` — down to the Find handler and
gate the listener on it. This mirrors how terminal leaves already gate
global shortcuts via `focusedGroupId` in TabGroupSplitLayout. Floating
browser panels omit the prop and fall back to `isActive`, preserving
their behavior. The IPC path (webview guest focused) is unchanged; it
only fires when the guest genuinely has focus.

Not platform-specific: the chord resolves through `keybindingMatchesAction`
(Mod -> metaKey on macOS, ctrlKey elsewhere), so the same path is fixed on
macOS, Linux, and Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(browser): preserve Find before split focus settles

* fix(browser): handle stale focused split IDs

* fix(browser): route guest Find to source page

* test(browser): wait for split address bar

* test(browser): focus split before Find routing

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-30 14:17:26 -07:00

52 lines
1.5 KiB
TypeScript

import { isBrowserFindSource, type BrowserFindSource } from '../shared/browser-find-source'
type BrowserFindCallback = () => void
export function createBrowserFindSubscriptions(): {
dispatch: (source: unknown) => void
subscribe: (source: BrowserFindSource, callback: BrowserFindCallback) => () => void
} {
const callbacksByWorkspace = new Map<string, Map<string, Set<BrowserFindCallback>>>()
return {
dispatch: (source) => {
if (!isBrowserFindSource(source)) {
return
}
const callbacks = callbacksByWorkspace
.get(source.browserWorkspaceId)
?.get(source.browserPageId)
if (!callbacks) {
return
}
for (const callback of callbacks) {
callback()
}
},
subscribe: (source, callback) => {
let callbacksByPage = callbacksByWorkspace.get(source.browserWorkspaceId)
if (!callbacksByPage) {
callbacksByPage = new Map()
callbacksByWorkspace.set(source.browserWorkspaceId, callbacksByPage)
}
let callbacks = callbacksByPage.get(source.browserPageId)
if (!callbacks) {
callbacks = new Set()
callbacksByPage.set(source.browserPageId, callbacks)
}
callbacks.add(callback)
return () => {
callbacks.delete(callback)
if (callbacks.size > 0) {
return
}
callbacksByPage.delete(source.browserPageId)
if (callbacksByPage.size === 0) {
callbacksByWorkspace.delete(source.browserWorkspaceId)
}
}
}
}
}