@mbsks/mtplatx-tiptap-format-blocks
v0.1.0
Published
Mixed-format blocks for any TipTap editor. One extension gives you the `FormatBlock` node (a block whose content is a single declared language — Typst, LaTeX, or Markdown) with an Obsidian-style fold/preview NodeView, source editing, language guessing, an
Readme
@mbsks/mtplatx-tiptap-format-blocks
Mixed-format blocks for any TipTap editor. One extension gives you the
FormatBlock node (a block whose content is a single declared language —
Typst, LaTeX, or Markdown) with an Obsidian-style fold/preview NodeView,
source editing, language guessing, and .ms fence input — the same feature
set as @mbsks/mtplatx-editor, as a drop-in TipTap bundle.
The package wraps @mbsks/mtplatx-editor — it does not fork it. The node, the
NodeView, and the WASM pipeline are re-exported; this package only adds the
TipTap Extension glue and commands.
Install
npm install @mbsks/mtplatx-tiptap-format-blocks @mbsks/mtplatx-editor @tiptap/core@mbsks/mtplatx-tiptap-format-blocks and @tiptap/core are peer dependencies of
each other's packages; @mbsks/mtplatx-editor is a peer dependency of this
package. Inside this monorepo the packages are npm workspaces.
Quickstart
import { Editor } from "@tiptap/core";
import StarterKit from "@tiptap/starter-kit";
import { FormatBlocks, initWasm } from "@mbsks/mtplatx-tiptap-format-blocks";
// The WASM core must be ready before format blocks render.
// Call it once at app startup; the NodeView also awaits it lazily.
void initWasm();
const editor = new Editor({
element: document.querySelector("#editor")!,
extensions: [StarterKit, FormatBlocks],
content: "",
});That is it. Now:
- Type
```typst.ms(or```latex.ms,```md.ms) in a paragraph and press Space or Enter — the paragraph becomes aformatBlock. editor.commands.insertFormatBlock({ language: "typst" })inserts an empty block that opens in source-edit mode.- Each block shows a folded header (language badge + first source line) with native HTML preview; unfold, re-declare the language, or edit the source from the header controls.
editor.commands.guessFormatBlockLanguage()runs the Rust guesser on the selected block and re-tags it asguessed.
React example
import { useEffect, useRef } from "react";
import { Editor } from "@tiptap/core";
import StarterKit from "@tiptap/starter-kit";
import { FormatBlocks, initWasm, toolbarButtons } from "@mbsks/mtplatx-tiptap-format-blocks";
export function TipTapApp() {
const host = useRef<HTMLDivElement>(null);
const editor = useRef<Editor | null>(null);
useEffect(() => {
void initWasm();
editor.current = new Editor({
element: host.current!,
extensions: [StarterKit, FormatBlocks],
content: "",
});
return () => editor.current?.destroy();
}, []);
return (
<div>
{toolbarButtons().map((def) => (
<button
key={def.language}
title={def.title}
onClick={() => editor.current?.chain().focus().insertFormatBlock({ language: def.language }).run()}
>
{def.label}
</button>
))}
<div ref={host} />
</div>
);
}API
Extension
| Export | Type | Description |
|--------|------|-------------|
| FormatBlocks | Extension | The bundle. Registers the formatBlock node (and its fence-input ProseMirror plugin) and the commands below. |
Options (Extension.create config, FormatBlocksOptions):
| Option | Default | Description |
|--------|---------|-------------|
| languages | ["typst", "latex", "markdown"] | Languages insertFormatBlock accepts; anything else falls back to typst. |
Commands
| Command | Arguments | Description |
|---------|-----------|-------------|
| insertFormatBlock | { language } | Insert a new formatBlock with the declared language (guessed: false), empty source. |
| toggleFormatBlockFold | — | Fold/unfold the selected block's preview (drives the NodeView header). |
| setFormatBlockLanguage | { language } | Re-declare the selected block's language (guessed: false). |
| guessFormatBlockLanguage | — | Run the guesser on the selected block; applies the suggestion with guessed: true when one clears the confidence floor. Returns false if the WASM core is not ready or no suggestion exists. |
Node
FormatBlock (re-exported from @mbsks/mtplatx-editor) — block-level atom node:
| Attr | Type | Description |
|------|------|-------------|
| language | "typst" \| "latex" \| "markdown" (default "typst") | The declared language of the block's source. |
| source | string (default "") | The byte-exact source. |
| guessed | boolean (default false) | true when the language came from the guesser, not a declaration. |
| diagnostics | Diagnostic[] (default []) | Validation / render diagnostics (not rendered to HTML). |
Re-exports
FormatBlockView (the NodeView class, for custom extension wiring),
fenceFormatBlock (the .ms fence-input plugin, standalone),
initWasm / getWasm (the WASM lifecycle — call initWasm() once before
rendering), FORMAT_BLOCK_LANGUAGES, isFormatBlockLanguage, and
toolbarButtons() (plain button defs for hosts that render their own
toolbar).
All-in-one alternative
MtplatxEditor from @mbsks/mtplatx-editor is the full editor:
modes (wysiwyg / markdown / typst / latex), document round-trips, toolbar,
math, and PDF/HTML export. Use @mbsks/mtplatx-tiptap-format-blocks when you want
to stay in your own TipTap setup.
