Slate: Transforms.setSelection puts cursor in a wrong location

Created on 4 Aug 2020  路  3Comments  路  Source: ianstormtaylor/slate

Do you want to request a _feature_ or report a _bug_?

Bug

What's the current behavior?

Slate: 0.58.4
Browser: Chrome 84.0.4147.105 (Official Build) (64-bit)
OS: Ubuntu 20.04

Steps to reproduce:

  1. Go to https://www.slatejs.org/examples/mentions
  2. Focus the editor, put cursor at the end of document
  3. Hit @
  4. Hit a (Aayla Secura will be selected)
  5. Hit Enter (interestingly, cursor is put in a correct place here)
  6. Hit Backspace
  7. Hit @
  8. Hit a (Aayla Secura will be selected)
  9. Hit Enter

Expected result:
Mention is inserted. Cursor is placed after the mention.

Actual result:
Mention is inserted. Cursor is placed before the mention.

screencast

What's the expected behavior?

Mention is inserted. Cursor is placed after the mention.


This Transforms.move call does not work as expected: https://github.com/ianstormtaylor/slate/blob/0bbe121d76c5c2313d939de8a7ebed3bfd37f62d/site/examples/mentions.js#L159

I've also tried using Transforms.select manually computing the location at which the cursor should be placed, but the result was the same.

Interestingly, editor.selection points to the location after the mention node, which is incorrect, as the cursor is obviously before the mention node.

Most helpful comment

This is directly related to https://github.com/ianstormtaylor/slate/issues/3282#issuecomment-564208496

Applying @eddyw's example to mentions example fixes the problem. Here's the diff:

diff --git a/site/examples/mentions.js b/site/examples/mentions.js
index 2289d151..00d3bd19 100644
--- a/site/examples/mentions.js
+++ b/site/examples/mentions.js
@@ -169,13 +169,16 @@ const Element = props => {
   }
 }

-const MentionElement = ({ attributes, children, element }) => {
+const MentionElement = ({
+  attributes: { contentEditable, ...attributes },
+  children,
+  element,
+}) => {
   const selected = useSelected()
   const focused = useFocused()
   return (
     <span
       {...attributes}
-      contentEditable={false}
       style={{
         padding: '3px 3px 2px',
         margin: '0 1px',
@@ -187,7 +190,7 @@ const MentionElement = ({ attributes, children, element }) => {
         boxShadow: selected && focused ? '0 0 0 2px #B4D5FF' : 'none',
       }}
     >
-      @{element.character}
+      <span contentEditable={contentEditable}>@{element.character}</span>
       {children}
     </span>
   )

Notable changes:

  1. Pick out contentEditable from attributes, so it's not assigned to the span outside.
  2. Add one more child span which wraps _only_ the mention, where we assign the contentEditable prop.
  3. The children must be a direct descendant of the parent element (the element with {...attributes}), otherwise, there will be a bug with deleting a _focused_ mention element (reported at #3282).

All 3 comments

It seems that deferring Transforms.move(editor) with setTimeout "fixes" the issue:

    setTimeout(() => {
        Transforms.move(editor);
    }, 0);

This is directly related to https://github.com/ianstormtaylor/slate/issues/3282#issuecomment-564208496

Applying @eddyw's example to mentions example fixes the problem. Here's the diff:

diff --git a/site/examples/mentions.js b/site/examples/mentions.js
index 2289d151..00d3bd19 100644
--- a/site/examples/mentions.js
+++ b/site/examples/mentions.js
@@ -169,13 +169,16 @@ const Element = props => {
   }
 }

-const MentionElement = ({ attributes, children, element }) => {
+const MentionElement = ({
+  attributes: { contentEditable, ...attributes },
+  children,
+  element,
+}) => {
   const selected = useSelected()
   const focused = useFocused()
   return (
     <span
       {...attributes}
-      contentEditable={false}
       style={{
         padding: '3px 3px 2px',
         margin: '0 1px',
@@ -187,7 +190,7 @@ const MentionElement = ({ attributes, children, element }) => {
         boxShadow: selected && focused ? '0 0 0 2px #B4D5FF' : 'none',
       }}
     >
-      @{element.character}
+      <span contentEditable={contentEditable}>@{element.character}</span>
       {children}
     </span>
   )

Notable changes:

  1. Pick out contentEditable from attributes, so it's not assigned to the span outside.
  2. Add one more child span which wraps _only_ the mention, where we assign the contentEditable prop.
  3. The children must be a direct descendant of the parent element (the element with {...attributes}), otherwise, there will be a bug with deleting a _focused_ mention element (reported at #3282).

Above patch did work, so any reason not pick it up?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bunterWolf picture bunterWolf  路  3Comments

ianstormtaylor picture ianstormtaylor  路  3Comments

gorillatron picture gorillatron  路  3Comments

Slapbox picture Slapbox  路  3Comments

yalu picture yalu  路  3Comments