1- import { Editor } from "@tiptap/core" ;
21import { Node } from "prosemirror-model" ;
32
43import type { BlockNoteEditor } from "../../editor/BlockNoteEditor" ;
54import {
5+ Block ,
66 BlockIdentifier ,
77 BlockSchema ,
88 InlineContentSchema ,
99 PartialBlock ,
1010 StyleSchema ,
1111} from "../../schema" ;
12- import { blockToNode } from "../nodeConversions/nodeConversions" ;
12+ import { blockToNode , nodeToBlock } from "../nodeConversions/nodeConversions" ;
1313import { getNodeById } from "../nodeUtil" ;
1414import { Transaction } from "prosemirror-state" ;
1515
@@ -22,7 +22,7 @@ export function insertBlocks<
2222 referenceBlock : BlockIdentifier ,
2323 placement : "before" | "after" | "nested" = "before" ,
2424 editor : BlockNoteEditor < BSchema , I , S >
25- ) : void {
25+ ) : Block < BSchema , I , S > [ ] {
2626 const ttEditor = editor . _tiptapEditor ;
2727
2828 const id =
@@ -35,39 +35,53 @@ export function insertBlocks<
3535 ) ;
3636 }
3737
38- let insertionPos = - 1 ;
39-
4038 const { node, posBeforeNode } = getNodeById ( id , ttEditor . state . doc ) ;
4139
4240 if ( placement === "before" ) {
43- insertionPos = posBeforeNode ;
41+ ttEditor . view . dispatch (
42+ ttEditor . state . tr . insert ( posBeforeNode , nodesToInsert )
43+ ) ;
4444 }
4545
4646 if ( placement === "after" ) {
47- insertionPos = posBeforeNode + node . nodeSize ;
47+ ttEditor . view . dispatch (
48+ ttEditor . state . tr . insert ( posBeforeNode + node . nodeSize , nodesToInsert )
49+ ) ;
4850 }
4951
5052 if ( placement === "nested" ) {
5153 // Case if block doesn't already have children.
5254 if ( node . childCount < 2 ) {
53- insertionPos = posBeforeNode + node . firstChild ! . nodeSize + 1 ;
54-
5555 const blockGroupNode = ttEditor . state . schema . nodes [ "blockGroup" ] . create (
5656 { } ,
5757 nodesToInsert
5858 ) ;
5959
6060 ttEditor . view . dispatch (
61- ttEditor . state . tr . insert ( insertionPos , blockGroupNode )
61+ ttEditor . state . tr . insert (
62+ posBeforeNode + node . firstChild ! . nodeSize + 1 ,
63+ blockGroupNode
64+ )
6265 ) ;
63-
64- return ;
6566 }
67+ }
6668
67- insertionPos = posBeforeNode + node . firstChild ! . nodeSize + 2 ;
69+ // Now that the `PartialBlock`s have been converted to nodes, we can
70+ // re-convert them into full `Block`s.
71+ const insertedBlocks : Block < BSchema , I , S > [ ] = [ ] ;
72+ for ( const node of nodesToInsert ) {
73+ insertedBlocks . push (
74+ nodeToBlock (
75+ node ,
76+ editor . blockSchema ,
77+ editor . inlineContentSchema ,
78+ editor . styleSchema ,
79+ editor . blockCache
80+ )
81+ ) ;
6882 }
6983
70- ttEditor . view . dispatch ( ttEditor . state . tr . insert ( insertionPos , nodesToInsert ) ) ;
84+ return insertedBlocks ;
7185}
7286
7387export function updateBlock <
@@ -77,37 +91,56 @@ export function updateBlock<
7791> (
7892 blockToUpdate : BlockIdentifier ,
7993 update : PartialBlock < BSchema , I , S > ,
80- editor : Editor
81- ) {
94+ editor : BlockNoteEditor < BSchema , I , S >
95+ ) : Block < BSchema , I , S > {
96+ const ttEditor = editor . _tiptapEditor ;
97+
8298 const id =
8399 typeof blockToUpdate === "string" ? blockToUpdate : blockToUpdate . id ;
84- const { posBeforeNode } = getNodeById ( id , editor . state . doc ) ;
100+ const { posBeforeNode } = getNodeById ( id , ttEditor . state . doc ) ;
85101
86- editor . commands . BNUpdateBlock ( posBeforeNode + 1 , update ) ;
102+ ttEditor . commands . BNUpdateBlock ( posBeforeNode + 1 , update ) ;
103+
104+ const blockContainerNode = ttEditor . state . doc
105+ . resolve ( posBeforeNode + 1 )
106+ . node ( ) ;
107+
108+ return nodeToBlock (
109+ blockContainerNode ,
110+ editor . blockSchema ,
111+ editor . inlineContentSchema ,
112+ editor . styleSchema ,
113+ editor . blockCache
114+ ) ;
87115}
88116
89- function removeBlocksWithCallback (
117+ function removeBlocksWithCallback <
118+ BSchema extends BlockSchema ,
119+ I extends InlineContentSchema ,
120+ S extends StyleSchema
121+ > (
90122 blocksToRemove : BlockIdentifier [ ] ,
91- editor : Editor ,
123+ editor : BlockNoteEditor < BSchema , I , S > ,
92124 // Should return new removedSize.
93125 callback ?: (
94126 node : Node ,
95127 pos : number ,
96128 tr : Transaction ,
97129 removedSize : number
98130 ) => number
99- ) {
100- const tr = editor . state . tr ;
131+ ) : Block < BSchema , I , S > [ ] {
132+ const ttEditor = editor . _tiptapEditor ;
133+ const tr = ttEditor . state . tr ;
101134
102135 const idsOfBlocksToRemove = new Set < string > (
103136 blocksToRemove . map ( ( block ) =>
104137 typeof block === "string" ? block : block . id
105138 )
106139 ) ;
107-
140+ const removedBlocks : Block < BSchema , I , S > [ ] = [ ] ;
108141 let removedSize = 0 ;
109142
110- editor . state . doc . descendants ( ( node , pos ) => {
143+ ttEditor . state . doc . descendants ( ( node , pos ) => {
111144 // Skips traversing nodes after all target blocks have been removed.
112145 if ( idsOfBlocksToRemove . size === 0 ) {
113146 return false ;
@@ -121,10 +154,20 @@ function removeBlocksWithCallback(
121154 return true ;
122155 }
123156
124- removedSize = callback ?.( node , pos , tr , removedSize ) || removedSize ;
125-
157+ // Saves the block that is being deleted.
158+ removedBlocks . push (
159+ nodeToBlock (
160+ node ,
161+ editor . blockSchema ,
162+ editor . inlineContentSchema ,
163+ editor . styleSchema ,
164+ editor . blockCache
165+ )
166+ ) ;
126167 idsOfBlocksToRemove . delete ( node . attrs . id ) ;
127168
169+ // Removes the block and calculates the change in document size.
170+ removedSize = callback ?.( node , pos , tr , removedSize ) || removedSize ;
128171 const oldDocSize = tr . doc . nodeSize ;
129172 tr . delete ( pos - removedSize - 1 , pos - removedSize + node . nodeSize + 1 ) ;
130173 const newDocSize = tr . doc . nodeSize ;
@@ -133,6 +176,7 @@ function removeBlocksWithCallback(
133176 return false ;
134177 } ) ;
135178
179+ // Throws an error if now all blocks could be found.
136180 if ( idsOfBlocksToRemove . size > 0 ) {
137181 const notFoundIds = [ ...idsOfBlocksToRemove ] . join ( "\n" ) ;
138182
@@ -142,14 +186,20 @@ function removeBlocksWithCallback(
142186 ) ;
143187 }
144188
145- editor . view . dispatch ( tr ) ;
189+ ttEditor . view . dispatch ( tr ) ;
190+
191+ return removedBlocks ;
146192}
147193
148- export function removeBlocks (
194+ export function removeBlocks <
195+ BSchema extends BlockSchema ,
196+ I extends InlineContentSchema ,
197+ S extends StyleSchema
198+ > (
149199 blocksToRemove : BlockIdentifier [ ] ,
150- editor : Editor
151- ) {
152- removeBlocksWithCallback ( blocksToRemove , editor ) ;
200+ editor : BlockNoteEditor < BSchema , I , S >
201+ ) : Block < BSchema , I , S > [ ] {
202+ return removeBlocksWithCallback ( blocksToRemove , editor ) ;
153203}
154204
155205export function replaceBlocks <
@@ -160,24 +210,24 @@ export function replaceBlocks<
160210 blocksToRemove : BlockIdentifier [ ] ,
161211 blocksToInsert : PartialBlock < BSchema , I , S > [ ] ,
162212 editor : BlockNoteEditor < BSchema , I , S >
163- ) {
213+ ) : {
214+ insertedBlocks : Block < BSchema , I , S > [ ] ;
215+ removedBlocks : Block < BSchema , I , S > [ ] ;
216+ } {
164217 const ttEditor = editor . _tiptapEditor ;
165218
166219 const nodesToInsert : Node [ ] = [ ] ;
167- for ( const blockSpec of blocksToInsert ) {
168- nodesToInsert . push (
169- blockToNode ( blockSpec , ttEditor . schema , editor . styleSchema )
170- ) ;
220+ for ( const block of blocksToInsert ) {
221+ nodesToInsert . push ( blockToNode ( block , ttEditor . schema , editor . styleSchema ) ) ;
171222 }
172223
173224 const idOfFirstBlock =
174225 typeof blocksToRemove [ 0 ] === "string"
175226 ? blocksToRemove [ 0 ]
176227 : blocksToRemove [ 0 ] . id ;
177-
178- removeBlocksWithCallback (
228+ const removedBlocks = removeBlocksWithCallback (
179229 blocksToRemove ,
180- ttEditor ,
230+ editor ,
181231 ( node , pos , tr , removedSize ) => {
182232 if ( node . attrs . id === idOfFirstBlock ) {
183233 const oldDocSize = tr . doc . nodeSize ;
@@ -190,4 +240,21 @@ export function replaceBlocks<
190240 return removedSize ;
191241 }
192242 ) ;
243+
244+ // Now that the `PartialBlock`s have been converted to nodes, we can
245+ // re-convert them into full `Block`s.
246+ const insertedBlocks : Block < BSchema , I , S > [ ] = [ ] ;
247+ for ( const node of nodesToInsert ) {
248+ insertedBlocks . push (
249+ nodeToBlock (
250+ node ,
251+ editor . blockSchema ,
252+ editor . inlineContentSchema ,
253+ editor . styleSchema ,
254+ editor . blockCache
255+ )
256+ ) ;
257+ }
258+
259+ return { insertedBlocks, removedBlocks } ;
193260}
0 commit comments