slate: "Cannot resolve a Slate point from DOM point" for non-editable text rendered inside of Element

Do you want to request a feature or report a bug?

Bug

What’s the current behavior?

When selecting (supposed to be) non-editable text that is rendered inside of an element, I am seeing an error “Cannot resolve a Slate point from DOM point”. My usecase is to have a prefix that isn’t editable, but explains the purpose of the block.

Slate: 0.57.1 Browser: Chrome 79.0.3945.117 OS: MacOS 10.15.2 (19C57)

Large GIF (996x358)

Edit React Slate

VM469:1691 Uncaught Error: Cannot resolve a Slate point from DOM point: [object Text],7
    at Object.toSlatePoint (eval at Dr (eval.js:61), <anonymous>:1691:13)
    at Object.toSlateRange (eval at Dr (eval.js:61), <anonymous>:1736:30)
    at HTMLDocument.eval (eval at Dr (eval.js:61), <anonymous>:800:43)
    at later (eval at Dr (eval.js:61), <anonymous>:27:23)
toSlatePoint @ VM469:1691
toSlateRange @ VM469:1736
eval @ VM469:800
later @ VM474:27
setTimeout (async)
later @ VM474:23
setTimeout (async)
later @ VM474:23
setTimeout (async)
later @ VM474:23
setTimeout (async)
debounced @ VM474:38

What’s the expected behavior?

To see no error, and have Slate ignore the non-editable text.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 19 (1 by maintainers)

Commits related to this issue

Most upvoted comments

This is kind of strange, but I think a hack solution is to use both a CSS style and an HTML attribute.

✅ For example, this works to render elements:

<div {...attributes}>
  <div
    style={{ userSelect: "none" }}
    contentEditable={false}
  >
    Non-editable
  </div>
  <p>{children}</p>
</div>

🛑 But oddly, this doesn’t work:

<div {...attributes}>
  <div
    contentEditable={false}
  >
    Non-editable
  </div>
  <p>{children}</p>
</div>

🛑 Nor does this:

<div {...attributes}>
  <div
    style={{ userSelect: "none" }}
  >
    Non-editable
  </div>
  <p>{children}</p>
</div>

I added these examples to the example code sandbox above.

I say this is a “hack solution” because ideally all you would need is contentEditable={false} to avoid this problem. An example usecase for this: you might want to let users select this non-editable text, and userSelect: none CSS prevents that.

NOTE: This does not seem to stop the error from happening when doubleclicking into a child, and selecting all of the text. It seems to sometimes stop it, but not always. This specifically stops the error from happening when selecting or clicking on the non-interactive text specfically.

I ran into this problem when rendering nothing in the slate component, since the introduction tutorial starts off with nothing in the useState([]). So I guess it tries to render an empty array, but has nothing to put the values into at the start.

To solve this, I set this as the default value:

  const [value, setValue] = useState<Descendant[]>([
    {
      type: "paragraph",
      children: [{ text: "" }],
    },
  ]);

This has been a long standing behavior of slate. It assumes that elements on the DOM that are children of the editor are either

  1. represented in some way in the in the slate value or
  2. contentEditable=false and userSelect: none.

contentEditable=false does not work by itself because this is the state void nodes have.

I find this happens if you’re rendering (and then interacting) with an element that doesn’t have slate’s data attributes, which get passed in renderLeaf or renderNode btw.

for example:

renderLeaf={props => <span>{props.children}</span>}

will cause this problem. To fix it you do this:

renderLeaf={props => <span {...props.attributes}>{props.children}</span>}

There are occasions when you want to render content that you don’t want to be part of slates content, but appear alongside it. In this case you just add `contentEditable={false} to that element. For example

renderLeaf={props => <span {...props.attributes}><i contentEditable={false}>👍</i>{props.children}</span>}

If an element will have contentEditable set to false, slate will not try to get the selected range when you click on it, hence the error will not occur. Hope that helps others.

Probably would be good to throw a better error cc @ianstormtaylor

I am experiencing this problem as well, @charlex thanks for the hack solution for the time being 😃

i am encountering similar issues, only while running end to end tests using a headless puppeteer environment, @charlex does this sound similar to what you have there? I am unable to fix this though, having a hard time figuring out what is wrong

 Cannot resolve a Slate node from DOM node: [object HTMLSpanElement]

      at Object.toSlateNode (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:203920)
      at http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:221289
      at Object.Ve (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1666433)
      at $e (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1666587)
      at http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1684794
      at jr (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1684888)
      at kr (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1685303)
      at http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1690956
      at De (http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1766815)
      at http:/localhost:3000/static/js/2.f3428cd3.chunk.js:2:1686764

@dark-swordsman that solved my problem too. However, it would be much better if slate would give us a very clear message about empty content. And I think it should be able to handle empty content as well.

I have found that wrapping children in a span and adding attributes to the span as opposed to the Styled Component solves @DraGonM 's issue above:

// bad
<XLargeText as="h2" {...attributes}> // Styled Component
  {children}
</XLargeText>

// good
<XLargeText as="h2"> // Styled Component
  <span {...attributes}>{children}</span>
</XLargeText>

@dark-swordsman that solved my problem too. However, it would be much better if slate would give us a very clear message about empty content. And I think it should be able to handle empty content as well.

i think this issue becomes enchantment at this point. it looks like solution works for everybody 👍 😊

If someone like me getting this error when using some interactive non-slate-elements inside slate-element (it was td in my case), even with contentEditable={false} and userSelect: "none", you must check that your nearest slate-element not wrapped in styled-components (maybe it also the case for some other wrappers)

Because toSlateNode method was trying to find the nearest slate-element to the clicked non-slate-element, it was searching weakmap ELEMENT_TO_NODE by <td class="your random styled class" ...>, but in ELEMENT_TO_NODE this element was actually StyledComponent wrapper. image image

I don’t get this error anymore, after I removed styled-wrapper and started using style prop for td slate-element, I hope it helps someone.

In my case, I’ve added a draggable item, which required the ref of the element. but apparently attributes wants the ref too

from

  <div  ref={draggable.innerRef} {...attributes}>

to

  <div
      ref={el => {
        attributes.ref(el);
        draggable.innerRef(el); 
      }}
      {...attributes}>

(but I have another issue, so it’s still broken 😄)

I keep on bumping into this error, I have absolutely no idea why, or when it happens as it seems completely random. And it’s driving me completely crazy

Thank you @dark-swordsman.

I solved this problem using your solution.

If you have empty initial state remove autoFocus prop in <Editable /> component

@juliankrispel thank you for providing that context.

Thank you so much @charlex for the workaround! I’ve struggled so long with this issue (with slate 0.58.3)! 😰

BTW, I find the “Checklist” example (https://github.com/ianstormtaylor/slate/blob/master/site/examples/check-lists.js) misleading on that matter: it works with the <input> element but crashes in the same way as described here with a <select> one. So bad for such a tiny change…