@@ -60,23 +60,38 @@ export function serializeInlineContentExternalHTML<
60
60
61
61
for ( const node of nodes ) {
62
62
// 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
+ ) {
64
67
const inlineContentImplementation =
65
68
editor . schema . inlineContentSpecs [ node . type . name ] . implementation ;
66
69
67
- if ( inlineContentImplementation ?. toExternalHTML ) {
70
+ if ( inlineContentImplementation ) {
68
71
// Convert the node to inline content format
69
72
const inlineContent = nodeToCustomInlineContent (
70
73
node ,
71
74
editor . schema . inlineContentSchema ,
72
75
editor . schema . styleSchema ,
73
76
) ;
74
77
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
+ ) ;
80
95
81
96
if ( output ) {
82
97
fragment . appendChild ( output . dom ) ;
@@ -93,14 +108,40 @@ export function serializeInlineContentExternalHTML<
93
108
continue ;
94
109
}
95
110
}
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
+ }
97
135
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
+ }
104
145
}
105
146
106
147
if (
0 commit comments