Rich text / foldkit-mixins-richtext

The Markdown source editor

Source mode is SourceSession | null in the application's Model: foldkit-richtext-markdown's openSource sets it, and closeSource ends it. While it is set, draw this instead of the rich editor:

ts
import { sourceEditor } from 'foldkit-mixins-richtext'

sourceEditor<Message>()(
  {
    session: model.source,
    document: model.document,
    drafted: draft => DraftedSource({ draft }),
    moved: caret => MovedInSource({ caret }),
    done: LeftSource(),
  },
  h,
)
  • The text area holds the draft and sends drafted as it changes. When drawn it takes focus with its caret at session.caret, where openSource(document, { selection }) put the rich editor's caret, then sends moved as the caret moves. The application keeps that in session.caret, so closeSource(...).selection is the caret back in the rich editor. The caret is placed when the text area appears, not on every render, since a Mount reads its args once.
  • The warnings under it name what switching back would lose or refuse, read from closeSource, so there are none until the draft is edited. They are computed once per draft.
  • done is the way back. The application's update decides whether to commit closeSource(...).document at once or to ask first when there are warnings.

Split mode is the same session drawn twice: sourcePreview<Message>()({ session, document, rendering? }) beside the editor renders the document switching back would commit, through the read-only renderer, so it dispatches nothing. It shares the editor's parse of the draft, and while the draft is unedited it shows the document the application holds now.

SlotCapabilityRenders
rootContainerthe editor's wrapper
textTextInputthe Markdown, data-source="text"
warningsCollectionthe list, data-source="warnings"
warningBaseone loss, with data-code and data-detail for a Style to key on
doneInteractivethe way back, data-source="done"

What it does not draw

  • The placeholder is the editor's own, placed with editorAt, because it is drawn inside the editable subtree this package stays out of.
  • Positioning is foldkit-richtext-dom/toolbar's: selectionAnchor for a floating toolbar, blockAnchor and blockDrag for the handle.

Checks

bash
pnpm --filter foldkit-mixins-richtext typecheck
pnpm vitest run packages/mixins-richtext/test

smoke/ checks the built richtext packages the way a consumer meets them: through each package's exports map, from dist. Everything inside this workspace resolves them from source, so nothing else catches a wrong exports path, a missing file, or a wrong types condition. Build first, then:

bash
pnpm build
pnpm --filter foldkit-mixins-richtext smoke