Custom node, dynamic imports and [enter] destructive operation

Hey - me again :grinning:

One of the things that I’m experimenting with is to see whether it would be possible to create a metadata-driven editor. I’m using tiptap v2, (currently) a fixed json document - that has both PM content and metadata that should drive the editor instance and ES6 dynamic import functionality. I’m facing a problem with this which I’m trying to track down. Now I know that this is a) maybe, probably not a PM issue (or tiptap) for that matter and b) maybe somewhat of a ‘different’ way to do things - but I’m reaching out to this forum to see whether the problematic behavior I will describe rings any bells.

The situation is relatively straightforward. I use standard Document, Paragraph, Text, Bold and Italic extensions and use them (in a dev setup) using dynamic imports. Additionally I have a custom extension (node) called Introduction which I add into the mix.

The content expression for the document is:

introduction? paragraph*

The content expression for the introduction is:

paragraph+

So effectively I describe the document as optionally starting with an Introduction (which itself could hold one or more paragraphs), then followed by zero or more paragraphs.

I start out this document with content like this:

{
"type": "doc",
  "content": [
    {
      "type": "introduction",
      "content": [
        {
          "type": "paragraph",
          "content": [{ "type": "text", "text": "Some introductory words..." }]
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "It's a "
        },
        {
          "type": "text",
          "marks": [
            {
              "type": "bold"
            }
          ],
          "text": "dynamic"
        },
        {
          "type": "text",
          "text": " "
        },
        {
          "type": "text",
          "marks": [
            {
              "type": "italic"
            }
          ],
          "text": "world"
        },
        {
          "type": "text",
          "text": "!"
        }
      ]
    }
  ]
}

This loads fine and the prosemirror-dev-toolkit shows the following content:

Whenever I position the cursor in the introduction and hit [enter], just as I expect a new paragraph is added and is reflected by the toolkit:

However when I move the cursor to the very end of the document (at the end of the paragraph, not within the introduction) and when I hit [enter] to start a new paragraph, the following error is displayed on the console:

After which the Introduction has vanished from the document content, also seen in the toolkit:

The below screen recording shows the behavior as it happens.

enter-removes-custom-node

My question/ask is: has anyone seen a similar kind of behavior before?

Could this (somehow) be related to using dynamic imports?

No, this is not related to dynamic imports, though it may be related to mixing different schema objects. Check your initial document with the check method to make sure it is valid at that point.

Thanks Marijn - actually it isn’t valid:

Uncaught RangeError: Invalid content for node doc: <introduction(paragraph("Some introductory words..
    check node.js:329
    onCreate main.ts:46
    emit EventEmitter.ts:29
    emit EventEmitter.ts:29
    Editor Editor.ts:101
    setTimeout handler*Editor Editor.ts:95
    <anonymous> main.ts:38
    promise callback* main.ts:27
    promise callback* main.ts:18

I’ve also echoed the editor.schema.spec and from the looks of it the doc extension somehow wasn’t applied.

{
  "topNode": "doc",
  "nodes": {
    "content": [
      "paragraph",
      { "content": "inline*", "group": "block", "parseDOM": [{ "tag": "p" }] },
      "doc",
      { "content": "block+" },
      "text",
      { "group": "inline" },
      "introduction",
      { "content": "paragraph+", "parseDOM": [{ "tag": "introduction" }] }
    ]
  },
  "marks": {
    "content": [
      "bold",
      {
        "parseDOM": [
          { "tag": "strong" },
          { "tag": "b" },
          { "style": "font-weight" }
        ]
      },
      "italic",
      {
        "parseDOM": [
          { "tag": "em" },
          { "tag": "i" },
          { "style": "font-style=italic" }
        ]
      }
    ]
  }
}

Have to figure out why that is next.

Adding group: 'block' to the Introduction custom node does make this problem go away.

And - FWIW - the content expression for the Document tiptap extension wasn’t set properly.

Initially I was using something like:

resolvedPlugins.forEach((resolvedExtension) => {
        const extension = resolvedExtension.default;
        console.info(`Loaded: ${extension.name}`);

        if (content.inlineExtensions[extension.name]) {
          console.info(`Applying inline extension of: ${extension.name}`);
          extension.extend(content.inlineExtensions[extension.name]);
        }

        extensions.push(extension);
      });

And this needs to be something like this:

resolvedPlugins.forEach((resolvedExtension) => {
        let extension = resolvedExtension.default;
        console.info(`Loaded: ${extension.name}`);

        if (content.inlineExtensions[extension.name]) {
          console.info(`Applying inline extension of: ${extension.name}`);
          extension = extension.extend(content.inlineExtensions[extension.name]);
        }

        extensions.push(extension);
      });

Which results in a document schema like so:

{
  "topNode": "doc",
  "nodes": {
    "content": [
      "paragraph",
      {
        "content": "inline*",
        "group": "block",
        "parseDOM": [
          {
            "tag": "p"
          }
        ]
      },
      "doc",
      {
        "content": "introduction? paragraph*"
      },
      "text",
      {
        "group": "inline"
      },
      "introduction",
      {
        "content": "paragraph+",
        "group": "block",
        "parseDOM": [
          {
            "tag": "introduction"
          }
        ]
      }
    ]
  },
  "marks": {
    "content": [
      "bold",
      {
        "parseDOM": [
          {
            "tag": "strong"
          },
          {
            "tag": "b"
          },
          {
            "style": "font-weight"
          }
        ]
      },
      "italic",
      {
        "parseDOM": [
          {
            "tag": "em"
          },
          {
            "tag": "i"
          },
          {
            "style": "font-style=italic"
          }
        ]
      }
    ]
  }
}

Thank you again.