Skip to content

Commit 57de41f

Browse files
committed
Merge branch 'main' into new-releases
2 parents 3a3ca4d + cefbb70 commit 57de41f

File tree

194 files changed

+3446
-3234
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+3446
-3234
lines changed

.github/workflows/build.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ jobs:
1414
name: Build
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@v2
17+
- uses: actions/checkout@v3
1818

19-
- uses: actions/setup-node@v2
19+
- uses: actions/setup-node@v3
2020
with:
2121
node-version: "18.x"
2222

2323
- name: Cache node modules
24-
uses: actions/cache@v2
24+
uses: actions/cache@v3
2525
env:
2626
cache-name: cache-node-modules
2727
with:
@@ -35,7 +35,7 @@ jobs:
3535
3636
- name: cache playwright
3737
id: playwright-cache
38-
uses: actions/cache@v2
38+
uses: actions/cache@v3
3939
with:
4040
path: ~/.cache/ms-playwright
4141
key: pw-new-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
@@ -72,7 +72,7 @@ jobs:
7272
- name: Run Playwright tests
7373
run: npx playwright test
7474

75-
- uses: actions/upload-artifact@v2
75+
- uses: actions/upload-artifact@v3
7676
if: always()
7777
with:
7878
name: playwright-report

examples/editor/src/App.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import "@blocknote/core/style.css";
33
import { BlockNoteView, useBlockNote } from "@blocknote/react";
44
import styles from "./App.module.css";
5+
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
56

67
type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any };
78

@@ -16,6 +17,7 @@ function App() {
1617
"data-test": "editor",
1718
},
1819
},
20+
uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY,
1921
});
2022

2123
// Give tests a way to get prosemirror instance

examples/editor/src/index.css

-5
This file was deleted.

examples/editor/src/main.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from "react";
22
import { createRoot } from "react-dom/client";
33
import App from "./App";
4-
import "./index.css";
54

65
window.React = React;
76

package-lock.json

+41-22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"examples/*"
77
],
88
"devDependencies": {
9-
"@playwright/experimental-ct-react": "^1.33.0",
10-
"@playwright/test": "^1.33.0",
9+
"@playwright/experimental-ct-react": "^1.38.1",
10+
"@playwright/test": "^1.38.1",
1111
"eslint": "^8.22.0",
1212
"eslint-plugin-import": "^2.28.0",
1313
"eslint-config-react-app": "^7.0.0",
@@ -20,7 +20,7 @@
2020
"scripts": {
2121
"start": "lerna run --stream --scope @blocknote/example-editor dev",
2222
"start:built": "npx serve examples/editor/dist",
23-
"test:updateSnaps": "docker run --rm -e RUN_IN_DOCKER=true --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.35.1-focal npx playwright test -u",
23+
"test:updateSnaps": "docker run --rm -e RUN_IN_DOCKER=true --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.38.1-focal npx playwright test -u",
2424
"build": "lerna run --stream build --concurrency 1",
2525
"build:site": "lerna run --stream docs:build --concurrency 1",
2626
"lint": "lerna run --stream lint",

packages/core/src/BlockNoteEditor.ts

+44-12
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import {
1111
updateBlock,
1212
} from "./api/blockManipulation/blockManipulation";
1313
import {
14+
HTMLToBlocks,
1415
blocksToHTML,
1516
blocksToMarkdown,
16-
HTMLToBlocks,
1717
markdownToBlocks,
1818
} from "./api/formatConversions/formatConversions";
1919
import {
@@ -44,6 +44,7 @@ import { getBlockInfoFromPos } from "./extensions/Blocks/helpers/getBlockInfoFro
4444

4545
import { FormattingToolbarProsemirrorPlugin } from "./extensions/FormattingToolbar/FormattingToolbarPlugin";
4646
import { HyperlinkToolbarProsemirrorPlugin } from "./extensions/HyperlinkToolbar/HyperlinkToolbarPlugin";
47+
import { ImageToolbarProsemirrorPlugin } from "./extensions/ImageToolbar/ImageToolbarPlugin";
4748
import { SideMenuProsemirrorPlugin } from "./extensions/SideMenu/SideMenuPlugin";
4849
import { BaseSlashMenuItem } from "./extensions/SlashMenu/BaseSlashMenuItem";
4950
import { SlashMenuProsemirrorPlugin } from "./extensions/SlashMenu/SlashMenuPlugin";
@@ -106,6 +107,13 @@ export type BlockNoteEditorOptions<BSchema extends BlockSchema> = {
106107
*/
107108
blockSchema: BSchema;
108109

110+
/**
111+
* A custom function to handle file uploads.
112+
* @param file The file that should be uploaded.
113+
* @returns The URL of the uploaded file.
114+
*/
115+
uploadFile: (file: File) => Promise<string>;
116+
109117
/**
110118
* When enabled, allows for collaboration between multiple users.
111119
*/
@@ -151,6 +159,9 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
151159
public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin<BSchema>;
152160
public readonly slashMenu: SlashMenuProsemirrorPlugin<BSchema, any>;
153161
public readonly hyperlinkToolbar: HyperlinkToolbarProsemirrorPlugin<BSchema>;
162+
public readonly imageToolbar: ImageToolbarProsemirrorPlugin<BSchema>;
163+
164+
public readonly uploadFile: ((file: File) => Promise<string>) | undefined;
154165

155166
constructor(
156167
private readonly options: Partial<BlockNoteEditorOptions<BSchema>> = {}
@@ -178,6 +189,7 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
178189
getDefaultSlashMenuItems(newOptions.blockSchema)
179190
);
180191
this.hyperlinkToolbar = new HyperlinkToolbarProsemirrorPlugin(this);
192+
this.imageToolbar = new ImageToolbarProsemirrorPlugin(this);
181193

182194
const extensions = getBlockNoteExtensions<BSchema>({
183195
editor: this,
@@ -195,13 +207,16 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
195207
this.formattingToolbar.plugin,
196208
this.slashMenu.plugin,
197209
this.hyperlinkToolbar.plugin,
210+
this.imageToolbar.plugin,
198211
];
199212
},
200213
});
201214
extensions.push(blockNoteUIExtension);
202215

203216
this.schema = newOptions.blockSchema;
204217

218+
this.uploadFile = newOptions.uploadFile;
219+
205220
const initialContent =
206221
newOptions.initialContent ||
207222
(options.collaboration
@@ -216,28 +231,36 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
216231
const tiptapOptions: EditorOptions = {
217232
...blockNoteTipTapOptions,
218233
...newOptions._tiptapOptions,
219-
onCreate: () => {
220-
newOptions.onEditorReady?.(this);
221-
this.ready = true;
222-
},
223234
onBeforeCreate(editor) {
224235
if (!initialContent) {
225236
// when using collaboration
226237
return;
227238
}
228-
// we have to set the initial content here, because now we can use the editor schema
229-
// which has been created at this point
230-
const schema = editor.editor.schema;
231-
const ic = initialContent.map((block) => blockToNode(block, schema));
232239

240+
// We always set the initial content to a single paragraph block. This
241+
// allows us to easily replace it with the actual initial content once
242+
// the TipTap editor is initialized.
243+
const schema = editor.editor.schema;
233244
const root = schema.node(
234245
"doc",
235246
undefined,
236-
schema.node("blockGroup", undefined, ic)
247+
schema.node("blockGroup", undefined, [
248+
blockToNode({ id: "initialBlock", type: "paragraph" }, schema),
249+
])
237250
);
238-
// override the initialcontent
239251
editor.editor.options.content = root.toJSON();
240252
},
253+
onCreate: () => {
254+
// We need to wait for the TipTap editor to init before we can set the
255+
// initial content, as the schema may contain custom blocks which need
256+
// it to render.
257+
if (initialContent !== undefined) {
258+
this.replaceBlocks(this.topLevelBlocks, initialContent);
259+
}
260+
261+
newOptions.onEditorReady?.(this);
262+
this.ready = true;
263+
},
241264
onUpdate: () => {
242265
// This seems to be necessary due to a bug in TipTap:
243266
// https://github.com/ueberdosis/tiptap/issues/2583
@@ -460,6 +483,12 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
460483
posBeforeNode + 2
461484
)!;
462485

486+
// For blocks without inline content
487+
if (contentNode.type.spec.content === "") {
488+
this._tiptapEditor.commands.setNodeSelection(startPos);
489+
return;
490+
}
491+
463492
if (placement === "start") {
464493
this._tiptapEditor.commands.setTextSelection(startPos + 1);
465494
} else {
@@ -473,9 +502,12 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
473502
* Gets a snapshot of the current selection.
474503
*/
475504
public getSelection(): Selection<BSchema> | undefined {
505+
// Either the TipTap selection is empty, or it's a node selection. In either
506+
// case, it only spans one block, so we return undefined.
476507
if (
477508
this._tiptapEditor.state.selection.from ===
478-
this._tiptapEditor.state.selection.to
509+
this._tiptapEditor.state.selection.to ||
510+
"node" in this._tiptapEditor.state.selection
479511
) {
480512
return undefined;
481513
}

0 commit comments

Comments
 (0)