Type dictated words at the note's cursor instead of the bottom - #192
Merged
Merged
Conversation
Clicking the mic moves focus off the editor before its click handler runs, so the "is the editor focused?" check used to capture the cursor always failed and every dictated chunk was appended to the end of the note. Even when it did catch the cursor, it started a new paragraph after the cursor's block rather than typing at the cursor. ProseMirror keeps its selection when the editor blurs, so dictation now types straight into that selection (collapsing a range to its end, with spacing to neighbouring words), leaving the caret after the words so each chunk continues in order. This works however focus moves, so the mic button keeps focus for Enter/Space toggling, and it follows the cursor if the user clicks elsewhere mid-session. With no cursor placed in the note (tracked via the editor wrapper's focus, reset when a note is loaded) the words go at the bottom as before, now filling the trailing empty line instead of leaving a gap. prosemirror-state/-model are declared as direct dependencies at the versions already installed through BlockNote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Go397yGvJqhvMQhc53Q46
davior
marked this pull request as ready for review
September 26, 2026 18:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When dictating into a note, the words always appeared at the bottom of the note, even if the cursor had been placed somewhere in it.
Root cause: clicking the mic button moves focus off the editor on
mousedown, beforeonClickruns. TheonMouseDown={e => e.preventDefault()}that used to prevent this was removed so the mic button could keep focus for Enter/Space toggling. As a resulthandleDictationToggle'seditor.isFocused()check was always false, the cursor anchor was alwaysnull, and every chunk fell through to "append at end of note". And when the anchor was captured, it inserted a new paragraph after the cursor's block rather than typing at the cursor.Fix
ProseMirror keeps its selection when the editor blurs, so dictation now types straight into that selection. This doesn't depend on which element has focus.
utils/dictationInsert.ts:insertDictationAtSelection(tr, text)inserts at the selection like typing does:falsewhen the selection can't hold text (image block, select-all), so the caller can fall back.EditorView.tsx:editorHasCursorReftracks whether the user has put the cursor in the note. It's set from the editor wrapper'sonFocusand reset when a note is loaded into the editor.handleDictationToggle, and the dictation-onlyanchorBlockIdparameter ofinsertBlocksAtCursor.prosemirror-stateandprosemirror-modelare declared as direct dependencies at the versions already installed through BlockNote (1.4.4 / 1.25.9). The lockfile resolution is unchanged andvite.config.tsalready dedupes them.Testing
npx tsc --noEmit✅,npm run build✅,npx vitest run: 155 passed, including 12 new unit tests for the insertion helper.Hello there my good friend worldHello big wide world, caret left beforeworldAlso checked that the dictated text autosaves: the server copy contained
Hello world and goodbye.🤖 Generated with Claude Code
https://claude.ai/code/session_017Go397yGvJqhvMQhc53Q46
Generated by Claude Code