@mdxeditor/editor 4.0.3 → 4.1.0
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.
- package/dist/MDXEditor.js +138 -53
- package/dist/RealmWithPlugins.js +27 -9
- package/dist/exportMarkdownFromLexical.js +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/mdastUtilHtmlComment.js +2 -1
- package/dist/plugins/codeblock/CodeBlockNode.js +3 -1
- package/dist/plugins/core/NestedLexicalEditor.js +58 -38
- package/dist/plugins/core/index.js +25 -29
- package/dist/plugins/core/lexicalExtensions.js +143 -0
- package/dist/plugins/link-dialog/LinkDialog.js +2 -1
- package/dist/plugins/link-dialog/index.js +15 -1
- package/dist/plugins/search/index.js +273 -170
- package/dist/plugins/table/TableEditor.js +37 -23
- package/dist/plugins/thematic-break/LexicalThematicBreakVisitor.js +2 -2
- package/dist/realmSession.js +38 -0
- package/dist/utils/lexicalHelpers.js +53 -74
- package/package.json +23 -12
- package/dist/plugins/core/SharedHistoryPlugin.js +0 -10
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
2
2
|
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
3
|
-
import {
|
|
3
|
+
import { LexicalExtensionEditorComposer } from "@lexical/react/LexicalExtensionEditorComposer";
|
|
4
4
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
5
5
|
import * as RadixPopover from "@radix-ui/react-popover";
|
|
6
|
-
import { $createParagraphNode,
|
|
6
|
+
import { $createParagraphNode, $getRoot, KEY_TAB_COMMAND, COMMAND_PRIORITY_CRITICAL, FOCUS_COMMAND, COMMAND_PRIORITY_LOW, KEY_ENTER_COMMAND, BLUR_COMMAND, COMMAND_PRIORITY_EDITOR } from "lexical";
|
|
7
7
|
import React__default from "react";
|
|
8
8
|
import { exportLexicalTreeToMdast } from "../../exportMarkdownFromLexical.js";
|
|
9
9
|
import { importMdastTreeToLexical } from "../../importMarkdownToLexical.js";
|
|
10
|
-
import { lexicalTheme } from "../../styles/lexicalTheme.js";
|
|
11
|
-
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
|
12
10
|
import { mergeRegister } from "@lexical/utils";
|
|
13
11
|
import * as RadixToolbar from "@radix-ui/react-toolbar";
|
|
14
12
|
import classNames from "classnames";
|
|
@@ -17,6 +15,7 @@ import { isPartOftheEditorUI } from "../../utils/isPartOftheEditorUI.js";
|
|
|
17
15
|
import { uuidv4 } from "../../utils/uuid4.js";
|
|
18
16
|
import { iconComponentFor$, readOnly$, useTranslation, editorRootElementRef$, importVisitors$, exportVisitors$, usedLexicalNodes$, jsxComponentDescriptors$, directiveDescriptors$, codeBlockEditorDescriptors$, defaultCodeBlockLanguage$, jsxIsAvailable$, rootEditor$, tableCellEditorChildren$, NESTED_EDITOR_UPDATED_COMMAND } from "../core/index.js";
|
|
19
17
|
import { useCellValues } from "@mdxeditor/gurx";
|
|
18
|
+
import { createExtensionEditor } from "../core/lexicalExtensions.js";
|
|
20
19
|
const getCellType = (rowIndex) => {
|
|
21
20
|
if (rowIndex === 0) {
|
|
22
21
|
return "th";
|
|
@@ -231,27 +230,36 @@ const CellEditor = ({ focus, setActiveCell, parentEditor, lexicalTable, contents
|
|
|
231
230
|
rootEditor$,
|
|
232
231
|
tableCellEditorChildren$
|
|
233
232
|
);
|
|
234
|
-
const [editor] = React__default.useState(
|
|
235
|
-
|
|
233
|
+
const [editor, setEditor] = React__default.useState(null);
|
|
234
|
+
React__default.useEffect(() => {
|
|
235
|
+
const editor2 = createExtensionEditor({
|
|
236
|
+
name: "@mdxeditor/table-cell",
|
|
236
237
|
nodes: usedLexicalNodes,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
238
|
+
namespace: "TableCellEditor",
|
|
239
|
+
parentEditor,
|
|
240
|
+
historyMode: "table-local",
|
|
241
|
+
initialEditorState: () => {
|
|
242
|
+
importMdastTreeToLexical({
|
|
243
|
+
root: $getRoot(),
|
|
244
|
+
mdastRoot: { type: "root", children: [{ type: "paragraph", children: contents }] },
|
|
245
|
+
visitors: importVisitors,
|
|
246
|
+
jsxComponentDescriptors,
|
|
247
|
+
directiveDescriptors,
|
|
248
|
+
codeBlockEditorDescriptors,
|
|
249
|
+
defaultCodeBlockLanguage
|
|
250
|
+
});
|
|
251
|
+
}
|
|
250
252
|
});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
+
setEditor(editor2);
|
|
254
|
+
return () => {
|
|
255
|
+
editor2.dispose();
|
|
256
|
+
};
|
|
257
|
+
}, []);
|
|
253
258
|
const saveAndFocus = React__default.useCallback(
|
|
254
259
|
(nextCell) => {
|
|
260
|
+
if (!editor) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
255
263
|
editor.getEditorState().read(() => {
|
|
256
264
|
const mdast = exportLexicalTreeToMdast({
|
|
257
265
|
root: $getRoot(),
|
|
@@ -272,6 +280,9 @@ const CellEditor = ({ focus, setActiveCell, parentEditor, lexicalTable, contents
|
|
|
272
280
|
[colIndex, editor, exportVisitors, jsxComponentDescriptors, jsxIsAvailable, lexicalTable, parentEditor, rowIndex, setActiveCell]
|
|
273
281
|
);
|
|
274
282
|
React__default.useEffect(() => {
|
|
283
|
+
if (!editor) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
275
286
|
return mergeRegister(
|
|
276
287
|
editor.registerCommand(
|
|
277
288
|
KEY_TAB_COMMAND,
|
|
@@ -324,11 +335,14 @@ const CellEditor = ({ focus, setActiveCell, parentEditor, lexicalTable, contents
|
|
|
324
335
|
);
|
|
325
336
|
}, [colIndex, editor, rootEditor, rowIndex, saveAndFocus, setActiveCell]);
|
|
326
337
|
React__default.useEffect(() => {
|
|
327
|
-
if (focus) {
|
|
338
|
+
if (focus && editor) {
|
|
328
339
|
editor.focus();
|
|
329
340
|
}
|
|
330
341
|
}, [focus, editor]);
|
|
331
|
-
|
|
342
|
+
if (!editor) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return /* @__PURE__ */ React__default.createElement(LexicalExtensionEditorComposer, { initialEditor: editor }, /* @__PURE__ */ React__default.createElement(RichTextPlugin, { contentEditable: /* @__PURE__ */ React__default.createElement(ContentEditable, null), placeholder: /* @__PURE__ */ React__default.createElement("div", null), ErrorBoundary: LexicalErrorBoundary }), tableCellEditorChildren.map((Child, index) => /* @__PURE__ */ React__default.createElement(Child, { key: index })));
|
|
332
346
|
};
|
|
333
347
|
const ColumnEditor = ({
|
|
334
348
|
parentEditor,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode.js";
|
|
2
2
|
const LexicalThematicBreakVisitor = {
|
|
3
|
-
testLexicalNode:
|
|
3
|
+
testLexicalNode: (node) => node instanceof HorizontalRuleNode,
|
|
4
4
|
visitLexicalNode({ actions }) {
|
|
5
5
|
actions.addAndStepInto("thematicBreak");
|
|
6
6
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const realmCleanups = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function registerRealmCleanup(realm, cleanup) {
|
|
3
|
+
let cleanups = realmCleanups.get(realm);
|
|
4
|
+
if (!cleanups) {
|
|
5
|
+
cleanups = /* @__PURE__ */ new Set();
|
|
6
|
+
realmCleanups.set(realm, cleanups);
|
|
7
|
+
}
|
|
8
|
+
cleanups.add(cleanup);
|
|
9
|
+
return () => {
|
|
10
|
+
cleanups.delete(cleanup);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function disposeRealmSession(realm) {
|
|
14
|
+
const cleanups = realmCleanups.get(realm);
|
|
15
|
+
realmCleanups.delete(realm);
|
|
16
|
+
if (!cleanups) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let hasError = false;
|
|
20
|
+
let firstError;
|
|
21
|
+
for (const cleanup of [...cleanups].reverse()) {
|
|
22
|
+
try {
|
|
23
|
+
cleanup();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!hasError) {
|
|
26
|
+
hasError = true;
|
|
27
|
+
firstError = error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (hasError) {
|
|
32
|
+
throw firstError instanceof Error ? firstError : new Error("Realm cleanup failed with a non-Error value");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
disposeRealmSession,
|
|
37
|
+
registerRealmCleanup
|
|
38
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { $getSelection, $getRoot, $isRangeSelection,
|
|
2
|
-
import { $
|
|
3
|
-
import { $isHeadingNode } from "@lexical/rich-text";
|
|
4
|
-
import { $isListItemNode, $isListNode } from "@lexical/list";
|
|
1
|
+
import { $getSelection, $getRoot, $isRangeSelection, createEditor, $createParagraphNode } from "lexical";
|
|
2
|
+
import { $generateJSONFromSelectedNodes, $generateNodesFromSerializedNodes } from "@lexical/clipboard";
|
|
5
3
|
import { $isAtNodeEnd } from "@lexical/selection";
|
|
6
4
|
import { tap } from "./fp.js";
|
|
7
5
|
import { exportMarkdownFromLexical } from "../exportMarkdownFromLexical.js";
|
|
@@ -101,80 +99,61 @@ function getStateAsMarkdown(editor, exportParams) {
|
|
|
101
99
|
});
|
|
102
100
|
}).markdown;
|
|
103
101
|
}
|
|
104
|
-
function getSelectionAsMarkdown(editor,
|
|
102
|
+
function getSelectionAsMarkdown(editor, exportParams) {
|
|
103
|
+
let temporaryEditor = null;
|
|
104
|
+
let selectedNodes = [];
|
|
105
105
|
let markdown = "";
|
|
106
|
-
editor.getEditorState().read(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const nodes = selection.getNodes();
|
|
112
|
-
if (nodes.length === 0) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const parentNodes = /* @__PURE__ */ new Set();
|
|
116
|
-
nodes.forEach((node) => {
|
|
117
|
-
let current = node;
|
|
118
|
-
while (current) {
|
|
119
|
-
if ($isHeadingNode(current) || $isListItemNode(current) || current.getType() === "paragraph" || current.getType() === "quote") {
|
|
120
|
-
if ($isElementNode(current)) {
|
|
121
|
-
parentNodes.add(current);
|
|
122
|
-
}
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
current = current.getParent();
|
|
106
|
+
editor.getEditorState().read(
|
|
107
|
+
() => {
|
|
108
|
+
const selection = $getSelection();
|
|
109
|
+
if (!selection || $isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {
|
|
110
|
+
return;
|
|
126
111
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
return text;
|
|
160
|
-
} else if ($isLinkNode(node)) {
|
|
161
|
-
const url = node.getURL();
|
|
162
|
-
const title = node.getTitle();
|
|
163
|
-
const children = node.getChildren();
|
|
164
|
-
const linkText = children.map((child) => nodeToMarkdown(child)).join("");
|
|
165
|
-
if (title) {
|
|
166
|
-
return `[${linkText}](${url} "${title}")`;
|
|
112
|
+
selectedNodes = $generateJSONFromSelectedNodes(editor, selection).nodes;
|
|
113
|
+
if (selectedNodes.length > 0) {
|
|
114
|
+
temporaryEditor = createEditor();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{ editor }
|
|
118
|
+
);
|
|
119
|
+
const selectedTreeEditor = temporaryEditor;
|
|
120
|
+
if (!selectedTreeEditor || selectedNodes.length === 0) {
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
123
|
+
const exportResult = { error: void 0, failed: false };
|
|
124
|
+
selectedTreeEditor.update(
|
|
125
|
+
() => {
|
|
126
|
+
try {
|
|
127
|
+
const root = $getRoot();
|
|
128
|
+
const nodes = $generateNodesFromSerializedNodes(selectedNodes);
|
|
129
|
+
let inlineContainer = $createParagraphNode();
|
|
130
|
+
const appendInlineContainer = () => {
|
|
131
|
+
if (!inlineContainer.isEmpty()) {
|
|
132
|
+
root.append(inlineContainer);
|
|
133
|
+
inlineContainer = $createParagraphNode();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
for (const node of nodes) {
|
|
137
|
+
if (node.isInline()) {
|
|
138
|
+
inlineContainer.append(node);
|
|
139
|
+
} else {
|
|
140
|
+
appendInlineContainer();
|
|
141
|
+
root.append(node);
|
|
142
|
+
}
|
|
167
143
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
144
|
+
appendInlineContainer();
|
|
145
|
+
markdown = exportMarkdownFromLexical({ root, ...exportParams });
|
|
146
|
+
} catch (error) {
|
|
147
|
+
exportResult.failed = true;
|
|
148
|
+
exportResult.error = error;
|
|
172
149
|
}
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
150
|
+
},
|
|
151
|
+
{ discrete: true, skipTransforms: true }
|
|
152
|
+
);
|
|
153
|
+
if (exportResult.failed) {
|
|
154
|
+
throw exportResult.error;
|
|
155
|
+
}
|
|
156
|
+
return markdown.replace(/\n+$/u, "");
|
|
178
157
|
}
|
|
179
158
|
export {
|
|
180
159
|
fromWithinEditorRead,
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"*.css"
|
|
12
12
|
],
|
|
13
13
|
"type": "module",
|
|
14
|
-
"version": "4.0
|
|
14
|
+
"version": "4.1.0",
|
|
15
15
|
"description": "React component for rich text markdown editing",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "vite build",
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
"lint": "eslint src --ext .ts,.tsx",
|
|
23
23
|
"test": "vitest",
|
|
24
24
|
"test:once": "vitest --run",
|
|
25
|
+
"test:compat:unit": "vitest --run src/test/compatibility.test.tsx",
|
|
26
|
+
"test:browser:serve": "ladle dev --host 127.0.0.1 --port 61000 --noWatch",
|
|
27
|
+
"test:browser": "playwright test",
|
|
28
|
+
"test:browser:chromium": "playwright test --project=chromium",
|
|
29
|
+
"test:compat": "npm run test:compat:unit && npm run test:browser",
|
|
30
|
+
"test:lexical-versions": "node scripts/assert-lexical-versions.mjs",
|
|
31
|
+
"test:package": "node scripts/verify-package-consumer.mjs",
|
|
32
|
+
"test:cross-version": "node scripts/verify-cross-version-markdown.mjs",
|
|
25
33
|
"semantic-release": "semantic-release",
|
|
26
34
|
"image-upload-backend": "node ./src/examples/file-backend.js",
|
|
27
35
|
"export-icons": "node ./scripts/export-figma-icons.mjs"
|
|
@@ -44,15 +52,17 @@
|
|
|
44
52
|
"@codemirror/merge": "^6.4.0",
|
|
45
53
|
"@codemirror/state": "^6.4.0",
|
|
46
54
|
"@codemirror/view": "^6.23.0",
|
|
47
|
-
"@lexical/clipboard": "^0.
|
|
48
|
-
"@lexical/
|
|
49
|
-
"@lexical/
|
|
50
|
-
"@lexical/
|
|
51
|
-
"@lexical/
|
|
52
|
-
"@lexical/
|
|
53
|
-
"@lexical/
|
|
54
|
-
"@lexical/
|
|
55
|
-
"@lexical/
|
|
55
|
+
"@lexical/clipboard": "^0.48.0",
|
|
56
|
+
"@lexical/extension": "^0.48.0",
|
|
57
|
+
"@lexical/history": "^0.48.0",
|
|
58
|
+
"@lexical/link": "^0.48.0",
|
|
59
|
+
"@lexical/list": "^0.48.0",
|
|
60
|
+
"@lexical/markdown": "^0.48.0",
|
|
61
|
+
"@lexical/plain-text": "^0.48.0",
|
|
62
|
+
"@lexical/react": "^0.48.0",
|
|
63
|
+
"@lexical/rich-text": "^0.48.0",
|
|
64
|
+
"@lexical/selection": "^0.48.0",
|
|
65
|
+
"@lexical/utils": "^0.48.0",
|
|
56
66
|
"@mdxeditor/gurx": "^1.2.4",
|
|
57
67
|
"@radix-ui/colors": "^3.0.0",
|
|
58
68
|
"@radix-ui/react-dialog": "^1.1.11",
|
|
@@ -67,8 +77,8 @@
|
|
|
67
77
|
"cm6-theme-basic-light": "^0.2.0",
|
|
68
78
|
"codemirror": "^6.0.1",
|
|
69
79
|
"downshift": "^7.6.0",
|
|
70
|
-
"js-yaml": "4.
|
|
71
|
-
"lexical": "^0.
|
|
80
|
+
"js-yaml": "4.2.0",
|
|
81
|
+
"lexical": "^0.48.0",
|
|
72
82
|
"mdast-util-directive": "^3.0.0",
|
|
73
83
|
"mdast-util-from-markdown": "^2.0.0",
|
|
74
84
|
"mdast-util-frontmatter": "^2.0.1",
|
|
@@ -106,6 +116,7 @@
|
|
|
106
116
|
"@babel/preset-typescript": "^7.23.3",
|
|
107
117
|
"@ladle/react": "^5.1.1",
|
|
108
118
|
"@ngneat/falso": "^6.4.0",
|
|
119
|
+
"@playwright/test": "1.61.1",
|
|
109
120
|
"@testing-library/dom": "^10.4.1",
|
|
110
121
|
"@testing-library/jest-dom": "^6.1.6",
|
|
111
122
|
"@testing-library/react": "^16.3.0",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
|
2
|
-
import React__default from "react";
|
|
3
|
-
import { historyState$ } from "./index.js";
|
|
4
|
-
import { useCellValue } from "@mdxeditor/gurx";
|
|
5
|
-
const SharedHistoryPlugin = () => {
|
|
6
|
-
return /* @__PURE__ */ React__default.createElement(HistoryPlugin, { externalHistoryState: useCellValue(historyState$) });
|
|
7
|
-
};
|
|
8
|
-
export {
|
|
9
|
-
SharedHistoryPlugin
|
|
10
|
-
};
|