hybricmark
v0.1.7
Published
A headless, Typora-like Markdown editor for React, built on Tiptap.
Maintainers
Readme
hybricmark
Headless, Typora-like Markdown editor for React. Built on Tiptap.
- Live docs: https://txlan.top
- Playground: https://txlan.top/playground
Recent Updates (v0.1.6)
- Removed custom
Deleteinterception in keyboard behavior to restore native ProseMirror forward-delete flow. - Kept stable list/headline editing path by avoiding aggressive key remapping in core editing shortcuts.
- Refreshed docs (
README+www/docs) for app-level outline integration (onDebouncedUpdate, heading extraction, click-to-scroll contract). v0.1.2build stability fix remains (stable Vite 7 output, browser-safe ESM build).
Previous Fixes (v0.1.2)
- Fixed browser runtime error in ESM consumers:
Calling 'require' for "react" in an environment that doesn't expose the require function.
- Root cause was unstable bundler output in library build.
- Build pipeline is now pinned to stable Vite 7 to keep
dist/hybricmark.es.jsbrowser-safe.
Why HybricMark
- Block-level UUIDs via
attrs.idfor product workflows (comments, references, patch updates). - Typora-style writing UX (context menu + keyboard shortcuts + markdown shortcuts).
- Built-in table controls, footnotes, math, task lists, link interaction, and image support.
- Uncontrolled editor architecture optimized for IME safety and large-document usage.
Install
npm install hybricmark @tiptap/core @tiptap/react @tiptap/starter-kit react react-domQuick Start
import { useState } from 'react'
import { HybricEditor } from 'hybricmark'
import 'hybricmark/style.css'
import 'katex/dist/katex.min.css'
export default function App() {
const [doc, setDoc] = useState<object | null>(null)
return (
<div style={{ maxWidth: 920, margin: '40px auto' }}>
<HybricEditor
content="# Hello HybricMark\n\nType '/' for commands..."
debounceMs={800}
onChange={(editor) => setDoc(editor.getJSON())}
onDebouncedUpdate={({ editor }) => {
// Persist to DB/API here
console.log('save', editor.getJSON())
}}
/>
<pre style={{ marginTop: 20, fontSize: 12 }}>
{JSON.stringify(doc, null, 2)}
</pre>
</div>
)
}Core API
HybricEditor props (high-level):
content?: string | JSONContenteditable?: booleanplaceholder?: stringextensions?: Extension[]editorProps?: EditorPropsdebounceMs?: numberonChange?: (editor: Editor) => voidonUpdate?: ({ editor, transaction }) => voidonDebouncedUpdate?: ({ editor, transaction }) => voidonExtract?: (data: { id: string; content: JSONContent; text: string }) => void
Full reference: https://txlan.top/docs/api
Outline / Contents Integration (App Side)
HybricMark keeps editor core focused and exposes update hooks so the app can own outline UI.
Recommended flow:
- Use
onDebouncedUpdatefor low-noise heading extraction. - Build a heading list from
editor.getJSON()(H1~H3 or your own depth). - Render the list in your right-side Contents panel.
- On click, resolve heading block and scroll/focus to it in the editor surface.
Example shape:
type OutlineItem = {
id: string
level: number
text: string
blockId?: string
}This keeps typing smooth (no per-keystroke outline re-render) and makes app UX fully customizable.
Block Identity Example
{
"type": "paragraph",
"attrs": {
"id": "f7652fb0-0815-4f41-9efb-b67fe7b18390"
},
"content": [{ "type": "text", "text": "Block-level targeting" }]
}Notes for Next.js
- Mount editor client-side (
dynamic(..., { ssr: false })) for editing surfaces. - Keep editor uncontrolled during typing (especially Chinese IME scenarios).
Docs Index
- Getting started: https://txlan.top/docs/getting-started
- API reference: https://txlan.top/docs/api
- Extensions: https://txlan.top/docs/extensions
- Guides:
- Saving to DB
- Outline / Contents
- Image uploads
- Tables
- Links
- Keyboard shortcuts
- Footnotes & math
Local Development
npm run dev
npm run lint
npm run buildLicense
MIT
