@@ -8,21 +8,94 @@ import { $prosemirrorDelta } from "@y/prosemirror";
88 * `blockContent blockGroup?`) this is its block-content type (paragraph,
99 * heading, image, ...).
1010 */
11- const firstChildName = (
11+ const firstChild = (
1212 d : schema . Unwrap < typeof $prosemirrorDelta > ,
13- ) : string | null => {
13+ ) : schema . Unwrap < typeof $prosemirrorDelta > | null => {
1414 for ( const op of ( d as any ) . children ) {
1515 if ( delta . $insertOp . check ( op ) ) {
1616 for ( const it of op . insert ) {
1717 if ( delta . $deltaAny . check ( it ) ) {
18- return it . name ;
18+ return it ;
1919 }
2020 }
2121 }
2222 }
2323 return null ;
2424} ;
2525
26+ function getTableDimensions (
27+ d : schema . Unwrap < typeof $prosemirrorDelta > ,
28+ ) : { rows : number ; cols : number } | null {
29+ if ( d . name !== "table" ) {
30+ return null ;
31+ }
32+
33+ // Collect all rows with their cells' colspan/rowspan values.
34+ const rows : Array < Array < { colspan : number ; rowspan : number } > > = [ ] ;
35+ for ( const op of ( d as any ) . children ) {
36+ if ( delta . $insertOp . check ( op ) ) {
37+ for ( const tr of op . insert as Array <
38+ schema . Unwrap < typeof $prosemirrorDelta >
39+ > ) {
40+ if ( tr . name !== "tableRow" ) {
41+ return null ;
42+ }
43+ const cells : Array < { colspan : number ; rowspan : number } > = [ ] ;
44+ for ( const trOp of ( tr as any ) . children ) {
45+ if ( delta . $insertOp . check ( trOp ) ) {
46+ for ( const td of trOp . insert as Array <
47+ schema . Unwrap < typeof $prosemirrorDelta >
48+ > ) {
49+ if ( td . name !== "tableCell" && td . name !== "tableHeader" ) {
50+ return null ;
51+ }
52+ cells . push ( {
53+ colspan : Number ( td . attrs . colspan ) || 1 ,
54+ rowspan : Number ( td . attrs . rowspan ) || 1 ,
55+ } ) ;
56+ }
57+ }
58+ }
59+ rows . push ( cells ) ;
60+ }
61+ }
62+ }
63+
64+ if ( rows . length === 0 ) {
65+ return null ;
66+ }
67+
68+ // Build an occupancy grid to determine the true column count.
69+ // Each entry in `grid[r]` tracks which columns are already occupied
70+ // (by a cell from a previous row with rowspan > 1).
71+ const grid : boolean [ ] [ ] = [ ] ;
72+ for ( let r = 0 ; r < rows . length ; r ++ ) {
73+ if ( ! grid [ r ] ) {
74+ grid [ r ] = [ ] ;
75+ }
76+ let col = 0 ;
77+ for ( const cell of rows [ r ] ) {
78+ // Skip columns already occupied by a rowspan from above.
79+ while ( grid [ r ] [ col ] ) {
80+ col ++ ;
81+ }
82+ // Mark all slots this cell occupies.
83+ for ( let dr = 0 ; dr < cell . rowspan ; dr ++ ) {
84+ if ( ! grid [ r + dr ] ) {
85+ grid [ r + dr ] = [ ] ;
86+ }
87+ for ( let dc = 0 ; dc < cell . colspan ; dc ++ ) {
88+ grid [ r + dr ] [ col + dc ] = true ;
89+ }
90+ }
91+ col += cell . colspan ;
92+ }
93+ }
94+
95+ const numCols = Math . max ( ...grid . map ( ( row ) => row . length ) ) ;
96+ return { rows : rows . length , cols : numCols } ;
97+ }
98+
2699/**
27100 * BlockNote's node-pairing policy for y-prosemirror's `matchNodes` option
28101 * (forwarded to `lib0/delta.diff`). This is the schema-specific bit that lives
@@ -48,6 +121,34 @@ const firstChildName = (
48121export const blockMatchNodes = (
49122 a : schema . Unwrap < typeof $prosemirrorDelta > ,
50123 b : schema . Unwrap < typeof $prosemirrorDelta > ,
51- ) : boolean =>
52- a . name === b . name &&
53- ( a . name !== "blockContainer" || firstChildName ( a ) === firstChildName ( b ) ) ;
124+ ) : boolean => {
125+ if ( a . name !== b . name ) {
126+ return false ;
127+ }
128+
129+ if ( a . name !== "blockContainer" ) {
130+ return true ;
131+ }
132+
133+ const childA = firstChild ( a ) ;
134+ const childB = firstChild ( b ) ;
135+
136+ if ( childA ?. name !== childB ?. name ) {
137+ return false ;
138+ }
139+
140+ if ( childA ?. name === "table" && childB ?. name === "table" ) {
141+ const dimA = getTableDimensions ( childA ) ;
142+ const dimB = getTableDimensions ( childB ) ;
143+ if (
144+ dimA !== null &&
145+ dimB !== null &&
146+ dimA . rows !== dimB . rows &&
147+ dimA . cols !== dimB . cols
148+ ) {
149+ return false ;
150+ }
151+ }
152+
153+ return true ;
154+ } ;
0 commit comments