Skip to content

Commit a07ddc1

Browse files
committed
rich text editor: improve handling of attributes for paragraphs, headings, list items, blockquotes, and code blocks
1 parent 3075e48 commit a07ddc1

File tree

1 file changed

+47
-19
lines changed

1 file changed

+47
-19
lines changed

examples/rich-text-editor/rich_text_editor.js

+47-19
Original file line numberDiff line numberDiff line change
@@ -160,19 +160,30 @@ function traverseMdastNode(node, delta, attributes = {}) {
160160
}
161161
break;
162162

163-
case "paragraph":
163+
case "paragraph": {
164164
for (const child of node.children || []) {
165165
traverseMdastNode(child, delta, attributes);
166166
}
167-
delta.ops.push({ insert: "\n" });
167+
const pLineAttributes = {};
168+
if (attributes.blockquote) {
169+
pLineAttributes.blockquote = true;
170+
}
171+
delta.ops.push({ insert: "\n", attributes: pLineAttributes });
168172
break;
173+
}
169174

170-
case "heading":
175+
case "heading": {
176+
const headingContentAttributes = { ...attributes, header: node.depth };
171177
for (const child of node.children || []) {
172-
traverseMdastNode(child, delta, { header: node.depth });
178+
traverseMdastNode(child, delta, headingContentAttributes);
179+
}
180+
const headingLineAttributes = { header: node.depth };
181+
if (attributes.blockquote) {
182+
headingLineAttributes.blockquote = true;
173183
}
174-
delta.ops.push({ insert: "\n", attributes: { header: node.depth } });
184+
delta.ops.push({ insert: "\n", attributes: headingLineAttributes });
175185
break;
186+
}
176187

177188
case "text":
178189
delta.ops.push({ insert: node.value || "", attributes });
@@ -212,36 +223,53 @@ function traverseMdastNode(node, delta, attributes = {}) {
212223
}
213224
break;
214225

215-
case "listItem":
226+
case "listItem": {
227+
const { list, ...listItemChildrenAttributes } = attributes;
228+
216229
for (const child of node.children || []) {
217-
traverseMdastNode(child, delta, {});
230+
traverseMdastNode(child, delta, listItemChildrenAttributes);
218231
}
232+
233+
// Attributes for the listItem's newline (e.g., { list: 'bullet', blockquote: true })
234+
// are in `attributes` passed to this `listItem` case.
219235
{
220236
const lastOp = delta.ops[delta.ops.length - 1];
221-
if (lastOp && lastOp.insert === "\n") lastOp.attributes = attributes;
222-
else delta.ops.push({ insert: "\n", attributes });
237+
if (lastOp && lastOp.insert === "\n") {
238+
lastOp.attributes = { ...lastOp.attributes, ...attributes };
239+
} else {
240+
delta.ops.push({ insert: "\n", attributes });
241+
}
223242
}
224243
break;
244+
}
225245

226246
case "blockquote":
227247
for (const child of node.children || []) {
228248
traverseMdastNode(child, delta, { ...attributes, blockquote: true });
229249
}
230250
break;
231251

232-
case "code":
233-
delta.ops.push({
234-
insert: node.value || "",
235-
attributes: { "code-block": node.lang || "plain" },
236-
});
237-
delta.ops.push({
238-
insert: "\n",
239-
attributes: { "code-block": node.lang || "plain" },
240-
});
252+
case "code": { // mdast 'code' is a block
253+
const codeBlockLineFormat = { "code-block": node.lang || true };
254+
if (attributes.blockquote) {
255+
codeBlockLineFormat.blockquote = true;
256+
}
257+
258+
const textInCodeAttributes = {};
259+
if (attributes.blockquote) { // Text lines also get blockquote if active
260+
textInCodeAttributes.blockquote = true;
261+
}
262+
263+
const lines = (node.value || "").split('\n');
264+
for (const lineText of lines) {
265+
delta.ops.push({ insert: lineText, attributes: textInCodeAttributes });
266+
delta.ops.push({ insert: "\n", attributes: codeBlockLineFormat });
267+
}
241268
break;
269+
}
242270

243271
case "inlineCode":
244-
delta.ops.push({ insert: node.value || "", attributes: { code: true } });
272+
delta.ops.push({ insert: node.value || "", attributes: { ...attributes, code: true } });
245273
break;
246274

247275
default:

0 commit comments

Comments
 (0)