@@ -60,23 +60,38 @@ export function serializeInlineContentExternalHTML<
6060
6161 for ( const node of nodes ) {
6262 // Check if this is a custom inline content node with toExternalHTML
63- if ( editor . schema . inlineContentSchema [ node . type . name ] ) {
63+ if (
64+ node . type . name !== "text" &&
65+ editor . schema . inlineContentSchema [ node . type . name ]
66+ ) {
6467 const inlineContentImplementation =
6568 editor . schema . inlineContentSpecs [ node . type . name ] . implementation ;
6669
67- if ( inlineContentImplementation ?. toExternalHTML ) {
70+ if ( inlineContentImplementation ) {
6871 // Convert the node to inline content format
6972 const inlineContent = nodeToCustomInlineContent (
7073 node ,
7174 editor . schema . inlineContentSchema ,
7275 editor . schema . styleSchema ,
7376 ) ;
7477
75- // Use the custom toExternalHTML method
76- const output = inlineContentImplementation . toExternalHTML (
77- inlineContent as any ,
78- editor as any ,
79- ) ;
78+ // Use the custom toExternalHTML method or fallback to `render`
79+ const output = inlineContentImplementation . toExternalHTML
80+ ? inlineContentImplementation . toExternalHTML (
81+ inlineContent as any ,
82+ editor as any ,
83+ )
84+ : inlineContentImplementation . render . call (
85+ {
86+ renderType : "dom" ,
87+ props : undefined ,
88+ } ,
89+ inlineContent as any ,
90+ ( ) => {
91+ // No-op
92+ } ,
93+ editor as any ,
94+ ) ;
8095
8196 if ( output ) {
8297 fragment . appendChild ( output . dom ) ;
@@ -93,14 +108,40 @@ export function serializeInlineContentExternalHTML<
93108 continue ;
94109 }
95110 }
96- }
111+ } else if ( node . type . name === "text" ) {
112+ // We serialize text nodes manually as we need to serialize the styles/
113+ // marks using `styleSpec.implementation.render`. When left up to
114+ // ProseMirror, it'll use `toDOM` which is incorrect.
115+ let dom : globalThis . Node | Text = document . createTextNode (
116+ node . textContent ,
117+ ) ;
118+ // Reverse the order of marks to maintain the correct priority.
119+ for ( const mark of node . marks . toReversed ( ) ) {
120+ if ( mark . type . name in editor . schema . styleSpecs ) {
121+ const newDom = (
122+ editor . schema . styleSpecs [ mark . type . name ] . implementation
123+ . toExternalHTML ??
124+ editor . schema . styleSpecs [ mark . type . name ] . implementation . render
125+ ) ( mark . attrs [ "stringValue" ] , editor ) ;
126+ newDom . contentDOM ! . appendChild ( dom ) ;
127+ dom = newDom . dom ;
128+ } else {
129+ const domOutputSpec = mark . type . spec . toDOM ! ( mark , true ) ;
130+ const newDom = DOMSerializer . renderSpec ( document , domOutputSpec ) ;
131+ newDom . contentDOM ! . appendChild ( dom ) ;
132+ dom = newDom . dom ;
133+ }
134+ }
97135
98- // Fall back to default serialization for this node
99- const nodeFragment = serializer . serializeFragment (
100- Fragment . from ( [ node ] ) ,
101- options ,
102- ) ;
103- fragment . appendChild ( nodeFragment ) ;
136+ fragment . appendChild ( dom ) ;
137+ } else {
138+ // Fall back to default serialization for this node
139+ const nodeFragment = serializer . serializeFragment (
140+ Fragment . from ( [ node ] ) ,
141+ options ,
142+ ) ;
143+ fragment . appendChild ( nodeFragment ) ;
144+ }
104145 }
105146
106147 if (
0 commit comments