ProseMirror / prosemirror

The ProseMirror WYSIWYM editor
http://prosemirror.net/
MIT License
7.61k stars 336 forks source link

`posAtCoords` incorrect for inline, atomic custom element (using Lit) #1369

Closed eric-burel closed 1 year ago

eric-burel commented 1 year ago

Hi,

I am experiencing issues with when computing the position of atomic inline elements, that are rendered using a web component.

I couldn't yet build a minimal reproduction, so sorry in advance for the messy ticket. I'll share all info that could be relevant.

First the setup: I am trying to create pills that can be dragged within the text editor, but also outside of it. I am using a custom element for the rendering, it also let me shove JSON data within the DragEvent.

Schema:

inline-pill: {
        // this prevents user to change the pivot value
        atom: true,
        // allow to drag without a first click
        draggable: true,
        group: "inline",
        inline: true,
        selectable: true,
        toDOM: () => ["my-button", {}, "foobar"]
}

Web component (using Lit):

class DummyButton extends LitElement {
    render() {
        return html`<button><slot></slot></button>`
    }
}
customElements.define("my-button", DummyButton)

Resulting DOM: image

The bug: The issue stems from posFromElement, here is the code for the record:

function posFromElement(view, elt, coords) {
    let { node, offset } = findOffsetInNode(elt, coords), bias = -1;
    if (node.nodeType == 1 && !node.firstChild) {
        console.log("no first child", node)
        let rect = node.getBoundingClientRect();
        bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
    }
    return view.docView.posFromDOM(node, offset, bias);
}

When clicking on the blank space of the button, the computed position is 13, while it should be 12. The node does have a firstChild, so bias stays "-1". image

When clicking on the text, the computed position is 12, which is correct. image

A variation of this bug: I experience a variation of this issue, where the element has no firstChild (not sure why, it does have child but perhaps hidden in the shadow DOM?). The bug is slightly different, in this case a "bias" is computed and the result is that:

I have started a Codesandbox to reproduce but couldn't yet obtain the same result.

This seems to affect specifically Lit elements, whether they make use of a tag or not.

Related to: https://github.com/ProseMirror/prosemirror/issues/1348

eric-burel commented 1 year ago

Closing as I am close to figuring a palliative: it turns out that despite posAtCoords being one char after the position I want, the "MouseDown" utility (sadly unexposed) used by the default drag handler is able to compute the actual position I want.

I can duplicate this code in my own app, however I will try to think about a better solution: the underlying issue is that I want to keep most of the default drag and drop logic, but tweak the last part that sets some "text/plain" content and instead use a custom data type + custom commands to handle this data type.

It seems that "pos" is what we expect to be, the position nearest to the mouse event (so it can be the position after the node I've clicked). I should instead use "inside". The behaviour I observe is still slightly surprising, but not a blocker.