@@ -29,7 +29,6 @@ import {
2929 BlockSchema ,
3030 PartialBlock ,
3131} from "./extensions/Blocks/api/blockTypes" ;
32- import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes" ;
3332import {
3433 DefaultBlockSchema ,
3534 defaultBlockSchema ,
@@ -42,6 +41,7 @@ import {
4241import { Selection } from "./extensions/Blocks/api/selectionTypes" ;
4342import { getBlockInfoFromPos } from "./extensions/Blocks/helpers/getBlockInfoFromPos" ;
4443
44+ import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes" ;
4545import { FormattingToolbarProsemirrorPlugin } from "./extensions/FormattingToolbar/FormattingToolbarPlugin" ;
4646import { HyperlinkToolbarProsemirrorPlugin } from "./extensions/HyperlinkToolbar/HyperlinkToolbarPlugin" ;
4747import { ImageToolbarProsemirrorPlugin } from "./extensions/ImageToolbar/ImageToolbarPlugin" ;
@@ -217,6 +217,12 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
217217
218218 this . uploadFile = newOptions . uploadFile ;
219219
220+ if ( newOptions . collaboration && newOptions . initialContent ) {
221+ console . warn (
222+ "When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider"
223+ ) ;
224+ }
225+
220226 const initialContent =
221227 newOptions . initialContent ||
222228 ( options . collaboration
@@ -233,20 +239,35 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
233239 ...newOptions . _tiptapOptions ,
234240 onBeforeCreate ( editor ) {
235241 newOptions . _tiptapOptions ?. onBeforeCreate ?.( editor ) ;
236- if ( ! initialContent ) {
237- // when using collaboration
238- return ;
239- }
240-
241242 // We always set the initial content to a single paragraph block. This
242243 // allows us to easily replace it with the actual initial content once
243244 // the TipTap editor is initialized.
244245 const schema = editor . editor . schema ;
246+
247+ // This is a hack to make "initial content detection" by y-prosemirror (and also tiptap isEmpty)
248+ // properly detect whether or not the document has changed.
249+ // We change the doc.createAndFill function to make sure the initial block id is set, instead of null
250+ let cache : any ;
251+ const oldCreateAndFill = schema . nodes . doc . createAndFill ;
252+ ( schema . nodes . doc as any ) . createAndFill = ( ...args : any ) => {
253+ if ( cache ) {
254+ return cache ;
255+ }
256+ const ret = oldCreateAndFill . apply ( schema . nodes . doc , args ) ;
257+
258+ // create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)
259+ const jsonNode = JSON . parse ( JSON . stringify ( ret ! . toJSON ( ) ) ) ;
260+ jsonNode . content [ 0 ] . content [ 0 ] . attrs . id = "initialBlockId" ;
261+
262+ cache = Node . fromJSON ( schema , jsonNode ) ;
263+ return ret ;
264+ } ;
265+
245266 const root = schema . node (
246267 "doc" ,
247268 undefined ,
248269 schema . node ( "blockGroup" , undefined , [
249- blockToNode ( { id : "initialBlock " , type : "paragraph" } , schema ) ,
270+ blockToNode ( { id : "initialBlockId " , type : "paragraph" } , schema ) ,
250271 ] )
251272 ) ;
252273 editor . editor . options . content = root . toJSON ( ) ;
0 commit comments