Skip to content

Commit f6b4d01

Browse files
docs: adding sections for mermaid and driver packages (tldraw#8607)
5.0 is going to introduce 2 new packages for mermaid and the driver package. This adds in docs sections similar to what we have for sync. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 84984d7 commit f6b4d01

5 files changed

Lines changed: 329 additions & 1 deletion

File tree

apps/docs/content/docs/driver.mdx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: Driving the editor
3+
status: published
4+
author: steveruizok
5+
date: 4/28/2026
6+
order: 8
7+
keywords:
8+
- driver
9+
- automation
10+
- scripting
11+
- testing
12+
- repl
13+
- imperative
14+
- input
15+
- simulation
16+
---
17+
18+
You can drive the tldraw editor programmatically with the **`@tldraw/driver`** package. It wraps an [`Editor`](?) with an imperative, fluent API for simulating user input. You can use it for scripting, automation, REPL sessions, and writing tests.
19+
20+
## Quick start
21+
22+
Install the package alongside `tldraw`:
23+
24+
```bash
25+
npm install @tldraw/driver
26+
```
27+
28+
Wrap an [`Editor`](?) instance with a [`Driver`](?) and dispatch input:
29+
30+
```ts
31+
import { Driver } from '@tldraw/driver'
32+
33+
const driver = new Driver(editor)
34+
35+
driver.click(100, 200).pointerDown(300, 400).pointerMove(500, 600).pointerUp()
36+
37+
driver.keyPress('a')
38+
39+
driver.dispose()
40+
```
41+
42+
Every input method returns `this`, so calls can be chained. Call `dispose` when you're done so the driver can clean up its side-effect handlers.
43+
44+
## Simulating input
45+
46+
Pointer, keyboard, wheel, and pinch events all flow through `editor.dispatch`, so they go through the editor's normal tool state machines—a `pointerDown``pointerMove`... → `pointerUp` sequence against the draw tool produces real draw shapes, not an image overlay:
47+
48+
```ts
49+
editor.setCurrentTool('draw')
50+
driver.pointerDown(100, 100)
51+
driver.pointerMove(150, 120)
52+
driver.pointerMove(200, 140)
53+
driver.pointerUp()
54+
```
55+
56+
Pointer coordinates are in screen space. For page-space positions, use `editor.pageToScreen` to convert before dispatching.
57+
58+
Keyboard helpers track modifier state automatically:
59+
60+
```ts
61+
driver.keyDown('Shift')
62+
driver.click(100, 100, { target: 'canvas' })
63+
driver.keyUp('Shift')
64+
```
65+
66+
## Manipulating the selection
67+
68+
Selection helpers work in page coordinates and convert to screen space internally, so you can move, rotate, and resize the current selection without computing pointer paths by hand:
69+
70+
```ts
71+
driver.translateSelection(50, 0)
72+
driver.rotateSelection(Math.PI / 4)
73+
driver.resizeSelection({ scaleX: 2 }, 'bottom_right')
74+
```
75+
76+
## Clipboard
77+
78+
The driver keeps its own in-memory clipboard, independent of the system clipboard. Useful for scripted copy/paste flows and testing:
79+
80+
```ts
81+
driver.copy() // copies the current selection
82+
driver.paste({ x: 400, y: 400 })
83+
```
84+
85+
## Queries
86+
87+
The driver tracks shapes it has caused to be created via `editor.sideEffects`, making it easy to grab the most recent result of a scripted action:
88+
89+
```ts
90+
const shape = driver.getLastCreatedShape()
91+
const lastFive = driver.getLastCreatedShapes(5)
92+
```
93+
94+
See [`Driver`](?) for the full list of query helpers (shape/selection page centers, rotations, arrows bound to a shape, etc.).
95+
96+
## Related
97+
98+
- [`Driver`](?) — Full reference for every input, selection, clipboard, and query method
99+
- [`Editor`](?) — The editor class the driver wraps
100+
- [Shapes](/docs/shapes) — Defining shape types that driver-produced input will interact with
101+
- [Tools](/docs/tools) — Understanding the tool state machines that process simulated events

apps/docs/content/docs/llm-docs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: LLM documentation
33
status: published
44
author: steveruizok
55
date: 2/1/2026
6-
order: 8
6+
order: 9
77
keywords:
88
- llm
99
- ai

apps/docs/content/docs/mermaid.mdx

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
title: Mermaid diagrams
3+
status: published
4+
author: guillaumerichard
5+
date: 4/28/2026
6+
order: 8
7+
keywords:
8+
- mermaid
9+
- diagram
10+
- flowchart
11+
- sequence
12+
- state
13+
- mindmap
14+
- integration
15+
- parse
16+
- render
17+
- visualization
18+
---
19+
20+
You can turn [Mermaid](https://mermaid.js.org/) diagram syntax into native, editable tldraw shapes with the **`@tldraw/mermaid`** package. Instead of rendering a static SVG, it parses Mermaid text and creates real geo shapes, arrows, frames, and groups on the canvas—so users can move, resize, restyle, and connect them like any other shape.
21+
22+
## Quick start
23+
24+
Install the package alongside `tldraw`:
25+
26+
```bash
27+
npm install @tldraw/mermaid
28+
```
29+
30+
Then call [`createMermaidDiagram`](?) with an [`Editor`](?) and a Mermaid source string:
31+
32+
```tsx
33+
import { createMermaidDiagram } from '@tldraw/mermaid'
34+
35+
await createMermaidDiagram(
36+
editor,
37+
`
38+
flowchart TD
39+
A[Start] --> B{Decision}
40+
B -->|Yes| C[Do something]
41+
B -->|No| D[Do something else]
42+
`
43+
)
44+
```
45+
46+
By default the diagram is centered on the current viewport. Pass a `blueprintRender.position` to place it at a specific page point, and set `centerOnPosition: false` to anchor its top-left corner instead of its center.
47+
48+
## Supported diagram types
49+
50+
| Diagram type | Mermaid keyword | What you get |
51+
| ---------------- | -------------------- | ------------------------------------------------------------------- |
52+
| Flowchart | `flowchart`, `graph` | Geo shapes, arrows, subgraph frames |
53+
| Sequence diagram | `sequenceDiagram` | Actor shapes, lifelines, signal arrows, fragment frames |
54+
| State diagram | `stateDiagram-v2` | State shapes, transitions, compound state frames, fork/join, choice |
55+
| Mindmap | `mindmap` | Colored geo shapes, parent-child edges, tree hierarchy |
56+
57+
For unsupported types (pie, gantt, class, ER, etc.) pass an `onUnsupportedDiagram` callback—for example, to fall back to importing Mermaid's rendered SVG:
58+
59+
```tsx
60+
await createMermaidDiagram(editor, text, {
61+
onUnsupportedDiagram(svgString) {
62+
editor.putExternalContent({ type: 'svg-text', text: svgString })
63+
},
64+
})
65+
```
66+
67+
Without a callback, `createMermaidDiagram` throws a [`MermaidDiagramError`](?) for unsupported types and parse failures.
68+
69+
## Handling pasted Mermaid text
70+
71+
The most common integration is converting Mermaid text when users paste it onto the canvas. Register an external content handler that sniffs for a Mermaid keyword and dynamically imports the package:
72+
73+
```tsx
74+
import { useEffect } from 'react'
75+
import { defaultHandleExternalTextContent, useEditor } from 'tldraw'
76+
77+
const MERMAID_KEYWORD =
78+
/^\s*(flowchart|graph|sequenceDiagram|stateDiagram|classDiagram|erDiagram|gantt|pie|gitGraph|mindmap)/
79+
80+
export function MermaidPasteHandler() {
81+
const editor = useEditor()
82+
83+
useEffect(() => {
84+
editor.registerExternalContentHandler('text', async (content) => {
85+
if (!MERMAID_KEYWORD.test(content.text)) {
86+
await defaultHandleExternalTextContent(editor, content)
87+
return
88+
}
89+
90+
try {
91+
const { createMermaidDiagram } = await import('@tldraw/mermaid')
92+
await createMermaidDiagram(editor, content.text, {
93+
async onUnsupportedDiagram(svgString) {
94+
await editor.putExternalContent({ type: 'svg-text', text: svgString })
95+
},
96+
})
97+
} catch {
98+
await defaultHandleExternalTextContent(editor, content)
99+
}
100+
})
101+
}, [editor])
102+
103+
return null
104+
}
105+
```
106+
107+
Drop `<MermaidPasteHandler />` inside your [`Tldraw`](?) component and pasting Mermaid text will render it as shapes.
108+
109+
<Callout type="info">
110+
The `mermaid` dependency is ~2 MB. The pattern above pre-screens with a lightweight regex and
111+
lazy-loads `@tldraw/mermaid` only when the text matches, so users who never paste Mermaid don't
112+
pay the cost.
113+
</Callout>
114+
115+
## Customizing node shapes
116+
117+
By default, blueprint nodes are materialized as tldraw geo shapes. If you want to render them as your own custom shape type instead—for example, sticky notes for mindmap leaves, or a bespoke "actor" shape for sequence diagrams—pass `mapNodeToRenderSpec` on `blueprintRender`:
118+
119+
```tsx
120+
await createMermaidDiagram(editor, text, {
121+
blueprintRender: {
122+
mapNodeToRenderSpec(input) {
123+
if (input.diagramKind === 'mindmap') {
124+
return { variant: 'shape', type: 'note', props: {} }
125+
}
126+
// Return undefined to keep the package default for this node.
127+
return undefined
128+
},
129+
},
130+
})
131+
```
132+
133+
The callback receives `diagramKind`, `nodeId`, `kind`, and the full [`MermaidBlueprintNode`](?), and returns a [`MermaidBlueprintNodeRenderSpec`](?)—either a `geo` variant or a custom `shape` type that's registered on the editor. See [`createMermaidDiagram`](?) and [`renderBlueprint`](?) in the reference for the full API.
134+
135+
## Examples
136+
137+
- [Hundreds of mermaid diagrams](/examples/use-cases/hundred-mermaids) — A runnable demo rendering many diagram types at once
138+
- [Customizing mermaid diagrams](/examples/use-cases/custom-shape-mermaids) - Converting mermaid diagram nodes into custom shapes
139+
140+
## Related
141+
142+
- [`createMermaidDiagram`](?), [`renderBlueprint`](?), [`MermaidDiagramError`](?) — Entry points and errors
143+
- [`DiagramMermaidBlueprint`](?), [`MermaidBlueprintNode`](?), [`MermaidBlueprintNodeRenderSpec`](?) — The data model you can customize
144+
- [Shapes](/docs/shapes) — Define a custom shape you can map Mermaid nodes to
145+
- [External content handlers](/sdk-features/external-content) — More on `registerExternalContentHandler` for the paste integration

apps/docs/content/sections.json

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,46 @@
4646
"title": "API Reference",
4747
"description": "Reference for the tldraw package's APIs (generated).",
4848
"categories": [
49+
{
50+
"id": "driver",
51+
"title": "@tldraw/driver",
52+
"description": "",
53+
"groups": [
54+
{
55+
"id": "Class",
56+
"path": null
57+
},
58+
{
59+
"id": "Function",
60+
"path": null
61+
},
62+
{
63+
"id": "Variable",
64+
"path": null
65+
},
66+
{
67+
"id": "Enum",
68+
"path": null
69+
},
70+
{
71+
"id": "Interface",
72+
"path": null
73+
},
74+
{
75+
"id": "TypeAlias",
76+
"path": null
77+
},
78+
{
79+
"id": "Namespace",
80+
"path": null
81+
},
82+
{
83+
"id": "Component",
84+
"path": null
85+
}
86+
],
87+
"hero": null
88+
},
4989
{
5090
"id": "editor",
5191
"title": "@tldraw/editor",
@@ -86,6 +126,46 @@
86126
],
87127
"hero": null
88128
},
129+
{
130+
"id": "mermaid",
131+
"title": "@tldraw/mermaid",
132+
"description": "",
133+
"groups": [
134+
{
135+
"id": "Class",
136+
"path": null
137+
},
138+
{
139+
"id": "Function",
140+
"path": null
141+
},
142+
{
143+
"id": "Variable",
144+
"path": null
145+
},
146+
{
147+
"id": "Enum",
148+
"path": null
149+
},
150+
{
151+
"id": "Interface",
152+
"path": null
153+
},
154+
{
155+
"id": "TypeAlias",
156+
"path": null
157+
},
158+
{
159+
"id": "Namespace",
160+
"path": null
161+
},
162+
{
163+
"id": "Component",
164+
"path": null
165+
}
166+
],
167+
"hero": null
168+
},
89169
{
90170
"id": "state",
91171
"title": "@tldraw/state",

apps/docs/scripts/lib/package-list.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ export const TLDRAW_PACKAGES_TO_INCLUDE_IN_DOCS = [
88
'state-react',
99
'sync',
1010
'sync-core',
11+
'mermaid',
12+
'driver',
1113
]

0 commit comments

Comments
 (0)