@mdxeditor/editor 3.49.2 → 3.50.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { usePublisher, useCellValue, useCellValues, useRealm } from "@mdxeditor/gurx";
|
|
2
2
|
import React__default from "react";
|
|
3
|
-
import { corePlugin, editorRootElementRef$, rootEditor$, useTranslation, contentEditableRef$, contentEditableWrapperElement$, contentEditableClassName$, spellCheck$, composerChildren$, topAreaChildren$, editorWrappers$, placeholder$, bottomAreaChildren$, insertMarkdown$, setMarkdown$,
|
|
3
|
+
import { corePlugin, editorRootElementRef$, editorWrapperElementRef$, rootEditor$, useTranslation, contentEditableRef$, contentEditableWrapperElement$, contentEditableClassName$, spellCheck$, composerChildren$, topAreaChildren$, editorWrappers$, placeholder$, bottomAreaChildren$, viewMode$, activeEditor$, exportVisitors$, toMarkdownExtensions$, toMarkdownOptions$, jsxComponentDescriptors$, jsxIsAvailable$, insertMarkdown$, setMarkdown$, markdownSourceEditorValue$, markdown$ } from "./plugins/core/index.js";
|
|
4
4
|
import { RealmWithPlugins } from "./RealmWithPlugins.js";
|
|
5
5
|
import { createLexicalComposerContext, LexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
6
6
|
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
@@ -11,6 +11,7 @@ import { defaultSvgIcons } from "./defaultSvgIcons.js";
|
|
|
11
11
|
import { lexicalTheme } from "./styles/lexicalTheme.js";
|
|
12
12
|
import styles from "./styles/ui.module.css.js";
|
|
13
13
|
import { noop } from "./utils/fp.js";
|
|
14
|
+
import { getSelectionAsMarkdown } from "./utils/lexicalHelpers.js";
|
|
14
15
|
const LexicalProvider = ({ children }) => {
|
|
15
16
|
const rootEditor = useCellValue(rootEditor$);
|
|
16
17
|
const composerContextValue = React__default.useMemo(() => {
|
|
@@ -73,7 +74,9 @@ const RenderRecursiveWrappers = ({ wrappers, children }) => {
|
|
|
73
74
|
};
|
|
74
75
|
const EditorRootElement = ({ children, className, overlayContainer }) => {
|
|
75
76
|
const editorRootElementRef = React__default.useRef(null);
|
|
77
|
+
const wrapperElementRef = React__default.useRef(null);
|
|
76
78
|
const setEditorRootElementRef = usePublisher(editorRootElementRef$);
|
|
79
|
+
const setEditorWrapperElementRef = usePublisher(editorWrapperElementRef$);
|
|
77
80
|
React__default.useEffect(() => {
|
|
78
81
|
const popupContainer = document.createElement("div");
|
|
79
82
|
popupContainer.classList.add(
|
|
@@ -86,11 +89,12 @@ const EditorRootElement = ({ children, className, overlayContainer }) => {
|
|
|
86
89
|
container.appendChild(popupContainer);
|
|
87
90
|
editorRootElementRef.current = popupContainer;
|
|
88
91
|
setEditorRootElementRef(editorRootElementRef);
|
|
92
|
+
setEditorWrapperElementRef(wrapperElementRef);
|
|
89
93
|
return () => {
|
|
90
94
|
popupContainer.remove();
|
|
91
95
|
};
|
|
92
|
-
}, [className, editorRootElementRef, overlayContainer, setEditorRootElementRef]);
|
|
93
|
-
return /* @__PURE__ */ React__default.createElement("div", { className: classNames("mdxeditor", styles.editorRoot, styles.editorWrapper, className) }, children);
|
|
96
|
+
}, [className, editorRootElementRef, overlayContainer, setEditorRootElementRef, setEditorWrapperElementRef]);
|
|
97
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: classNames("mdxeditor", styles.editorRoot, styles.editorWrapper, className), ref: wrapperElementRef }, children);
|
|
94
98
|
};
|
|
95
99
|
const Methods = ({ mdxRef }) => {
|
|
96
100
|
const realm = useRealm();
|
|
@@ -114,6 +118,26 @@ const Methods = ({ mdxRef }) => {
|
|
|
114
118
|
focus: (callbackFn, opts) => {
|
|
115
119
|
var _a;
|
|
116
120
|
(_a = realm.getValue(rootEditor$)) == null ? void 0 : _a.focus(callbackFn, opts);
|
|
121
|
+
},
|
|
122
|
+
getContentEditableHTML: () => {
|
|
123
|
+
var _a, _b;
|
|
124
|
+
return ((_b = (_a = realm.getValue(contentEditableRef$)) == null ? void 0 : _a.current) == null ? void 0 : _b.innerHTML) ?? "";
|
|
125
|
+
},
|
|
126
|
+
getSelectionMarkdown: () => {
|
|
127
|
+
const viewMode = realm.getValue(viewMode$);
|
|
128
|
+
if (viewMode === "source" || viewMode === "diff") {
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
const activeEditor = realm.getValue(activeEditor$);
|
|
132
|
+
if (!activeEditor) {
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
realm.getValue(exportVisitors$);
|
|
136
|
+
realm.getValue(toMarkdownExtensions$);
|
|
137
|
+
realm.getValue(toMarkdownOptions$);
|
|
138
|
+
realm.getValue(jsxComponentDescriptors$);
|
|
139
|
+
realm.getValue(jsxIsAvailable$);
|
|
140
|
+
return getSelectionAsMarkdown(activeEditor);
|
|
117
141
|
}
|
|
118
142
|
};
|
|
119
143
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -1169,6 +1169,11 @@ export declare const editorSearchTextNodeIndex$: NodeRef<TextNodeIndex>;
|
|
|
1169
1169
|
*/
|
|
1170
1170
|
export declare type EditorSubscription = (activeEditor: LexicalEditor) => () => void;
|
|
1171
1171
|
|
|
1172
|
+
/**
|
|
1173
|
+
* @group Core
|
|
1174
|
+
*/
|
|
1175
|
+
export declare const editorWrapperElementRef$: NodeRef<default_2.RefObject<HTMLDivElement> | null>;
|
|
1176
|
+
|
|
1172
1177
|
/* Excluded from this release type: editorWrappers$ */
|
|
1173
1178
|
|
|
1174
1179
|
export declare const EmptyTextNodeIndex: TextNodeIndex;
|
|
@@ -1314,6 +1319,15 @@ export declare interface GenericJsxEditorProps extends JsxEditorProps {
|
|
|
1314
1319
|
*/
|
|
1315
1320
|
export declare function getSelectedNode(selection: RangeSelection): TextNode | ElementNode | null;
|
|
1316
1321
|
|
|
1322
|
+
/**
|
|
1323
|
+
* Gets the markdown representation of the current selection in the Lexical editor.
|
|
1324
|
+
* Returns an empty string if there is no selection or if the selection is collapsed.
|
|
1325
|
+
* Converts selected nodes to markdown by recursively processing them and preserving formatting.
|
|
1326
|
+
* Note: Selects entire nodes, not partial selections within nodes.
|
|
1327
|
+
* @group Utils
|
|
1328
|
+
*/
|
|
1329
|
+
export declare function getSelectionAsMarkdown(editor: LexicalEditor, _exportParams: Omit<ExportMarkdownFromLexicalOptions, 'root'>): string;
|
|
1330
|
+
|
|
1317
1331
|
/**
|
|
1318
1332
|
* Gets the coordinates of the selection in the Lexical editor.
|
|
1319
1333
|
* @group Utils
|
|
@@ -2226,6 +2240,15 @@ export declare interface MDXEditorMethods {
|
|
|
2226
2240
|
defaultSelection?: 'rootStart' | 'rootEnd';
|
|
2227
2241
|
preventScroll?: boolean;
|
|
2228
2242
|
}) => void;
|
|
2243
|
+
/**
|
|
2244
|
+
* gets the underlying Lexical contentEditable HTML content
|
|
2245
|
+
*/
|
|
2246
|
+
getContentEditableHTML: () => string;
|
|
2247
|
+
/**
|
|
2248
|
+
* Gets the markdown representation of the current selection.
|
|
2249
|
+
* Returns an empty string if there is no selection, if selection is collapsed, or if editor is in source/diff mode.
|
|
2250
|
+
*/
|
|
2251
|
+
getSelectionMarkdown: () => string;
|
|
2229
2252
|
}
|
|
2230
2253
|
|
|
2231
2254
|
/**
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { MDXEditor } from "./MDXEditor.js";
|
|
|
4
4
|
import { defaultSvgIcons } from "./defaultSvgIcons.js";
|
|
5
5
|
import { MarkdownParseError, UnrecognizedMarkdownConstructError, importMarkdownToLexical, importMdastTreeToLexical } from "./importMarkdownToLexical.js";
|
|
6
6
|
import { exportLexicalTreeToMdast, exportMarkdownFromLexical } from "./exportMarkdownFromLexical.js";
|
|
7
|
-
import { Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, directiveDescriptors$, editorInFocus$, editorRootElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
|
|
7
|
+
import { Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, directiveDescriptors$, editorInFocus$, editorRootElementRef$, editorWrapperElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
|
|
8
8
|
import { ALL_HEADING_LEVELS, allowedHeadingLevels$, headingsPlugin } from "./plugins/headings/index.js";
|
|
9
9
|
import { insertThematicBreak$, thematicBreakPlugin } from "./plugins/thematic-break/index.js";
|
|
10
10
|
import { applyListType$, currentListType$, listsPlugin } from "./plugins/lists/index.js";
|
|
@@ -58,7 +58,7 @@ import { RemoteMDXEditorRealmProvider, remoteRealmPlugin, useRemoteMDXEditorReal
|
|
|
58
58
|
import { CAN_USE_DOM, IS_APPLE, controlOrMeta } from "./utils/detectMac.js";
|
|
59
59
|
import { always, call, compose, curry1to0, curry2to1, joinProc, noop, prop, tap, thrush } from "./utils/fp.js";
|
|
60
60
|
import { isPartOftheEditorUI } from "./utils/isPartOftheEditorUI.js";
|
|
61
|
-
import { fromWithinEditorRead, getSelectedNode, getSelectionRectangle, getStateAsMarkdown } from "./utils/lexicalHelpers.js";
|
|
61
|
+
import { fromWithinEditorRead, getSelectedNode, getSelectionAsMarkdown, getSelectionRectangle, getStateAsMarkdown } from "./utils/lexicalHelpers.js";
|
|
62
62
|
import { makeHslTransparent } from "./utils/makeHslTransparent.js";
|
|
63
63
|
import { uuidv4 } from "./utils/uuid4.js";
|
|
64
64
|
import { voidEmitter } from "./utils/voidEmitter.js";
|
|
@@ -237,6 +237,7 @@ export {
|
|
|
237
237
|
editorSearchTerm$,
|
|
238
238
|
editorSearchTermDebounced$,
|
|
239
239
|
editorSearchTextNodeIndex$,
|
|
240
|
+
editorWrapperElementRef$,
|
|
240
241
|
editorWrappers$,
|
|
241
242
|
exportLexicalTreeToMdast,
|
|
242
243
|
exportMarkdownFromLexical,
|
|
@@ -245,6 +246,7 @@ export {
|
|
|
245
246
|
frontmatterDialogOpen$,
|
|
246
247
|
frontmatterPlugin,
|
|
247
248
|
getSelectedNode,
|
|
249
|
+
getSelectionAsMarkdown,
|
|
248
250
|
getSelectionRectangle,
|
|
249
251
|
getStateAsMarkdown,
|
|
250
252
|
hasFrontmatter$,
|
|
@@ -84,7 +84,7 @@ const CodeMirrorEditor = ({ language, nodeKey, code, focusEmitter }) => {
|
|
|
84
84
|
editorViewRef.current = null;
|
|
85
85
|
el.removeEventListener("keydown", stopPropagationHandler);
|
|
86
86
|
};
|
|
87
|
-
}, [readOnly, language]);
|
|
87
|
+
}, [readOnly, language, ...codeMirrorExtensions]);
|
|
88
88
|
return /* @__PURE__ */ React__default.createElement("div", { className: styles.codeMirrorWrapper }, /* @__PURE__ */ React__default.createElement("div", { className: styles.codeMirrorToolbar }, /* @__PURE__ */ React__default.createElement(
|
|
89
89
|
Select,
|
|
90
90
|
{
|
|
@@ -116,6 +116,7 @@ const jsxComponentDescriptors$ = Cell([]);
|
|
|
116
116
|
const directiveDescriptors$ = Cell([]);
|
|
117
117
|
const codeBlockEditorDescriptors$ = Cell([]);
|
|
118
118
|
const editorRootElementRef$ = Cell(null);
|
|
119
|
+
const editorWrapperElementRef$ = Cell(null);
|
|
119
120
|
const contentEditableRef$ = Cell(null);
|
|
120
121
|
const addLexicalNode$ = Appender(usedLexicalNodes$);
|
|
121
122
|
const addImportVisitor$ = Appender(importVisitors$);
|
|
@@ -636,6 +637,7 @@ export {
|
|
|
636
637
|
directiveDescriptors$,
|
|
637
638
|
editorInFocus$,
|
|
638
639
|
editorRootElementRef$,
|
|
640
|
+
editorWrapperElementRef$,
|
|
639
641
|
editorWrappers$,
|
|
640
642
|
exportVisitors$,
|
|
641
643
|
historyState$,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { $getSelection, $getRoot } from "lexical";
|
|
1
|
+
import { $getSelection, $getRoot, $isRangeSelection, $isElementNode, $isTextNode } from "lexical";
|
|
2
|
+
import { $isLinkNode } from "@lexical/link";
|
|
3
|
+
import { $isHeadingNode } from "@lexical/rich-text";
|
|
4
|
+
import { $isListItemNode, $isListNode } from "@lexical/list";
|
|
2
5
|
import { $isAtNodeEnd } from "@lexical/selection";
|
|
3
6
|
import { tap } from "./fp.js";
|
|
4
7
|
import { exportMarkdownFromLexical } from "../exportMarkdownFromLexical.js";
|
|
@@ -72,9 +75,85 @@ function getStateAsMarkdown(editor, exportParams) {
|
|
|
72
75
|
});
|
|
73
76
|
}).markdown;
|
|
74
77
|
}
|
|
78
|
+
function getSelectionAsMarkdown(editor, _exportParams) {
|
|
79
|
+
let markdown = "";
|
|
80
|
+
editor.getEditorState().read(() => {
|
|
81
|
+
const selection = $getSelection();
|
|
82
|
+
if (!selection || !$isRangeSelection(selection) || selection.isCollapsed()) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const nodes = selection.getNodes();
|
|
86
|
+
if (nodes.length === 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const parentNodes = /* @__PURE__ */ new Set();
|
|
90
|
+
nodes.forEach((node) => {
|
|
91
|
+
let current = node;
|
|
92
|
+
while (current) {
|
|
93
|
+
if ($isHeadingNode(current) || $isListItemNode(current) || current.getType() === "paragraph" || current.getType() === "quote") {
|
|
94
|
+
if ($isElementNode(current)) {
|
|
95
|
+
parentNodes.add(current);
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
current = current.getParent();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const nodesToProcess = parentNodes.size > 0 ? Array.from(parentNodes) : nodes;
|
|
103
|
+
function nodeToMarkdown(node) {
|
|
104
|
+
if ($isHeadingNode(node)) {
|
|
105
|
+
const level = parseInt(node.getTag().replace("h", ""));
|
|
106
|
+
const children = node.getChildren();
|
|
107
|
+
const headingText = children.map((child) => nodeToMarkdown(child)).join("");
|
|
108
|
+
return "#".repeat(level) + " " + headingText + "\n\n";
|
|
109
|
+
} else if ($isListItemNode(node)) {
|
|
110
|
+
const parent = node.getParent();
|
|
111
|
+
const prefix = parent && $isListNode(parent) && parent.getListType() === "number" ? "1. " : "- ";
|
|
112
|
+
const children = node.getChildren();
|
|
113
|
+
const itemText = children.map((child) => nodeToMarkdown(child)).join("");
|
|
114
|
+
return prefix + itemText + "\n";
|
|
115
|
+
} else if ($isListNode(node)) {
|
|
116
|
+
const children = node.getChildren();
|
|
117
|
+
return children.map((child) => nodeToMarkdown(child)).join("") + "\n";
|
|
118
|
+
} else if ($isTextNode(node)) {
|
|
119
|
+
let text = node.getTextContent();
|
|
120
|
+
const format = node.getFormat();
|
|
121
|
+
if (format & 16) {
|
|
122
|
+
return `\`${text}\``;
|
|
123
|
+
}
|
|
124
|
+
if (format & 1) {
|
|
125
|
+
text = `**${text}**`;
|
|
126
|
+
}
|
|
127
|
+
if (format & 2) {
|
|
128
|
+
text = `*${text}*`;
|
|
129
|
+
}
|
|
130
|
+
if (format & 4) {
|
|
131
|
+
text = `~~${text}~~`;
|
|
132
|
+
}
|
|
133
|
+
return text;
|
|
134
|
+
} else if ($isLinkNode(node)) {
|
|
135
|
+
const url = node.getURL();
|
|
136
|
+
const title = node.getTitle();
|
|
137
|
+
const children = node.getChildren();
|
|
138
|
+
const linkText = children.map((child) => nodeToMarkdown(child)).join("");
|
|
139
|
+
if (title) {
|
|
140
|
+
return `[${linkText}](${url} "${title}")`;
|
|
141
|
+
}
|
|
142
|
+
return `[${linkText}](${url})`;
|
|
143
|
+
} else if ($isElementNode(node)) {
|
|
144
|
+
const children = node.getChildren();
|
|
145
|
+
return children.map((child) => nodeToMarkdown(child)).join("");
|
|
146
|
+
}
|
|
147
|
+
return node.getTextContent();
|
|
148
|
+
}
|
|
149
|
+
markdown = nodesToProcess.map((node) => nodeToMarkdown(node)).join("");
|
|
150
|
+
});
|
|
151
|
+
return markdown.trim();
|
|
152
|
+
}
|
|
75
153
|
export {
|
|
76
154
|
fromWithinEditorRead,
|
|
77
155
|
getSelectedNode,
|
|
156
|
+
getSelectionAsMarkdown,
|
|
78
157
|
getSelectionRectangle,
|
|
79
158
|
getStateAsMarkdown
|
|
80
159
|
};
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"*.css"
|
|
12
12
|
],
|
|
13
13
|
"type": "module",
|
|
14
|
-
"version": "3.
|
|
14
|
+
"version": "3.50.0",
|
|
15
15
|
"description": "React component for rich text markdown editing",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "vite build",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
22
|
"lint": "eslint src --ext .ts,.tsx",
|
|
23
23
|
"test": "NODE_ENV=development vitest",
|
|
24
|
+
"test:once": "NODE_ENV=development vitest --run",
|
|
24
25
|
"semantic-release": "semantic-release",
|
|
25
26
|
"image-upload-backend": "node ./src/examples/file-backend.js",
|
|
26
27
|
"export-icons": "node ./scripts/export-figma-icons.mjs"
|