API
import { MarkdownEditor, useMarkdownEditor } from '@zuilib/text-editor'
import '@zuilib/text-editor/styles.css'
Package entry points: . (ESM + types: the editor, the hook, the pure
drawing API and the first-party plugins), ./markdown
(the editor without the drawing canvas), ./lexical (node classes,
transformers, presets and every $-prefixed helper, for assembling your
own Lexical editor), ./drawing (the canvas on its own), ./mentions,
./comments, ./images, ./paste (the plugins on their own entries, not
on ./markdown), ./styles.css, ./package.json. DRAWING_FORMAT.md
and CHANGELOG.md ship in the package too. Hosts that only render
<MarkdownEditor> never need ./lexical; no $-name and no Lexical
node class leaves the root entry.
Component and hook
| Export | Purpose |
|---|---|
MarkdownEditor | The component. Compound parts as statics: .Root, .Content, .Toolbar, .ToolbarButton, .ToolbarDivider, .FormatButtons, .BlockButtons, .InsertButtons, .HistoryButtons, .Outline, .CharacterCount |
MarkdownEditorProps, ToolbarItems | Props of the component; the groups (format, block, insert, history) handed to a toolbar render function |
EditorRootProps, EditorContentProps, EditorMode, EditorFieldProps | Types of the compound parts |
useMarkdownEditor(), MarkdownEditorApi, BlockType | Headless hook and its return type (Toolbar) |
useEditorContext(), useLabels() | Editor context (mode, labels, field attributes) and resolved labels, for plugins |
EditorLabels, EditorLabelsInput, DeepPartial, DEFAULT_LABELS, resolveLabels | Localisation (Editor) |
CollapsibleHeadingsLabels, TableRowShortcutsLabels, TableColumnShortcutsLabels | Label types of the individual plugins |
Toolbar, ToolbarButton, ToolbarDivider, FormatButtons, BlockButtons, InsertButtons, HistoryButtons, CharacterCount | Toolbar primitives and the character counter as named exports |
useToolbarKeyboard, TOOLBAR_ITEM_ATTRIBUTE | APG toolbar keyboard pattern for your own toolbars |
isSafeUrl, SAFE_LINK_PROTOCOLS | Link validation (http, https, mailto, tel, scheme-less) |
EDIT_LINK_COMMAND | Opens the link bubble for a non-empty selection (what the toolbar link button dispatches); nothing is written until a URL is applied |
INSERT_HORIZONTAL_RULE_COMMAND | Inserts a rule after the current block (what insertHorizontalRule() dispatches) |
INSERT_FOOTNOTE_COMMAND, GOTO_FOOTNOTE_DEFINITION_COMMAND, GOTO_FOOTNOTE_REF_COMMAND | Insert a cue plus note ({ id? }; what insertFootnote() dispatches); move the caret to a note / back after its first cue |
Lexical assembly (./lexical)
For assembling your own Lexical editor with the same dialect. Use the
exported lists rather than rebuilding them: DRAWING_PRESET_NODES and
DRAWING_PRESET_TRANSFORMERS are what the default MarkdownEditor
mounts, MARKDOWN_NODES and MARKDOWN_TRANSFORMERS what ./markdown
mounts. The order is FRONTMATTER, DRAWING, DIAGRAM, LISTS,
CHECK_LIST, TABLE, CODE_BLOCK, HORIZONTAL_RULE, the three
FOOTNOTES, then Lexical's TRANSFORMERS without CODE: the fenced
blocks claim their syntax before CODE_BLOCK, LISTS and CHECK_LIST
before UNORDERED_LIST, and --- / [^id] before HEADING / LINK.
The custom headless assembly below imports Lexical directly. Declare
@lexical/headless and @lexical/markdown as direct application dependencies
for this integration; the standard MarkdownEditor install remains one
package.
import { createHeadlessEditor } from '@lexical/headless'
import { $convertFromMarkdownString } from '@lexical/markdown'
import { DRAWING_PRESET_NODES, DRAWING_PRESET_TRANSFORMERS } from '@zuilib/text-editor/lexical'
const editor = createHeadlessEditor({ namespace: 'x', nodes: DRAWING_PRESET_NODES, onError: console.error })
editor.update(() => $convertFromMarkdownString(markdown, DRAWING_PRESET_TRANSFORMERS))
| Export | Purpose |
|---|---|
DRAWING_PRESET, DRAWING_PRESET_NODES, DRAWING_PRESET_TRANSFORMERS | The default entry's preset and its node / transformer lists |
MARKDOWN_PRESET, MARKDOWN_NODES, MARKDOWN_TRANSFORMERS | The same without drawings (./markdown) |
createMarkdownEditor(preset), EditorPreset, TransformersInput | Build the component around a preset of nodes, transformers and plugins (Extending) |
resolveTransformers(defaults, prop), shortcutTransformers(list) | How the transformers prop is merged; which of the result double as typing shortcuts |
editorNodeClassNames, mergeNodeClassNames | The built-in node class names and the merge behind the nodeClassNames prop |
$replaceMarkdown(markdown, transformers), replaceMarkdown, EXTERNAL_UPDATE_TAG | Replace the whole document from markdown inside editor.update; what the controlled value prop uses, keeps the caret position when it still exists |
TABLE | GFM table transformer |
LISTS | Nested lists: 2 or 4 spaces on import, 2 on export |
CODE_BLOCK | Fenced code transformer; untagged blocks export as bare fences |
FRONTMATTER, FrontmatterNode, $createFrontmatterNode, $isFrontmatterNode, SerializedFrontmatterNode | Frontmatter block |
HORIZONTAL_RULE, HorizontalRuleNode, $createHorizontalRuleNode, $isHorizontalRuleNode | Thematic break (---); the node is Lexical's own |
FootnoteRefNode, FootnoteDefinitionNode, FootnoteSectionNode (+ $create*, $is*, Serialized*), FOOTNOTES, FOOTNOTE_DEFINITION, FOOTNOTE_CONTINUATION, FOOTNOTE_REF | Footnote cue, note and section nodes and their GFM transformers |
$insertFootnote(id?), $normalizeFootnotes(), $computeFootnoteNumbers(), $collectFootnoteRefs(), $getFootnoteSection(), $getFootnoteDefinitions(), $findFootnoteDefinition(id), $selectFootnoteDefinition(id), $selectFootnoteRef(id), $getSelectedFootnoteDefinition(), $nextFootnoteId(), FootnotesPlugin | Footnote model (inside editor.update / read); the plugin keeps the section last and sorted, numbers the cues and wires the keys — the root mounts it |
DRAWING, DIAGRAM, DrawingNode, $createDrawingNode, $isDrawingNode, SerializedDrawingNode | Drawing node and its two transformers (```drawing and ```diagram). Also on ./drawing |
$getSelectedTable, $getTableSettings, $setTableSettings, $isTableWidthExplicit, $getTableWidth, $setTableWidth, $getTableDensity, $setTableDensity | Table setting helpers, inside editor.update / read |
$getSelectedTableCell, $getTableCellPosition | Where the selection is |
$insertTableRowAt, $deleteTableRowAt, $insertTableRowNear, $deleteTableRowNear | Row operations |
$insertTableColumnAt, $deleteTableColumnAt, $insertTableColumnNear, $deleteTableColumnNear | Column operations |
codeTokenizer, registerCodeBlockHighlighting | Lexical tokenizer adapter and editor wiring for code highlighting |
MentionNode, $createMentionNode, $isMentionNode, MENTION; ImageNode, $createImageNode, $isImageNode, $getSelectedImage, IMAGE; COMMENT, $getMarkNodes, $getCommentIds, $removeComment, $plainTextOffset | The first-party plugin nodes and helpers (also on their own entries) |
Tables
| Export | Purpose |
|---|---|
TableDensity, TableSettings, TableSettingsOptions, DEFAULT_TABLE_SETTINGS | Setting types and defaults |
parseTableSettingsMarker, formatTableSettingsMarker | Marker comment ⇄ TableSettings |
TABLE_WIDTH_MARKER | Deprecated; use formatTableSettingsMarker |
TableCellPosition | Where the selection is |
insertableRowIndices, insertableColumnIndices, canDeleteRow, canDeleteColumn | Pure guards for custom toolbars |
The $-prefixed table helpers are on ./lexical.
Block width
| Export | Purpose |
|---|---|
BlockWidth | 'full' | 'text' | 'content' |
BLOCK_WIDTHS, isBlockWidth | Values and type guard |
NewBlockWidths | Shape of the newBlockWidth prop |
Drawing payload
| Export | Purpose |
|---|---|
DrawingData, DrawingShape, DrawingShapeType, NodeShapeType, ConnectorType, Binding, BindingSide, Point | Payload types |
deserializeDrawingData, serializeDrawingData, normalizeDrawingData | Lenient parse (version 2 payloads migrate to version 3), serialise, re-anchor bindings |
DRAWING_DATA_JSON_SCHEMA | JSON Schema of the payload |
isNodeShapeType, NODE_SHAPE_TYPES, CONNECTOR_TYPES, SHAPE_TYPES, SIDE_FIXED_POINTS, STROKE_COLORS, FILL_COLORS, EMPTY_DRAWING | Constants and guards |
NODE_SHAPE_DEFINITIONS, NodeShapeDefinition, TextField | Data-driven shape geometry and text slots |
findNodeShapeAt, createBinding | Hit-test a node shape; build a binding |
DrawingPlugin, INSERT_DRAWING_COMMAND, DRAWING_FOCUS_COMMAND | Handles insertion (the hook's insertDrawing dispatches the command); the canvas reports focus through the second. Also on ./drawing |
DrawingStyle | 'clean' | 'ink' (Diagrams) |
Geometry internals (binding resolution, elbow routing, ink rendering, outline math) are implementation details and are not exported.
Skeleton and Mermaid
| Export | Purpose |
|---|---|
DrawingSkeleton, SkeletonBox, SkeletonConnector, SkeletonEnd, SkeletonText, ColorName | Skeleton types |
parseDrawingSkeleton, isDrawingSkeleton, expandDrawingSkeleton | Parse and expand to DrawingData |
DRAWING_SKELETON_JSON_SCHEMA, COLOR_PRESETS | JSON Schema; palette name → stroke / fill |
drawingToMermaid, MermaidOptions, MermaidDirection | Mermaid flowchart export |
Code highlighting
| Export | Purpose |
|---|---|
CodeGrammar, CodeRule, CodeToken, CodeTokenType | Grammar and token types |
registerCodeLanguage, hasCodeLanguage, resolveCodeLanguage, getCodeLanguages | Registry (built-ins load on first lookup) |
tokenizeCode | The lexer, for use outside the editor |
BUILTIN_CODE_LANGUAGES, CODE_TOKEN_TYPES, PLAIN_LANGUAGE | Constants |
The Lexical wiring (codeTokenizer, registerCodeBlockHighlighting) is
on ./lexical.