@@ -2,6 +2,54 @@ import { Fragment, Schema, Slice } from "@tiptap/pm/model";
22import { EditorView } from "@tiptap/pm/view" ;
33
44import { getBlockInfoFromSelection } from "../api/getBlockInfoFromPos.js" ;
5+ import { findParentNodeClosestToPos } from "@tiptap/core" ;
6+
7+ /**
8+ * Checks if the current selection is inside a table cell.
9+ * Returns the depth of the tableCell/tableHeader node if found, -1 otherwise.
10+ */
11+ function isInTableCell ( view : EditorView ) : boolean {
12+ return (
13+ findParentNodeClosestToPos ( view . state . selection . $from , ( n ) => {
14+ return n . type . name === "tableCell" || n . type . name === "tableHeader" ;
15+ } ) !== undefined
16+ ) ;
17+ }
18+
19+ /**
20+ * Converts block content to inline content with hard breaks.
21+ * This is used when pasting into table cells which can only contain inline content.
22+ */
23+ function convertBlocksToInlineContent (
24+ fragment : Fragment ,
25+ schema : Schema ,
26+ ) : Fragment {
27+ const hardBreak = schema . nodes . hardBreak ;
28+ let result = Fragment . empty ;
29+
30+ fragment . forEach ( ( node ) => {
31+ if ( node . isTextblock && node . childCount > 0 ) {
32+ // Extract inline content from paragraphs, headings, etc.
33+ result = result . append ( node . content ) ;
34+ result = result . addToEnd ( hardBreak . create ( ) ) ;
35+ } else if ( node . isText ) {
36+ result = result . addToEnd ( node ) ;
37+ } else if ( node . isBlock && node . childCount > 0 ) {
38+ // Recurse into block containers, blockGroups, etc.
39+ result = result . append (
40+ convertBlocksToInlineContent ( node . content , schema ) ,
41+ ) ;
42+ result = result . addToEnd ( hardBreak . create ( ) ) ;
43+ }
44+ } ) ;
45+
46+ // Remove trailing hard break
47+ if ( result . lastChild ?. type === hardBreak ) {
48+ result = result . cut ( 0 , result . size - 1 ) ;
49+ }
50+
51+ return result ;
52+ }
553
654// helper function to remove a child from a fragment
755function removeChild ( node : Fragment , n : number ) {
@@ -65,6 +113,27 @@ export function transformPasted(slice: Slice, view: EditorView) {
65113 let f = Fragment . from ( slice . content ) ;
66114 f = wrapTableRows ( f , view . state . schema ) ;
67115
116+ if ( isInTableCell ( view ) ) {
117+ let hasTableContent = false ;
118+ f . descendants ( ( node ) => {
119+ if ( node . type . isInGroup ( "tableContent" ) ) {
120+ hasTableContent = true ;
121+ }
122+ } ) ;
123+ if (
124+ ! hasTableContent &&
125+ // is the content valid for a table paragraph?
126+ ! view . state . schema . nodes . tableParagraph . validContent ( f )
127+ ) {
128+ // if not, convert the content to inline content
129+ return new Slice (
130+ convertBlocksToInlineContent ( f , view . state . schema ) ,
131+ 0 ,
132+ 0 ,
133+ ) ;
134+ }
135+ }
136+
68137 if ( ! shouldApplyFix ( f , view ) ) {
69138 // Don't apply the fix.
70139 return new Slice ( f , slice . openStart , slice . openEnd ) ;
0 commit comments