Skip to content

Commit 03edfae

Browse files
authored
feat: add undo and redo methods to editor API (#1592)
1 parent 0fb6323 commit 03edfae

File tree

10 files changed

+222
-130
lines changed

10 files changed

+222
-130
lines changed

docs/pages/docs/editor-api/_meta.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"export-to-pdf": "",
88
"export-to-docx": "",
99
"export-to-odt": "",
10-
"events": ""
10+
"events": "",
11+
"methods": ""
1112
}
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
title: Methods
3+
description: BlockNote provides a number of methods to interact with the editor.
4+
imageTitle: Methods
5+
path: /docs/methods
6+
---
7+
8+
import { Example } from "@/components/example";
9+
10+
# Methods
11+
12+
BlockNote provides a number of methods to interact with the editor.
13+
14+
## `undo`
15+
16+
The `undo` method is used to undo the last action.
17+
18+
```typescript
19+
editor.undo();
20+
```
21+
22+
## `redo`
23+
24+
The `redo` method is used to redo the last action.
25+
26+
```typescript
27+
editor.redo();
28+
```
29+
30+
## `exec`
31+
32+
The `exec` method executes a prosemirror command. This is mostly for backwards compatibility with older code.
33+
34+
You should prefer the `transact` method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.
35+
36+
```typescript
37+
// Example of a custom command
38+
function insertTextCommand(state: EditorState, dispatch: EditorDispatch, view: EditorView) {
39+
if (dispatch) {
40+
dispatch(state.tr.insertText("Hello, world!"));
41+
}
42+
}
43+
44+
editor.exec(insertTextCommand);
45+
```
46+
47+
## `canExec`
48+
49+
The `canExec` method checks if a prosemirror command can be executed.
50+
51+
```typescript
52+
const canExecute = editor.canExec(insertTextCommand);
53+
```
54+
55+
## `transact`
56+
57+
The `transact` method executes a prosemirror transaction. See the [low-level APIs](/docs/editor-api/manipulating-blocks#blocknote-transactions) section for more information.
58+
59+
```typescript
60+
editor.transact((tr) => {
61+
tr.insertText("Hello, world!");
62+
});
63+
```
64+
65+
## `pasteHTML`
66+
67+
The `pasteHTML` method pastes HTML into the editor.
68+
69+
```typescript
70+
editor.pasteHTML("<p>Hello, world!</p>");
71+
```
72+
73+
## `pasteText`
74+
75+
The `pasteText` method pastes text into the editor.
76+
77+
```typescript
78+
editor.pasteText("Hello, world!");
79+
```
80+
81+
## `pasteMarkdown`
82+
83+
The `pasteMarkdown` method pastes markdown into the editor.
84+
85+
```typescript
86+
editor.pasteMarkdown("**Hello, world!**");
87+
```

examples/07-collaboration/02-liveblocks/.bnexample.json

+6-10
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22
"playground": true,
33
"docs": true,
44
"author": "yousefed",
5-
"tags": [
6-
"Advanced",
7-
"Saving/Loading",
8-
"Collaboration"
9-
],
5+
"tags": ["Advanced", "Saving/Loading", "Collaboration"],
106
"dependencies": {
11-
"@liveblocks/client": "^2.22.3",
12-
"@liveblocks/react": "^2.22.3",
13-
"@liveblocks/react-blocknote": "^2.22.3",
14-
"@liveblocks/react-tiptap": "^2.22.3",
15-
"@liveblocks/react-ui": "^2.22.3",
7+
"@liveblocks/client": "^2.23.1",
8+
"@liveblocks/react": "^2.23.1",
9+
"@liveblocks/react-blocknote": "^2.23.1",
10+
"@liveblocks/react-tiptap": "^2.23.1",
11+
"@liveblocks/react-ui": "^2.23.1",
1612
"yjs": "^13.6.15"
1713
}
1814
}

examples/07-collaboration/02-liveblocks/package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
"@blocknote/shadcn": "latest",
1818
"react": "^18.3.1",
1919
"react-dom": "^18.3.1",
20-
"@liveblocks/client": "^2.22.3",
21-
"@liveblocks/react": "^2.22.3",
22-
"@liveblocks/react-blocknote": "^2.22.3",
23-
"@liveblocks/react-tiptap": "^2.22.3",
24-
"@liveblocks/react-ui": "^2.22.3",
20+
"@liveblocks/client": "^2.23.1",
21+
"@liveblocks/react": "^2.23.1",
22+
"@liveblocks/react-blocknote": "^2.23.1",
23+
"@liveblocks/react-tiptap": "^2.23.1",
24+
"@liveblocks/react-ui": "^2.23.1",
2525
"yjs": "^13.6.15"
2626
},
2727
"devDependencies": {

packages/core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
"remark-stringify": "^11.0.0",
112112
"unified": "^11.0.5",
113113
"uuid": "^8.3.2",
114-
"y-prosemirror": "^1.3.3",
114+
"y-prosemirror": "^1.3.4",
115115
"y-protocols": "^1.0.6",
116116
"yjs": "^13.6.15"
117117
},

packages/core/src/editor/BlockNoteEditor.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ import {
101101
} from "@tiptap/pm/state";
102102
import { dropCursor } from "prosemirror-dropcursor";
103103
import { EditorView } from "prosemirror-view";
104-
import { ySyncPluginKey } from "y-prosemirror";
104+
import { undoCommand, redoCommand, ySyncPluginKey } from "y-prosemirror";
105+
import { undo, redo } from "@tiptap/pm/history";
105106
import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer.js";
106107
import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js";
107108
import { nodeToBlock } from "../api/nodeConversions/nodeToBlock.js";
@@ -1199,6 +1200,27 @@ export class BlockNoteEditor<
11991200
);
12001201
}
12011202

1203+
/**
1204+
* Undo the last action.
1205+
*/
1206+
public undo() {
1207+
if (this.options.collaboration) {
1208+
return this.exec(undoCommand);
1209+
}
1210+
1211+
return this.exec(undo);
1212+
}
1213+
1214+
/**
1215+
* Redo the last action.
1216+
*/
1217+
public redo() {
1218+
if (this.options.collaboration) {
1219+
return this.exec(redoCommand);
1220+
}
1221+
return this.exec(redo);
1222+
}
1223+
12021224
/**
12031225
* Insert a piece of content at the current cursor position.
12041226
*

packages/server-util/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@tiptap/core": "^2.7.1",
6161
"@tiptap/pm": "^2.7.1",
6262
"jsdom": "^25.0.1",
63-
"y-prosemirror": "^1.3.3",
63+
"y-prosemirror": "^1.3.4",
6464
"y-protocols": "^1.0.6",
6565
"yjs": "^13.6.15"
6666
},

playground/package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
"@blocknote/xl-pdf-exporter": "workspace:^",
2626
"@emotion/react": "^11.11.4",
2727
"@emotion/styled": "^11.11.5",
28-
"@liveblocks/core": "^2.22.3",
29-
"@liveblocks/react": "^2.22.3",
30-
"@liveblocks/react-blocknote": "^2.22.3",
31-
"@liveblocks/react-tiptap": "^2.22.3",
32-
"@liveblocks/react-ui": "^2.22.3",
28+
"@liveblocks/core": "^2.23.1",
29+
"@liveblocks/react": "^2.23.1",
30+
"@liveblocks/react-blocknote": "^2.23.1",
31+
"@liveblocks/react-tiptap": "^2.23.1",
32+
"@liveblocks/react-ui": "^2.23.1",
3333
"@mantine/core": "^7.10.1",
3434
"@mui/icons-material": "^5.16.1",
3535
"@mui/material": "^5.16.1",

playground/src/examples.gen.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1241,11 +1241,11 @@
12411241
"Collaboration"
12421242
],
12431243
"dependencies": {
1244-
"@liveblocks/client": "^2.22.3",
1245-
"@liveblocks/react": "^2.22.3",
1246-
"@liveblocks/react-blocknote": "^2.22.3",
1247-
"@liveblocks/react-tiptap": "^2.22.3",
1248-
"@liveblocks/react-ui": "^2.22.3",
1244+
"@liveblocks/client": "^2.23.1",
1245+
"@liveblocks/react": "^2.23.1",
1246+
"@liveblocks/react-blocknote": "^2.23.1",
1247+
"@liveblocks/react-tiptap": "^2.23.1",
1248+
"@liveblocks/react-ui": "^2.23.1",
12491249
"yjs": "^13.6.15"
12501250
} as any
12511251
},

0 commit comments

Comments
 (0)