How to wrap content in nested node

I am trying to build a collapsible details node. This is my schema:

nodes: {
  // ...
  paragraph: {
    content: "inline*",
    group: "block",
  },
  details: {
    content: "detailsSummary detailsContent",
    defining: true,
    group: "block",
  },
  detailsSummary: {
    content: "text*",
    selectable: false,
  },
  detailsContent: {
    content: "block*",
    selectable: false,
  },
  // ...
}

I try to wrap the selected content with the following code:

const { $from, $to } = state.selection
const range = $from.blockRange($to)

tr.wrap(range, [
  {
    type: schema.nodes.details,
  },
  {
    type: schema.nodes.detailsContent,
  },
])

This is the resulting document:

{
  "type": "doc",
  "content": [
    {
      "type": "details",
      "content": [
        {
          "type": "detailsContent",
          "content": [
            {
              "type": "paragraph",
              "content": [
                {
                  "type": "text",
                  "text": "This is a paragraph."
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

I would have thought detailsSummary would be added along by the forced schema:

{
  "type": "doc",
  "content": [
    {
      "type": "details",
      "content": [
        {
          "type": "detailsSummary"
        },
        {
          "type": "detailsContent",
          "content": [
            {
              "type": "paragraph",
              "content": [
                {
                  "type": "text",
                  "text": "This is a paragraph."
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Is this expected?

But ok, I added this to my command:

const { $from, $to } = state.selection
const range = $from.blockRange($to)

tr.wrap(range, [
  {
    type: schema.nodes.details,
  },
  {
    type: schema.nodes.detailsContent,
  },
])

// add summary manually
tr.insert(range.start + 1, schema.nodes.detailsSummary.createAndFill())

This works fine but for some reason I can’t undo this command. No error is thrown but something very strange happens here.

ezgif-7-073122347f89

Have I missed something obvious here? Is there a better way for doing this?

The fact that wrap goes through at all here is a bug—that should not be able to create an invalid document. I guess it relies on findWrapping to do the checks, which you didn’t use. Patch f741f383e adds a check for this.

The undo issue existed because undo won’t take the document back to an invalid state.

You’ll have to create a precise ReplaceAroundStep to implement this properly.

1 Like

Thanks for the quick answer and the bugfix! I try my luck with ReplaceAroundStep!