Draft-js: Losing cursor with non-editable entity components
Asked Answered
P

1

8

I have an editor that is supposed to have entities with the props name, color, start, end. In the editor the text in positions denoted by start and end will be subsistuted by name, and it will be rendered by a custom component with contentEditable=false.

This works great with draftjs in general but there are a couple of issues:

  • When moving the cursor with the keyboard arrows, the entities are skipped over, which is good. But when an entity is at the very end of the input and I try to move rightwards past it (either just with right arrow or with option or cmd + right) the cursor disappears and doesn't come back when I move left again.
  • If I go right to the left of an entity and push shift + option + right arrow, the entity is selected as expected. But if I then press left arrow the cursor is also lost.

I could fix this by making sure there is always a whitespace after such a last entity, but that seems hacky and probably has edge cases.

Another option is to not use contentEditable=false, but that creates other issues with my actual app, which has a more complicated entity component including a dropdown, and I will have to manually make sure the user can't change text inside the entities etc.

Here is a reproduction of the issue: https://codesandbox.io/s/competent-surf-st77i

Any ideas?

Pren answered 28/3, 2020 at 17:17 Comment(5)
Did you find a solution to this?Morava
Nope. Any ideas?Pren
Nothing here. Ended up moving to slate-js instead because it doesn't seem to have the same issue (and I could afford it, since it's a new project)Morava
Ok, thanks for the tip!Pren
JIC it's useful to someone else, I ran into this too trying to render some custom entities, the fix was to render the entity in such a way that the DOM structure matched the number of characters I wanted this entity to be. If you render an emoji for example, but using some funky image nested in a div, etc., I want this to be one character. So, render <span>{child}<spanA><img/></spanA></span>, where child is the single character with the entity applied. spanA here is a span with user-select: none. You can make the child color: transparent too, and caret-color: black to fix selection bhvr.Raphaelraphaela
A
0

Unfortunately, I too have been unable to find an alternative that has no downsides, however, I can recommend two alternatives that do work without causing draft-js editing bugginess.

Instead of using contentEditable={false}, when you add the entity to the ContentState, make your entity IMMUTABLE. When the user tries to change the text, the component will disappear. Demo with code. Note that when you render your entity, you should not try to adjust the text during the render.

If you are trying to avoid the user being able to put their cursor in the middle of the entity, or to show different text at render time, you may prefer to use a block instead of an entity. This has the downside of being an entire row in the editor, but you can control exactly how the block is rendered and include contentEditable={false} in your block.

Ala answered 3/5 at 23:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.