mirror of
https://github.com/stablyai/orca
synced 2026-04-21 14:17:16 +00:00
fix(browser): debounce find-in-page query to stop per-keystroke flash (#836)
* fix(browser): debounce find-in-page query to stop per-keystroke flash Why: findInPage re-highlights the active match on every call, which flashed as the user typed. Debounce (200ms) so the highlight only re-runs once typing settles. Enter still uses the live query for immediate next/previous nav. * fix(browser): auto-select top suggestion, preserve address-bar typing - Top history suggestion is auto-selected so Enter navigates to the best match without an extra ArrowDown keypress. - URL syncs from the store and webview navigation events no longer clobber the address bar while the user is actively typing in it. Previously, opening a fresh tab and starting to type could be overridden when the configured default URL (e.g. google.com) finished resolving.
This commit is contained in:
parent
bd52741efc
commit
7734cf9bef
3 changed files with 33 additions and 6 deletions
|
|
@ -162,8 +162,11 @@ export default function BrowserAddressBar({
|
|||
}
|
||||
}, [open, suggestions.length])
|
||||
|
||||
// Why: auto-select the top suggestion so Enter navigates to the best match
|
||||
// without an extra ArrowDown. Fall back to clearing selection when nothing
|
||||
// matches so stale highlights don't persist.
|
||||
useEffect(() => {
|
||||
setSelectedValue('')
|
||||
setSelectedValue(suggestions[0]?.url ?? '')
|
||||
}, [suggestions])
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -15,9 +15,19 @@ export default function BrowserFind({
|
|||
}: BrowserFindProps): React.JSX.Element | null {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const [query, setQuery] = useState('')
|
||||
const [debouncedQuery, setDebouncedQuery] = useState('')
|
||||
const [activeMatch, setActiveMatch] = useState(0)
|
||||
const [totalMatches, setTotalMatches] = useState(0)
|
||||
|
||||
// Why: findInPage re-highlights the active match on every call, which causes
|
||||
// a visible flash as the user types. Debounce to only re-run once typing
|
||||
// settles. Enter (findNext/findPrevious) still uses the live `query` so
|
||||
// explicit navigation is immediate.
|
||||
useEffect(() => {
|
||||
const id = setTimeout(() => setDebouncedQuery(query), 200)
|
||||
return () => clearTimeout(id)
|
||||
}, [query])
|
||||
|
||||
const safeFindInPage = useCallback(
|
||||
(text: string, opts?: Electron.FindInPageOptions): void => {
|
||||
const webview = webviewRef.current
|
||||
|
|
@ -70,16 +80,16 @@ export default function BrowserFind({
|
|||
}, [isOpen, safeStopFindInPage])
|
||||
|
||||
useEffect(() => {
|
||||
if (!query) {
|
||||
if (!debouncedQuery) {
|
||||
safeStopFindInPage()
|
||||
setActiveMatch(0)
|
||||
setTotalMatches(0)
|
||||
return
|
||||
}
|
||||
if (isOpen) {
|
||||
safeFindInPage(query)
|
||||
safeFindInPage(debouncedQuery)
|
||||
}
|
||||
}, [query, isOpen, safeFindInPage, safeStopFindInPage])
|
||||
}, [debouncedQuery, isOpen, safeFindInPage, safeStopFindInPage])
|
||||
|
||||
// Why: this effect captures `webviewRef.current` into a local variable, so
|
||||
// if the webview element were replaced while `isOpen` stays true the listener
|
||||
|
|
|
|||
|
|
@ -505,6 +505,13 @@ function BrowserPagePane({
|
|||
}, [browserTab.id, browserTab.url])
|
||||
|
||||
useEffect(() => {
|
||||
// Why: if the user is actively typing in the address bar (focused), do not
|
||||
// clobber their in-progress query when an async URL update lands (e.g., the
|
||||
// configured default URL resolving after a new tab opens). Syncing will
|
||||
// resume on the next legitimate URL change after the input loses focus.
|
||||
if (document.activeElement === addressBarInputRef.current) {
|
||||
return
|
||||
}
|
||||
setAddressBarValue(toDisplayUrl(browserTab.url))
|
||||
}, [browserTab.url])
|
||||
|
||||
|
|
@ -1056,7 +1063,11 @@ function BrowserPagePane({
|
|||
activeLoadFailureRef.current = null
|
||||
lastKnownWebviewUrlRef.current = normalizeBrowserNavigationUrl(currentUrl) ?? currentUrl
|
||||
rememberLiveBrowserUrl(browserTab.id, currentUrl)
|
||||
setAddressBarValue(toDisplayUrl(currentUrl))
|
||||
// Why: don't overwrite in-progress typing. See comment on the
|
||||
// browserTab.url sync effect above.
|
||||
if (document.activeElement !== addressBarInputRef.current) {
|
||||
setAddressBarValue(toDisplayUrl(currentUrl))
|
||||
}
|
||||
onSetUrlRef.current(browserTab.id, currentUrl)
|
||||
if (keepAddressBarFocusRef.current && currentUrl === ORCA_BROWSER_BLANK_URL) {
|
||||
focusAddressBarNow()
|
||||
|
|
@ -1083,7 +1094,10 @@ function BrowserPagePane({
|
|||
}
|
||||
lastKnownWebviewUrlRef.current = normalizeBrowserNavigationUrl(currentUrl) ?? currentUrl
|
||||
rememberLiveBrowserUrl(browserTab.id, currentUrl)
|
||||
setAddressBarValue(toDisplayUrl(currentUrl))
|
||||
// Why: don't overwrite in-progress typing (see above).
|
||||
if (document.activeElement !== addressBarInputRef.current) {
|
||||
setAddressBarValue(toDisplayUrl(currentUrl))
|
||||
}
|
||||
onSetUrlRef.current(browserTab.id, currentUrl)
|
||||
onUpdatePageStateRef.current(browserTab.id, {
|
||||
title: webview.getTitle() || currentUrl,
|
||||
|
|
|
|||
Loading…
Reference in a new issue