From b33121c8d2d7c28111047d1971453fce37eebd1a Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 9 Dec 2025 07:37:00 +0100 Subject: [PATCH] fix: put back `onBeforeChange` method #2221 --- .../core/src/editor/BlockNoteEditor.test.ts | 60 +++++++++++++++++++ packages/core/src/editor/BlockNoteEditor.ts | 17 ++++++ 2 files changed, 77 insertions(+) diff --git a/packages/core/src/editor/BlockNoteEditor.test.ts b/packages/core/src/editor/BlockNoteEditor.test.ts index bb15b66858..55435a083b 100644 --- a/packages/core/src/editor/BlockNoteEditor.test.ts +++ b/packages/core/src/editor/BlockNoteEditor.test.ts @@ -6,6 +6,7 @@ import { getNearestBlockPos, } from "../api/getBlockInfoFromPos.js"; import { BlockNoteEditor } from "./BlockNoteEditor.js"; +import { BlocksChanged } from "../api/getBlocksChangedByTransaction.js"; /** * @vitest-environment jsdom @@ -190,3 +191,62 @@ it("sets an initial block id when using Y.js", async () => { `"Hello"`, ); }); + +it("onBeforeChange", () => { + const editor = BlockNoteEditor.create(); + let beforeChangeCalled = false; + let changes: BlocksChanged = []; + editor.onBeforeChange(({ getChanges }) => { + beforeChangeCalled = true; + changes = getChanges(); + return true; + }); + editor.mount(document.createElement("div")); + editor.replaceBlocks(editor.document, [ + { + type: "paragraph", + content: [{ text: "Hello", styles: {}, type: "text" }], + }, + ]); + expect(beforeChangeCalled).toBe(true); + expect(changes).toMatchInlineSnapshot(` + [ + { + "block": { + "children": [], + "content": [], + "id": "3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + "prevBlock": undefined, + "source": { + "type": "local", + }, + "type": "insert", + }, + { + "block": { + "children": [], + "content": [], + "id": "2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + "prevBlock": undefined, + "source": { + "type": "local", + }, + "type": "delete", + }, + ] + `); +}); diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index 35ecd5265f..545fd3955f 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -52,6 +52,7 @@ import { } from "./managers/index.js"; import type { Selection } from "./selectionTypes.js"; import { transformPasted } from "./transformPasted.js"; +import { BlockChangeExtension } from "../extensions/index.js"; export type BlockCache< BSchema extends BlockSchema = any, @@ -904,6 +905,22 @@ export class BlockNoteEditor< this._tiptapEditor.on("selectionUpdate", callback); } + /** + * Executes a callback before any change is applied to the editor, allowing you to cancel the change. + * @param callback The callback to execute. + * @returns A function to remove the callback. + */ + public onBeforeChange( + callback: (context: { + getChanges: () => BlocksChanged; + tr: Transaction; + }) => boolean | void, + ) { + return this._extensionManager + .getExtension(BlockChangeExtension) + ?.subscribe(callback); + } + /** * Gets a snapshot of the current text cursor position. * @returns A snapshot of the current text cursor position.