yjs / y-prosemirror

ProseMirror editor binding for Yjs
https://demos.yjs.dev/prosemirror/prosemirror.html
MIT License
328 stars 115 forks source link

prosemirrorJSONToYXmlFragment doesn't work if no given YXmlFragment #136

Open NathanLauth opened 1 year ago

NathanLauth commented 1 year ago

Describe the bug In order to initially create and populate my Y.Doc in my server (Before sharing it with my frontend) I want to use y-prosemirror utility fonctions. The final goal is to have my Tiptap Wysiwyg nicely displayed with the already existing data in my DataBase (HTML stored as String). I already have my Y.Doc, and I only want to create a new Y.XmlFragment populated with my existing HTML.

So the utility function prosemirrorJSONToYXmlFragment(schema, state) looks perfect for my usage. But it seems that the method cannot return a populated Y.XmlFragment, without giving an existing one already linked to an existing Y.Doc

To Reproduce I think the best thing I can do is to provide a real exemple of what I am trying to do :

import * as Y from "yjs";
import { generateJSON } from "@tiptap/html";
import { prosemirrorJSONToYXmlFragment } from "y-prosemirror";
import { getSchema } from "@tiptap/core";

const htmlFromDataBase = "<p>Hello !</p>";
const yDoc = new Y.Doc();

// import from tiptap are omitted (but theses are only tiptap extensions).
const tiptapExtensions = [Document, Paragraph, Text, Link, BulletList, ListItem, OrderedList, Bold, Italic, Underline, Strike];

const schema = getSchema(tiptapExtensions);

const state = generateJSON(htmlFromDataBase, tiptapExtensions);

const xmlFragment = yDoc.getXmlFragment('myFragment');
// Here xmlFragment and yFragment are correctly populated with my given HTML. Working exemple !
const yFragment = prosemirrorJSONToYXmlFragment(schema, state, xmlFragment);

// If I would have done that, newFragment would have been empty (without Y.XmlElements) 
const newFragment = prosemirrorJSONToYXmlFragment(schema, state);

// Same I gave and existing fragment ! updateFragment is witout any elements.
const updateFragment = prosemirrorJSONToYXmlFragment(schema, state, new Y.XmlFragment());

// So i guess it only work if the given Y.XmlFragment is already linked to and existing Y.Doc !

Expected behavior I expect that if i use the method prosemirrorJSONToYXmlFragment(schema, state) with valid schema and json, it should create me a populated Y.XmlFragment

Environment Information

PhilGarb commented 1 year ago

I have stumbled upon this issue as well.

This makes it very difficult to restore a XmlFragment from the output of XmlFragment.toJSON(). Especially, because the XmlFragment cannot be properly cloned to be inserted in another yDoc.

You can see a reproduction of the above and the problem with the clone here: https://codesandbox.io/p/sandbox/agitated-night-7fgj8d

You just have to open the console from the served page to the right.

vitmf commented 11 months ago

I think you can create the XmlFragment with prosemirrorJSONToYXmlFragment(schema, state), but you can only get its contents after linking to a Y.Doc. See https://github.com/yjs/yjs/blob/main/src/types/YXmlFragment.js#L306.