Binding(Quill, CodeMirror, ...) with Nested Shared Types

In this collaborative quill editor demo,
I tried to change the code like this:

So it is actually just putting ytext into a shared map.
I expected this code to work perfectly like the original.
However, it is just not synced…

Expected (original example)

Actual (edited to use nested share types)

Is there anything that i’m missing?

(+)
codemirror and codemirror.next have same problem. So I think this is not the problem of particular implementation, just I’m doing something wrong with shared types.

Hi @a3626a,

I think it might make sense to experiment with the shared types a bit. I wrote a getting started section in the documentation: Shared Types - Yjs Docs

If you overwrite a property with a new empty Y.Text type every time a client joins (as you are doing in the second approach), then it is to be expected that the content will be overwritten.

The Y.text type that the client writes when it joins a session is different from the existing Y.Text type that already exists. So basically existing clients will work on a deleted type and won’t sync anymore.

1 Like

I accidently thought that share types are something like schema. So I expected only the text value to be synced. I never expected a new YText object to be initialized automatically.

Thank you dmonad!

I succeed to make it work by initializing YText once.

Here’s my naive tweak for my problem

/* eslint-env browser */

import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
import { QuillBinding } from 'y-quill'
import Quill from 'quill'
import QuillCursors from 'quill-cursors'

Quill.register('modules/cursors', QuillCursors)

window.addEventListener('load', () => {
  const ydoc = new Y.Doc()
  const provider = new WebsocketProvider('wss://demos.yjs.dev', 'quill-demo-4', ydoc)

  // Be Patient!
  // We must check YText object after the document is synced
  setTimeout(() => {
    if (ydoc.getMap('map').get('quill') === undefined) {
      // Only Initialize Once!
      const ytext = new Y.Text()
      ydoc.getMap('map').set('quill', ytext)
    }

    const ytext = ydoc.getMap('map').get('quill');
    console.log(ytext);

    const editorContainer = document.createElement('div')
    editorContainer.setAttribute('id', 'editor')
    document.body.insertBefore(editorContainer, null)

    const editor = new Quill(editorContainer, {
      modules: {
        cursors: true,
        toolbar: [
          [{ header: [1, 2, false] }],
          ['bold', 'italic', 'underline'],
          ['image', 'code-block']
        ],
        history: {
          userOnly: true
        }
      },
      placeholder: 'Start collaborating...',
      theme: 'snow' // or 'bubble'
    })

    const binding = new QuillBinding(ytext, editor, provider.awareness)

    /*
    // Define user name and user name
    // Check the quill-cursors package on how to change the way cursors are rendered
    provider.awareness.setLocalStateField('user', {
      name: 'Typing Jimmy',
      color: 'blue'
    })
    */

    const connectBtn = document.getElementById('y-connect-btn')
    connectBtn.addEventListener('click', () => {
      if (provider.shouldConnect) {
        provider.disconnect()
        connectBtn.textContent = 'Connect'
      } else {
        provider.connect()
        connectBtn.textContent = 'Disconnect'
      }
    })

    // @ts-ignore
    window.example = { provider, ydoc, ytext, binding, Y }
  }, 1000);
})
1 Like