Rich text / foldkit-richtext-markdown
Edit the Markdown itself
A source session lets a person edit the document as Markdown and switch back. It is a value, not a store: the application keeps it in its Model while source mode is on, and the rich document stands still meanwhile, so only one representation is ever being edited.
import { closeSource, openSource } from 'foldkit-richtext-markdown'
// Entering source mode: the draft starts as the printed document.
const session = openSource(model.document)
// Each keystroke in the source editor replaces the draft.
const edited = { ...session, draft: '# Title\n\nNew text\n' }
// Leaving it: a pure read, so it serves as a preview too.
const closed = closeSource(edited, model.document, { mint: () => crypto.randomUUID() })openSource prints the document and keeps what the printer could not show — a mark Markdown
has no syntax for — as unprintable. closeSource compares the draft with what was printed:
unedited, it returns the caller's own document untouched (changed: false), identities and
unprintable marks included, so switching modes without typing loses nothing. Edited, it
parses the draft into a new document and reports, in diagnostics, the unprintable content
the edit loses followed by what parsing refused. Nothing is committed until the application
puts closed.document in its Model, so it can warn first. SourceSession is a schema, so the
session fits in a Model as it is.
closed.style is how the edited draft spelled its constructs, over the style the session
opened with; its blocks are the edited draft's alone, since the blocks it names are new. Keep
it beside the document and pass it to the next openSource(document, { style }), and a writer who typed _hello_ and * item sees them spelled that way when they
come back to source mode, rather than in the canonical *hello* and - item.
The caret comes along both ways. openSource(document, { selection }) sets the session's
caret, an offset in the draft, to where the selection's focus printed; a node selection, or
none, starts it at 0. Replace caret as it moves in the source editor, and
closed.selection is that place in the document closeSource returns: in the parsed draft
when it was edited, and in the caller's own document when it was not. It is null when the
draft holds no text, or when an unedited draft does not have as many text blocks as the
caller's document. Keep the old selection then.