stackiva / slate-collaborate-support

0 stars 0 forks source link

Latest version of Slate does not support synchronizing the selection of collaborative editors #12

Closed thesunny closed 3 years ago

thesunny commented 3 years ago

Type some words and then undo the typing results in this:

http://g.recordit.co/mw7CIONVc7.gif

Which eventually ends in this error:

Looks like it's a small issue to do with how Slate is now ingesting the selection. I think previously we added it to the <Slate /> component but that's not a prop to pass in anymore. So I think it's a matter of updating the selection directly on the editor object? I'll leave you to figure out the details but this may be just a small Slate upgrade issue.

Here's a snippet of my integration:

export const RichTextEditor = ({ documentId }: { documentId: string }) => {
  const renderElement = useCallback((props) => <Element {...props} />, [])
  const renderLeaf = useCallback((props) => <Leaf {...props} />, [])

  /**
   * This is to prevent crashes with live reload due to the selection pointing
   * incorrectly.
   *
   * https://github.com/ianstormtaylor/slate/issues/4081
   */
  const [editor] = useState(() => withHistory(withReact(createEditor())))

  const param = useMemo(() => {
    return {}
  }, [])

  const { ready, value, selection, onChange } = useCollaborativeEditor({
    serviceURL: "ws://ec2-184-72-124-41.compute-1.amazonaws.com:8080",
    editor,
    documentId,
    param,
    initialValue,
  })

  return (
    <div>
      <Slate editor={editor} value={value as Descendant[]} onChange={onChange}>
        <Toolbar className="">
          <MarkButton fa="fa-bold" format="bold" icon="format_bold" />
          <MarkButton format="italic" icon="format_italic" />
          <MarkButton format="underline" icon="format_underlined" />
          <MarkButton format="code" icon="code" />
          <BlockButton format="heading-one" icon="looks_one" />
          <BlockButton format="heading-two" icon="looks_two" />
          <BlockButton format="block-quote" icon="format_quote" />
          <BlockButton format="numbered-list" icon="format_list_numbered" />
          <BlockButton format="bulleted-list" icon="format_list_bulleted" />
        </Toolbar>
        <$Editable
          renderElement={renderElement}
          renderLeaf={renderLeaf}
          placeholder="Enter some rich text…"
          spellCheck
          autoFocus
          readOnly={!ready}
          onKeyDown={(event) => {
            for (const hotkey in HOTKEYS) {
              if (isHotkey(hotkey, event as any)) {
                event.preventDefault()
                const mark = HOTKEYS[hotkey as keyof typeof HOTKEYS]
                toggleMark(editor, mark)
              }
            }
          }}
        />
      </Slate>
    </div>
  )
}
wleroux commented 3 years ago

Well, yes, if Slate changed their API not to have selection as a prop, they broke the contract we relied on for updating the selection and the selection will get out of sync... Causing all sorts of issues. In the meantime, it means that the version with the breaking API change onwards is currently not supported until we can provide support for the latest version of Slate. 😒

wleroux commented 3 years ago

This can cause other issues; if a secondary client updates text, the selection would not be updated appropriately either... And if the client has an invalid selection, it would cause that same issue.

wleroux commented 3 years ago

Looking into this ATM and it appears that the code still works when you assign selection, however the specification for Slate does not specify a selection node and require a ts-ignore to work.

        {/* @ts-ignore */}
        <Slate editor={editor} value={value} selection={selection} onChange={onChange}>
wleroux commented 3 years ago

I have updated the selection to be updated even if it was not specified in the Slate properties. While it is still possible to pass in the parameter directly, it is no longer required.