@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, IS_CODE } from "../../FormatConstants.js";
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
- if (prevFormat & format & IS_UNDERLINE) {
49
- localParentNode = actions.appendToParent(localParentNode, {
50
- type: "mdxJsxTextElement",
51
- name: "u",
52
- children: [],
53
- attributes: []
54
- });
55
- }
56
- if (prevFormat & format & IS_SUPERSCRIPT) {
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
- if (format & IS_STRIKETHROUGH && !(prevFormat & IS_STRIKETHROUGH)) {
133
- localParentNode = actions.appendToParent(localParentNode, {
134
- type: "delete",
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.0",
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.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.0",
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",