Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions scripts/findRefocus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import assert from 'node:assert/strict';
import test from 'node:test';

import { functionSource, readSource } from './sourceTree.js';

// #559: Cmd/Ctrl+F in the preview only ever set `findOpen = true`. Once the bar
// was open, clicking into the document moved focus out of the input and the
// shortcut became inert — the assignment writes the value the state already
// has, so the `$effect` that focuses on open never re-runs. The fix is an
// explicit focus call on the component, so the second press behaves like the
// first in every browser find bar: caret back in the field, previous query
// selected so typing replaces it.

const viewer = readSource('src/lib/MarkdownViewer.svelte');
const findBar = readSource('src/lib/components/FindBar.svelte');

test('the preview find shortcut focuses the bar rather than only opening it', () => {
const trigger = functionSource(viewer, 'triggerFindAction');
assert.match(trigger, /findBar\?\.focusInput\(\)/);
});

test('focusInput selects the previous query instead of clearing it', () => {
const focusInput = functionSource(findBar, 'focusInput');
assert.match(focusInput, /inputEl\?\.focus\(\)/);
assert.match(focusInput, /inputEl\?\.select\(\)/);
// Clearing here would defeat the point: the issue asks for the previous
// search to come back lit, not for an empty field.
assert.doesNotMatch(focusInput, /query\s*=/);
});

test('opening the bar and re-focusing it share one implementation', () => {
// Two copies would drift; the one that stopped selecting would be the one
// nobody re-reads.
assert.equal(findBar.match(/inputEl\?\.focus\(\)/g)?.length, 1);
});
10 changes: 9 additions & 1 deletion src/lib/MarkdownViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,11 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu
let liveMode = $state(false);

let findOpen = $state(false);
let findBar = $state<{ reapply: () => void; clearHighlights: () => void } | null>(null);
let findBar = $state<{
reapply: () => void;
clearHighlights: () => void;
focusInput: () => void;
} | null>(null);

// Decide where Cmd/Ctrl+F should land based on what's visible and where
// focus is. The in-window shortcut remains the canonical route on every
Expand All @@ -172,7 +176,11 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu
if (editorHasFocus || !previewVisible) {
editorPane?.triggerFind?.();
} else if (markdownBody) {
// Focus explicitly: once the bar is open, `findOpen = true` changes
// nothing, so a repeated shortcut after clicking into the document
// used to be swallowed (#559).
findOpen = true;
findBar?.focusInput();
}
}

Expand Down
19 changes: 15 additions & 4 deletions src/lib/components/FindBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,20 @@
}, DEBOUNCE_MS);
}

/**
* Put the caret back in the input with the previous query selected.
* Re-opening an already-open bar is a no-op — `open` never changes, so
* the effect below does not re-run — which left Cmd/Ctrl+F doing nothing
* once the user had clicked into the document (#559). Chrome, Firefox and
* VS Code all re-focus and re-select on a repeated find shortcut.
*/
export function focusInput() {
tick().then(() => {
inputEl?.focus();
inputEl?.select();
});
}

export function reapply() {
// Public hook for parent: call after the preview HTML is replaced
// so existing matches survive across re-renders.
Expand Down Expand Up @@ -324,10 +338,7 @@
return;
}
// On open, focus and select the input so typing replaces.
tick().then(() => {
inputEl?.focus();
inputEl?.select();
});
focusInput();
});

function handleKeydown(e: KeyboardEvent) {
Expand Down