@mdxeditor/editor 4.3.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -153,6 +153,7 @@ function exportLexicalTreeToMdast({
|
|
|
153
153
|
} else {
|
|
154
154
|
typedRoot.children.unshift(...imports);
|
|
155
155
|
}
|
|
156
|
+
splitParagraphsAtBlankLines(typedRoot);
|
|
156
157
|
fixWrappingWhitespace(typedRoot, []);
|
|
157
158
|
collapseNestedHtmlTags(typedRoot);
|
|
158
159
|
if (!jsxIsAvailable) {
|
|
@@ -206,6 +207,41 @@ function convertUnderlineJsxToHtml(node) {
|
|
|
206
207
|
nodeAsParent.children = newChildren;
|
|
207
208
|
}
|
|
208
209
|
}
|
|
210
|
+
const BLANK_LINE_REGEXP = /\n(?:[^\S\n]*\n)+/;
|
|
211
|
+
function splitParagraphsAtBlankLines(node) {
|
|
212
|
+
if (!("children" in node)) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const children = [];
|
|
216
|
+
for (const child of node.children) {
|
|
217
|
+
if (child.type === "paragraph" && child.children.some((c) => c.type === "text" && BLANK_LINE_REGEXP.test(c.value))) {
|
|
218
|
+
children.push(...splitParagraph(child));
|
|
219
|
+
} else {
|
|
220
|
+
splitParagraphsAtBlankLines(child);
|
|
221
|
+
children.push(child);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
node.children = children;
|
|
225
|
+
}
|
|
226
|
+
function splitParagraph(paragraph) {
|
|
227
|
+
const paragraphs = [{ type: "paragraph", children: [] }];
|
|
228
|
+
for (const child of paragraph.children) {
|
|
229
|
+
if (child.type !== "text") {
|
|
230
|
+
paragraphs.at(-1).children.push(child);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
child.value.split(BLANK_LINE_REGEXP).forEach((value, index) => {
|
|
234
|
+
if (index > 0) {
|
|
235
|
+
paragraphs.push({ type: "paragraph", children: [] });
|
|
236
|
+
}
|
|
237
|
+
if (value) {
|
|
238
|
+
paragraphs.at(-1).children.push({ type: "text", value });
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const nonEmptyParagraphs = paragraphs.filter((p) => p.children.length > 0);
|
|
243
|
+
return nonEmptyParagraphs.length > 0 ? nonEmptyParagraphs : [{ type: "paragraph", children: [] }];
|
|
244
|
+
}
|
|
209
245
|
const TRAILING_WHITESPACE_REGEXP = /\s+$/;
|
|
210
246
|
const LEADING_WHITESPACE_REGEXP = /^\s+/;
|
|
211
247
|
function fixWrappingWhitespace(node, parentChain) {
|
|
@@ -4,6 +4,7 @@ import { reconcileJsxKindMismatches } from "./plugins/jsx/reconcileJsxKind.js";
|
|
|
4
4
|
function isParent(node) {
|
|
5
5
|
return node.children instanceof Array;
|
|
6
6
|
}
|
|
7
|
+
const TEXT_BLOCK_TYPES = ["paragraph", "heading", "tableCell"];
|
|
7
8
|
class MarkdownParseError extends Error {
|
|
8
9
|
constructor(message, cause) {
|
|
9
10
|
super(message);
|
|
@@ -103,6 +104,16 @@ function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors })
|
|
|
103
104
|
throw new Error("Attempting to visit children of a non-parent");
|
|
104
105
|
}
|
|
105
106
|
mdastNode.children.forEach((child) => {
|
|
107
|
+
if (isParent(child) && !TEXT_BLOCK_TYPES.includes(child.type)) {
|
|
108
|
+
const formatting = formattingMap.get(mdastNode);
|
|
109
|
+
if (formatting !== void 0 && !formattingMap.has(child)) {
|
|
110
|
+
formattingMap.set(child, formatting);
|
|
111
|
+
}
|
|
112
|
+
const style = styleMap.get(mdastNode);
|
|
113
|
+
if (style !== void 0 && !styleMap.has(child)) {
|
|
114
|
+
styleMap.set(child, style);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
106
117
|
visit(child, lexicalParent, mdastNode);
|
|
107
118
|
});
|
|
108
119
|
}
|
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
import { $isTextNode } from "lexical";
|
|
2
|
-
import { IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_ITALIC, IS_BOLD, IS_STRIKETHROUGH, IS_HIGHLIGHT
|
|
2
|
+
import { IS_CODE, IS_UNDERLINE, IS_SUPERSCRIPT, IS_SUBSCRIPT, IS_ITALIC, IS_BOLD, IS_STRIKETHROUGH, IS_HIGHLIGHT } from "../../FormatConstants.js";
|
|
3
3
|
function isMdastText(mdastNode) {
|
|
4
4
|
return mdastNode.type === "text";
|
|
5
5
|
}
|
|
6
6
|
const JOINABLE_TAGS = ["u", "span", "sub", "sup"];
|
|
7
|
+
function tagFormat(format, name) {
|
|
8
|
+
return {
|
|
9
|
+
format,
|
|
10
|
+
isTag: true,
|
|
11
|
+
matches: (node) => node.type === "mdxJsxTextElement" && node.name === name && node.attributes.length === 0,
|
|
12
|
+
create: () => ({ type: "mdxJsxTextElement", name, children: [], attributes: [] })
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function markerFormat(format, type) {
|
|
16
|
+
return {
|
|
17
|
+
format,
|
|
18
|
+
isTag: false,
|
|
19
|
+
matches: (node) => node.type === type,
|
|
20
|
+
create: () => ({ type, children: [] })
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const FORMAT_CONTAINERS = [
|
|
24
|
+
tagFormat(IS_UNDERLINE, "u"),
|
|
25
|
+
tagFormat(IS_SUPERSCRIPT, "sup"),
|
|
26
|
+
tagFormat(IS_SUBSCRIPT, "sub"),
|
|
27
|
+
markerFormat(IS_ITALIC, "emphasis"),
|
|
28
|
+
markerFormat(IS_BOLD, "strong"),
|
|
29
|
+
markerFormat(IS_STRIKETHROUGH, "delete"),
|
|
30
|
+
markerFormat(IS_HIGHLIGHT, "highlight")
|
|
31
|
+
];
|
|
32
|
+
function countFollowingTextNodesWithFormat(lexicalNode, format) {
|
|
33
|
+
const style = lexicalNode.getStyle();
|
|
34
|
+
let count = 0;
|
|
35
|
+
let sibling = lexicalNode.getNextSibling();
|
|
36
|
+
while ($isTextNode(sibling) && sibling.getFormat() & format && sibling.getStyle() === style) {
|
|
37
|
+
count++;
|
|
38
|
+
sibling = sibling.getNextSibling();
|
|
39
|
+
}
|
|
40
|
+
return count;
|
|
41
|
+
}
|
|
7
42
|
const LexicalTextVisitor = {
|
|
8
43
|
shouldJoin: (prevNode, currentNode) => {
|
|
9
44
|
if (["text", "emphasis", "strong", "highlight"].includes(prevNode.type)) {
|
|
@@ -31,8 +66,6 @@ const LexicalTextVisitor = {
|
|
|
31
66
|
},
|
|
32
67
|
testLexicalNode: $isTextNode,
|
|
33
68
|
visitLexicalNode: ({ lexicalNode, mdastParent, actions }) => {
|
|
34
|
-
const previousSibling = lexicalNode.getPreviousSibling();
|
|
35
|
-
const prevFormat = $isTextNode(previousSibling) ? previousSibling.getFormat() : 0;
|
|
36
69
|
const textContent = lexicalNode.getTextContent();
|
|
37
70
|
const format = lexicalNode.getFormat();
|
|
38
71
|
const style = lexicalNode.getStyle();
|
|
@@ -45,101 +78,19 @@ const LexicalTextVisitor = {
|
|
|
45
78
|
attributes: [{ type: "mdxJsxAttribute", name: "style", value: style }]
|
|
46
79
|
});
|
|
47
80
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
58
|
-
type: "mdxJsxTextElement",
|
|
59
|
-
name: "sup",
|
|
60
|
-
children: [],
|
|
61
|
-
attributes: []
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
if (prevFormat & format & IS_SUBSCRIPT) {
|
|
65
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
66
|
-
type: "mdxJsxTextElement",
|
|
67
|
-
name: "sub",
|
|
68
|
-
children: [],
|
|
69
|
-
attributes: []
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if (prevFormat & format & IS_ITALIC) {
|
|
73
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
74
|
-
type: "emphasis",
|
|
75
|
-
children: []
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
if (prevFormat & format & IS_BOLD) {
|
|
79
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
80
|
-
type: "strong",
|
|
81
|
-
children: []
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
if (prevFormat & format & IS_STRIKETHROUGH) {
|
|
85
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
86
|
-
type: "delete",
|
|
87
|
-
children: []
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
if (prevFormat & format & IS_HIGHLIGHT) {
|
|
91
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
92
|
-
type: "highlight",
|
|
93
|
-
children: []
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
if (format & IS_UNDERLINE && !(prevFormat & IS_UNDERLINE)) {
|
|
97
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
98
|
-
type: "mdxJsxTextElement",
|
|
99
|
-
name: "u",
|
|
100
|
-
children: [],
|
|
101
|
-
attributes: []
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
if (format & IS_SUPERSCRIPT && !(prevFormat & IS_SUPERSCRIPT)) {
|
|
105
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
106
|
-
type: "mdxJsxTextElement",
|
|
107
|
-
name: "sup",
|
|
108
|
-
children: [],
|
|
109
|
-
attributes: []
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
if (format & IS_SUBSCRIPT && !(prevFormat & IS_SUBSCRIPT)) {
|
|
113
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
114
|
-
type: "mdxJsxTextElement",
|
|
115
|
-
name: "sub",
|
|
116
|
-
children: [],
|
|
117
|
-
attributes: []
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
if (format & IS_ITALIC && !(prevFormat & IS_ITALIC)) {
|
|
121
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
122
|
-
type: "emphasis",
|
|
123
|
-
children: []
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (format & IS_BOLD && !(prevFormat & IS_BOLD)) {
|
|
127
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
128
|
-
type: "strong",
|
|
129
|
-
children: []
|
|
130
|
-
});
|
|
81
|
+
let continuedFormats = 0;
|
|
82
|
+
for (; ; ) {
|
|
83
|
+
const lastChild = localParentNode.children.at(-1);
|
|
84
|
+
const container = lastChild && FORMAT_CONTAINERS.find((c) => format & c.format && !(continuedFormats & c.format) && c.matches(lastChild));
|
|
85
|
+
if (!container) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
continuedFormats |= container.format;
|
|
89
|
+
localParentNode = lastChild;
|
|
131
90
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
children: []
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
if (format & IS_HIGHLIGHT && !(prevFormat & IS_HIGHLIGHT)) {
|
|
139
|
-
localParentNode = actions.appendToParent(localParentNode, {
|
|
140
|
-
type: "highlight",
|
|
141
|
-
children: []
|
|
142
|
-
});
|
|
91
|
+
const containersToOpen = FORMAT_CONTAINERS.filter((c) => format & c.format && !(continuedFormats & c.format)).map((container) => ({ container, runLength: countFollowingTextNodesWithFormat(lexicalNode, container.format) })).sort((a, b) => Number(b.container.isTag) - Number(a.container.isTag) || b.runLength - a.runLength);
|
|
92
|
+
for (const { container } of containersToOpen) {
|
|
93
|
+
localParentNode = actions.appendToParent(localParentNode, container.create());
|
|
143
94
|
}
|
|
144
95
|
if (format & IS_CODE) {
|
|
145
96
|
actions.appendToParent(localParentNode, {
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"*.css"
|
|
12
12
|
],
|
|
13
13
|
"type": "module",
|
|
14
|
-
"version": "4.3.
|
|
14
|
+
"version": "4.3.1",
|
|
15
15
|
"description": "React component for rich text markdown editing",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "vite build",
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
"mdast-util-directive": "^3.0.0",
|
|
83
83
|
"mdast-util-from-markdown": "^2.0.0",
|
|
84
84
|
"mdast-util-frontmatter": "^2.0.1",
|
|
85
|
-
"mdast-util-gfm-strikethrough": "^2.0.
|
|
85
|
+
"mdast-util-gfm-strikethrough": "^2.0.1",
|
|
86
86
|
"mdast-util-gfm-table": "^2.0.0",
|
|
87
87
|
"mdast-util-gfm-task-list-item": "^2.0.0",
|
|
88
88
|
"mdast-util-highlight-mark": "^1.2.2",
|
|
89
89
|
"mdast-util-mdx": "^3.0.0",
|
|
90
90
|
"mdast-util-mdx-jsx": "^3.0.0",
|
|
91
|
-
"mdast-util-to-markdown": "^2.1.
|
|
91
|
+
"mdast-util-to-markdown": "^2.1.3",
|
|
92
92
|
"micromark-extension-directive": "^3.0.0",
|
|
93
93
|
"micromark-extension-frontmatter": "^2.0.0",
|
|
94
94
|
"micromark-extension-gfm-strikethrough": "^2.0.0",
|