Mixed inline and block content

I was recently looking at the history of GML, developed around 1970, and this is the example given:

   :h1.Chapter 1:  Introduction
   :p.GML supported hierarchical containers, such as
   :ol.
   :li.Ordered lists (like this one),
   :li.Unordered lists, and
   :li.Definition lists
   :eol.
   as well as simple structures.
   :p.Markup minimization (later generalized and formalized in SGML),
   allowed the end-tags to be omitted for the "h1" and "p" elements.

This example shows that GML supported mixed inline and block content (e.g. lists) in paragraphs, as do its successors HTML and various XML standards such as JATS.

It’s a recurring problem that ProseMirror doesn’t support mixed inline and block content, as we’d like to use ProseMirror to edit content that does have mixed inline and block content, so I’d like to find a solution.

The most obvious workaround is to create a new node type (e.g. fragment) that has inline* as it’s content and can be used in place of inline* in other block node types. This would mean wrapping contiguous inline nodes in fragment blocks on import and unwrapping them on export.

That’s a bit of a hassle and it means adjusting various things in lots of other places, like making keypress handlers work inside fragment as if it was a paragraph.

Is this the only solution and should we work towards making this possible?

If not, it would be useful to see a full description of the reason for the current restriction on mixed inline and block content in ProseMirror, in case there’s another solution that could be implemented in ProseMirror’s internals which would make this workaround unnecessary.

Cursor motion works differently in inline and block context. Browsers won’t even let you place a cursor between blocks. There’s probably more reasons—commands and other code uses the block/inline nature of nodes in many places. I don’t think this is something that’s likely to change.

Thanks @marijn - I’ll do some more investigation into the native behaviour of browser contenteditable elements with mixed content.

For those of use who do need to support editing mixed inline and block content, does the fragment approach I described above seem like the right thing to do?

Yes (though my impression is that reasonable encodings of structured text need the inline/block distinction, and not having that mostly seems like a worse-is-better, too-loose definition issue that doesn’t fit well with the more strict design philosophy of ProseMirror).

If it makes it clearer, this is how the content would be represented, using React’s <> to represent the fragment:

   <h1>Chapter 1:  Introduction</h1>
   <p>
    <>GML supported hierarchical containers, such as</>
    <ol>
      <li>
        <>Ordered lists (like this one),</>
      </li>
      <li>
        <>Unordered lists, and </>
      </li>
      <li>
        <>Definition lists</>
      </li>
     </ol>
     <>as well as simple structures.</>
   </p>
   <p>
    <>Markup minimization (later generalized and formalized in SGML), allowed the end-tags to be omitted for the "h1" and "p" elements.</>
   </p>

As the <> (fragment) would be a block node type, the distinction between block and inline node types would be maintained.

Everywhere which wants to allow mixed (inline | block)* content would need to have (fragment | block)* instead, and would need to wrap/unwrap the inline content in and out of fragment when importing/exporting.

I don’t need it, but the proposed structure does make sense. By the way, manuscripts.io is just plain sick.

1 Like