Search page titles, headings and text across the docs.

Rust crates

canvist_extensions

The canvist StarterKit: the extensions TipTap’s StarterKit ships, built on canvist_editor and named the way TipTap names them, so documents move between the two as ProseMirror JSON.

  • Nodes: paragraph, heading (levels 1 to 6), blockquote, code block, hard break, horizontal rule, bullet list, ordered list, list item, and task list.
  • Marks: bold, italic, underline, strike, code, and link (non-inclusive, with autolinking and linking on paste).
  • Behaviour: Markdown-style input rules (##, -, 1., [ ], >, ```, ---, **bold**), TipTap’s key bindings, undo and redo keys, and a trailing paragraph.

Each extension is behind its own Cargo feature, and starter-kit (the default) enables them all, so an app compiles only what it registers.

use canvist_editor::Editor;
use canvist_editor::Env;
use canvist_extensions::HeadingLevel;
use canvist_extensions::StarterKit;

let mut builder = Editor::builder();
let kit = StarterKit::add_all(&mut builder);
let mut editor = builder.build()?;
let env = Env::headless(std::time::Duration::ZERO);

// Typed commands, dry runs, and chains: no UI, nothing magic.
if editor.can(&kit.bold.toggle(), &env)? {
	editor.chain().then(kit.bold.toggle()).then(kit.heading.set(HeadingLevel::H2)).run(&env)?;
}
let level = kit.heading.level(editor.state());

Each handle exists only if its extension was registered, so code calling an extension the app left out does not compile. Dynamic hosts use the same commands by name (editor.run_named("toggleHeading", &Attrs::new().with("level", 2), &env)), and editor.metadata_json() describes every command, query, and attribute for generated bindings.

Typing a keystroke through the whole kit (keymaps, input rules, history, and fix-ups) costs about 0.6 µs at 100 to 100,000 blocks; a space, which runs every input rule, about 3.5 µs. Run cargo bench -p canvist_extensions to reproduce.

Docs