Rich text / foldkit-richtext-dom

Showing a document: the read-only renderer

foldkit-richtext-dom/view renders a document as ordinary Foldkit Html through inertHtml: it dispatches nothing and owns no DOM, so it serves a visitor's page, a preview, or an email as it is.

ts
const html = renderDocument(document) // a div of block elements
renderBlocks(slice.blocks) // one element per block
renderDocument(document, renderer) // a declared Link as a real <a href>
renderDocument(document, renderer, decorations) // a decoration overlaid on the runs it covers

It takes the same rendering(...) registry as the HTML serializer and the editor, so a declared mark or kind becomes the same element everywhere, custom elements included. Without one, blocks become p/h1–h6, marks nest as strong/em/code in the serializer's order, an undeclared mark rides on a span with data-marks, and an unknown block renders as an inert div data-unknown="Type" placeholder. A tag Foldkit cannot build is reported, never swapped for another element.

A decoration set is projected with RichText.decorationsIn: each covered piece of a run becomes a span[data-decoration=<kind>] with the run's marks inside it, which is also how the editor draws one, so one stylesheet serves both. Each string field of the decoration's data whose name is lowercase letters, digits, and hyphens is drawn as data-decoration-<name> on that span (data: { name: 'Ada' } is data-decoration-name="Ada", for a stylesheet's attr()); any other field is not drawn. A decoration that starts or ends in an empty run, such as another person's caret on an empty line, is drawn as an empty span in it, where the core's decorationsIn has no text to cover. renderBlocks takes no set, since a slice's positions cannot be resolved without its document. Text holding a NUL, which markup cannot carry, is written as the U+FFFD a parser would make of it.

h.DataAttribute prefixes data- itself, so it takes the bare name (DataAttribute('unknown', …) is data-unknown).