codeBlock with white-space: pre fails to set selection, only under very particular circumstances

I made a quick test plugin and it logs out the expected positions - they’re just not being set. I don’t really know what to make of the issue. What’s more - it only affects our editor when it’s nested in our app and not otherwise - but I already stripped away virtually everything about our app from the DOM to the CSS and the issue persists.

Conditions for reproduction:

  • white-space: pre
  • Horizontal scrollbar enabled on codeBlock
  • Some unknown secret sauce

I wonder if anyone has any ideas what could be the cause of this very strange bug?

I tried poking around in the mousedown handler in prosemirror-view but I couldn’t find anything going wrong there either. Everything looks correct to me, except in the end the selection is not set.

Reverting to white-space: pre-wrap “fixes” it, and more interestingly, dragging the mouse 1px before lifting the mouse button correctly sets the position in the editor, even though plain clicking does not.

new Plugin({
  props: {
    handleDOMEvents: {
      mousedown: (view, evt) => {
        const pos = view.posAtCoords({
          left: evt.clientX,
          top: evt.clientY,
        });

        console.warn(pos);
      },
    },
  }
})

I know this seems like a non-issue or project-specific problem, but I do believe there’s something a bit more generalizable going on here.

I’ve spent about 3 entire workdays on this now and ruled out literally everything I can conceive of. Even when the editor is the sole DOM element (besides its contents) this issue persists. I upgraded our Electron version to match the working Chromium version, but still in Electron ProseMirror exhibits this inability to click inside of the codeBlock. Like I said, the mousedown in a plugin yields the correct pos in the editor, but it’s not set, so I really cannot fathom what’s wrong.

After much investigation, it certainly seems to be an issue with ProseMirror to me, however idiosyncratic its presentation.

If I set a expanded selection in a non-problem area and then drag into the problem codeblock in a separate click, instead of selecting only the text in the codeblock, it expands the original selection into the codeblock, which to me is more evidence something is going awry in ProseMirror here.

I removed all non-browser CSS except the white-space and overflow-x styles necessary to provoke the bug. I remove the entire DOM except the editor and the full HTML on the page is like below - but still the issue persists. No issue in Chrome 124.0.6367.201, but the problem persists in Electron 30.0.6, which is based on Chromium 124.0.6367.207 - and it also affected all previous Electron versions. It’s utterly baffling.

DOM:

<html lang="en-US">

<head>
    <script defer="" src="http://localhost:2324/dist/renderer.dev.js"></script>
</head>

<body>
    <div id="root" style="">
        <div id="editor" class="editorDiv" spellcheck="true">
            <div contenteditable="true" translate="no" class="tiptap ProseMirror" tabindex="0">
                <p class="within-selection">dfgdfg dfgddddfg</p>
                <p><br class="ProseMirror-trailingBreak"></p>
                <div class="react-renderer node-codeBlock">
                    <div data-node-view-wrapper="" style="white-space: normal;">
                        <pre spellcheck="false"><code as="code" class="code-block language-plaintext " data-node-view-content=""><div style="white-space: inherit;">sdfsdfsdfsdf
ssdffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffff</div></code></pre>
                    </div>
                </div>
                <p><br class="ProseMirror-trailingBreak"></p>
            </div>
        </div>
    </div>
</body>

</html>

Styles (besides browser and prosemirror-view’s included styles):

pre {
  overflow-x: auto;
}
pre, pre code {
  white-space: pre;
}

I’d be happy to try to trace down what’s failing in ProseMirror itself if I had any idea where to begin. Everything looks fine to me, but it’s not like I really know what the workflow is supposed to be.

@marijn I finally pared my app down enough to run it directly in the browser. The browser exhibits no problems, yet in Electron we cannot select inside the codeblock still with a singleClick. There must be a bug somewhere, but I haven’t enough of a clue where to track it down and file a meaningful bug report.

Are there any hints you can provide?

I apologize for the lengthy explanations above; I don’t know how else to more succinctly articulate this strangest of issues.


PS: My example above uses TipTap’s React NodeView renderer, but the issue occurs even if we use a plain NodeView or register no NodeView.

Affects Electron 29.3 but not the version of Chrome that is based on the same underlying version of Chromium.

Apparently does not affect Electron 28.x.

I haven’t pinned it down more narrowly. This is truly one of the most baffling bugs I’ve ever seen.

This does sound very much like browser misbehavior. Often the only way around stuff like this is to change your setup to avoid the bug, and hope the browser eventually fixes it.

1 Like

Thanks very much for your reply @marijn.

I haven’t much experience reporting browser bugs, and certainly not highly esoteric ones. I wonder if you have any advice for how I might try to get this properly reported and resolved.

For example, it’s not present in Chrome, so I guess I shouldn’t be considering this a Chromium bug? So then I should be talking to the Electron team instead? Or do you think it’s still possible this is actually in Chromium somehow?

Sorry I know this is outside the scope of the forums now, but if you have any advice I’d value it greatly.

Since older version off Electron are insecure I seem quite stuck on this. I could try to re-implement ProseMirror’s handling of cursor selections, and I have tried, but that’s proved quite difficult to handle the edge cases.

Is there anywhere you might suspect prosemirror-view code could be failing that I could investigate further? The fact that ProseMirror can detect the clicked coordinate is so very strange.

I think I’m on the right path to pinpointing the issue now, although no way to know if I’ll ever get it fixed. Thanks very much for all the help.