Fix a selection issue where the CodeMirror is the first element in ProseMirror #78
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "main"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
When CodeMirror is the first element in ProseMirror, and you press Cmd+A in ProseMirror, the selection doesn’t get applied (or, rather, applies for a single frame). Instead, the CodeMirror element steals the focus.
Repro: CodeSandbox, demo:
https://github.com/user-attachments/assets/94557f2b-544e-461c-a0b8-05dd343df634
Cause: This seems to boil down to an interaction between ProseMirror’s selection logic and CodeMirror being contenteditable itself. When ProseMirror handles a Cmd+A event, it calls
domSel.collapse()before callingdomSel.expand():github.com/ProseMirror/prosemirror-view@76c7c47f03/src/viewdesc.ts (L464-L468)domSel.collapse()makes the selection collapse to a single point – at the beginning of the editorCodeMirror– so when that happens, the browser triggers the nativefocusevent on it.Solution: This PR attempts to fix the issue. The fix seems to work, but maybe there’s a better place for it, or some edge cases I don’t know about (I’m not very familiar with contenteditable gotchas).
(You can test this in CodeSandbox by swapping the
@codemirror/viewimport with@iamakulov/codemirror-view.)(The issue seems to be Chromium-only, btw.)
(And it seems to be new: in BrowserStack, I can only repro it starting Chrome 135+. Could be a browser bug, after all!)
Filed upstream: https://issues.chromium.org/issues/474377386. Thank you for being my rubber duck :D Let’s see what Chromium responds.
I find this patch somewhat scary. It is entirely possible for an editor to receive focus while the selection is elsewhere in the document, and this would cause the library to ignore such focus events entirely, allowing focus-tracking code to get confused.
It seems possible to work around this problem by adding any kind of inline element in front of the inner editor. Would adding a kludge like
<div style="position: absolute" aria-hidden=true>​</div>to the start of your CodeMirror node view work for you? It's not a general fix, but it's also less likely to cause additional issues.Oh, that’s clever!
That seems to solve Cmd+A (CodeSandbox), but it actually does cause more issues haha. With this workaround, Safari stops showing the Cmd+A highlight at all, and in both Chrome and Firefox, pressing ↑ gets the cursor stuck in the zero-width space div:
https://github.com/user-attachments/assets/b9a58e2e-9f9b-4bdc-81bd-c69a39065481
You can work around that by also adding a
contenteditable="true"on the div with the zero-width space. It’s still not great, tho (it leads to an extra cursor position in front of the code editor, and to Safari highlighting the whole page on Cmd+A). Meh :/Another thing I noticed: having CodeMirror first in ProseMirror also seems to break Cmd+C? (LMK if you’d like me to raise a separate issue for this.)
For example, in the original demo, if you Cmd+A in Safari (which works) and then Cmd+C, the only thing the browser copies is
// This CodeMirror block is firstinstead of the whole text. Chrome (with this PR’s fix) has a similar issue. (Firefox works fine.)The zero-width div workaround that you suggested solves it, but at the cost of the above issues.
Filed a fix for that: https://github.com/codemirror/view/pull/79
Ughhh, you're right. Nesting editable elements is a space where browsers do some really bizarre things.
I'm still worried that the fix is worse than the problem here. Even if we ignore that focus event, it seems the browser does put the actual focus on the inner editor, which is clearly not what you want. So maybe a kludge in ProseMirror that detects this situation right after selecting all, and forces the focus back to itself, is a more promising direction.
Looks like this is getting fixed upstream! https://issues.chromium.org/issues/474377386
I’ll close the PR 🙌
Pull request closed