Skip to content

Bug: Pasting in block results in pasting the content twice in Firefox #7071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
GermanJablo opened this issue Jan 20, 2025 · 7 comments · Fixed by #7354
Closed

Bug: Pasting in block results in pasting the content twice in Firefox #7071

GermanJablo opened this issue Jan 20, 2025 · 7 comments · Fixed by #7354

Comments

@GermanJablo
Copy link
Contributor

Originally reported here: payloadcms/payload#10634

Lexical version: 0.23.1

Steps To Reproduce

  1. open https://playground.lexical.dev/ in Firefox
  2. Insert a poll component
  3. When the selection is outside the poll, click on one of the inputs and paste something
  4. The content will be pasted in duplicate inside and outside the poll
decoratorselection.mov

Apparently it's a selection issue. There is no generic logic that selects any decoratorNode when clicked, but this is done only on some specific decoratorNodes.

The current behavior

The content will be pasted in duplicate inside and outside the poll

The expected behavior

The content should be pasted only inside the poll

I have a fix on the way.

@etrepum
Copy link
Collaborator

etrepum commented Jan 21, 2025

I think the best solution to this is probably something else. If it was merely a decorator node selection issue then the issue wouldn't be platform specific. It seems more like there's something wrong with the logic that determines whether to handle an event in a contentEditable=false or not, because also in chrome cmd-A is being captured while that input is focused but that probably shouldn't be the case. Firefox doesn't prevent cmd-A from going to the poll input. The review app in #7072 doesn't fix any of that.

@GermanJablo
Copy link
Contributor Author

I would describe it as a selection problem + something else (which makes it platform specific).

The Lexical selection still being outside the decorator when the cursor is inside is a bug regardless of whether there is something wrong with the events on contentEditable.

This is just one of the possible side effects that can occur. The one described at the end of #6632 is another. Who knows how many more there may be.

@etrepum
Copy link
Collaborator

etrepum commented Jan 21, 2025

There multiple scenarios where the lexical selection doesn't match the browser's selection by design, otherwise the SelectionAlwaysOnDisplay plug-in would have no purpose. I'm sure that some coherent solution exists but we should come up with something that solves all of the known quirks especially if we need to break compatibility to fix it.

Not having done much investigation here but knowing the internals a bit perhaps a closer solution would be to by default ignore all events with targets that are inside decorators (some of this already happens, e.g. $isSelectionCapturedInDecorator and isSelectionCapturedInDecoratorInput - these are not really relevant to the lexical selection per se as the inputs are DOM nodes) and have a way for them to explicitly forward them up to the parent editor. Maybe this could be done with a a command, possibly combined with a method on the decorator that toggles whether this happens by default or not. Selection might also have similar treatment particularly around keyboard navigation - not all decorator nodes have a sensible "single node selection", e.g. there's no reason why you would want a NodeSelection to happen for a HorizontalRuleNode since there is no internal content or editable state, a RangeSelection with element coordinates is fine and you would really want it to always be collapsed unless you're explicitly trying to select the node by holding the shift key or dragging.

@mshirlaw-alteryx
Copy link

mshirlaw-alteryx commented Mar 19, 2025

@etrepum we are facing a very similar issue in our editor. For context we have some custom code that handles copy and paste of a decorator node. The code in question essentially amounts to

const nodesToInsert = copiedNodes.map((node) => duplicateNode(node, callbacks));

$insertGeneratedNodes(editor, nodesToInsert, selection);

This code works the same way in chrome, edge, safari etc but is broken in firefox. The following videos demonstrate the difference between chrome and firefox:

In the example below we have two text nodes and one decorator node

Chrome

chrome.mov

Firefox

firefox.mov

I've logged out the nodes that we are sending to $insertGeneratedNodes in both chrome and firefox and I can see that they appear to be the same in both (see below):

Chrome

Image

Firefox

Image

So I think in our case there is something different about how these nodes are handled in $insertGeneratedNodes / selection.insertNodes. Hopefully this might lead to identifying the source of this issue?

@etrepum
Copy link
Collaborator

etrepum commented Mar 19, 2025

The screenshots aren’t very useful, the important details are what the browser selection and lexical selection are (plus the events themselves). The issue must be something to do with the events and how they are dispatched, I haven’t investigated it myself beyond what I wrote a few months ago.

@mshirlaw-alteryx
Copy link

mshirlaw-alteryx commented Mar 20, 2025

Just before pasting the following logging gives:

console.log('Lexical selection');
console.log(JSON.stringify(selection));
console.log('Browser selection');
console.log(JSON.stringify(globalThis.getSelection()));

Lexical selection:

{"anchor":{"key":"8","offset":0,"type":"element"},"focus":{"key":"8","offset":0,"type":"element"},"_cachedNodes":[{"__type":"paragraph","__parent":"root","__prev":"4","__next":"12","__key":"8","__first":null,"__last":null,"__size":0,"__format":0,"__style":"","__indent":0,"__dir":null,"__textFormat":0,"__textStyle":""}],"format":0,"style":"","dirty":false}

Browser selection:

{}
events.mov

@etrepum
Copy link
Collaborator

etrepum commented Mar 20, 2025

Looking a little deeper the paste issue seems specifically to be that Firefox ends up dispatching another event when processing the paste that Lexical dispatches as a CONTROLLED_TEXT_INSERTION_COMMAND which doesn't have proper handling of decorators. Could also be the cause of #7296

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants