a tool for shared writing and social publishing

Encode richtext as Yjs, for documents that arrive without editor state #103

targeting main from hipstersmoothie.com/leaflet:adopt-imported-documents
Open opened by and assigned to hipstersmoothie.com
targeting main from hipstersmoothie.com/leaflet:adopt-imported-documents

factsToPagesRecord walks a Yjs fragment and emits { plaintext, facets }. Nothing went the other way, so a document that arrives already in Leaflet's content format — converted from another platform, indexed off the firehose — has a record but no block/text value. It renders publicly and cannot be opened in the editor.

richtextToYjsText is the inverse of that walk. It slices the text at every facet boundary so each run carries one uniform set of marks, and emits the delta attributes YJSFragmentToFacets reads back: strong, em, underline, strikethrough, code, highlight, link. Overlapping facets are additive. Newlines become hard_break elements, the node the reader counts as a one-byte "\n".

Offsets are UTF-8 throughout, via UnicodeString — the same type the forward path measures with. Indexing by JS string position would shift every mark after the first non-BMP character; there's a test pinning a facet that starts after an emoji.

Inline marks only. Footnotes and mentions are element-level and Leaflet's own, so a document another platform authored cannot carry them; their features are skipped without dropping the text they covered.

One subtlety worth knowing before editing this: the paragraph is integrated into the document before it is filled. A Y.XmlText outside a document reports length 0 regardless of contents, so appending runs by text.length silently reverses them.

Commits 2

Give imported documents editor state, so they can be edited
Encode richtext as Yjs, for documents that arrive without editor state