@mdxeditor/editor 3.49.3 → 3.51.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 +27 -3
- package/dist/index.d.ts +26 -2
- package/dist/index.js +4 -2
- package/dist/plugins/core/index.js +2 -0
- package/dist/plugins/link-dialog/LinkDialog.js +10 -3
- package/dist/plugins/link-dialog/index.js +46 -40
- package/dist/utils/lexicalHelpers.js +80 -1
- package/package.json +5 -3
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
|
@@ -1122,9 +1122,10 @@ export declare interface EditingImageDialogState {
|
|
|
1122
1122
|
export declare interface EditLinkDialog {
|
|
1123
1123
|
type: 'edit';
|
|
1124
1124
|
initialUrl: string;
|
|
1125
|
-
hasInitialText: boolean;
|
|
1126
1125
|
url: string;
|
|
1127
1126
|
title: string;
|
|
1127
|
+
text: string;
|
|
1128
|
+
withAnchorText: boolean;
|
|
1128
1129
|
linkNodeKey: string;
|
|
1129
1130
|
rectangle: RectData;
|
|
1130
1131
|
}
|
|
@@ -1169,6 +1170,11 @@ export declare const editorSearchTextNodeIndex$: NodeRef<TextNodeIndex>;
|
|
|
1169
1170
|
*/
|
|
1170
1171
|
export declare type EditorSubscription = (activeEditor: LexicalEditor) => () => void;
|
|
1171
1172
|
|
|
1173
|
+
/**
|
|
1174
|
+
* @group Core
|
|
1175
|
+
*/
|
|
1176
|
+
export declare const editorWrapperElementRef$: NodeRef<default_2.RefObject<HTMLDivElement> | null>;
|
|
1177
|
+
|
|
1172
1178
|
/* Excluded from this release type: editorWrappers$ */
|
|
1173
1179
|
|
|
1174
1180
|
export declare const EmptyTextNodeIndex: TextNodeIndex;
|
|
@@ -1314,6 +1320,15 @@ export declare interface GenericJsxEditorProps extends JsxEditorProps {
|
|
|
1314
1320
|
*/
|
|
1315
1321
|
export declare function getSelectedNode(selection: RangeSelection): TextNode | ElementNode | null;
|
|
1316
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* Gets the markdown representation of the current selection in the Lexical editor.
|
|
1325
|
+
* Returns an empty string if there is no selection or if the selection is collapsed.
|
|
1326
|
+
* Converts selected nodes to markdown by recursively processing them and preserving formatting.
|
|
1327
|
+
* Note: Selects entire nodes, not partial selections within nodes.
|
|
1328
|
+
* @group Utils
|
|
1329
|
+
*/
|
|
1330
|
+
export declare function getSelectionAsMarkdown(editor: LexicalEditor, _exportParams: Omit<ExportMarkdownFromLexicalOptions, 'root'>): string;
|
|
1331
|
+
|
|
1317
1332
|
/**
|
|
1318
1333
|
* Gets the coordinates of the selection in the Lexical editor.
|
|
1319
1334
|
* @group Utils
|
|
@@ -2226,6 +2241,15 @@ export declare interface MDXEditorMethods {
|
|
|
2226
2241
|
defaultSelection?: 'rootStart' | 'rootEnd';
|
|
2227
2242
|
preventScroll?: boolean;
|
|
2228
2243
|
}) => void;
|
|
2244
|
+
/**
|
|
2245
|
+
* gets the underlying Lexical contentEditable HTML content
|
|
2246
|
+
*/
|
|
2247
|
+
getContentEditableHTML: () => string;
|
|
2248
|
+
/**
|
|
2249
|
+
* Gets the markdown representation of the current selection.
|
|
2250
|
+
* Returns an empty string if there is no selection, if selection is collapsed, or if editor is in source/diff mode.
|
|
2251
|
+
*/
|
|
2252
|
+
getSelectionMarkdown: () => string;
|
|
2229
2253
|
}
|
|
2230
2254
|
|
|
2231
2255
|
/**
|
|
@@ -2843,7 +2867,7 @@ export declare type SerializedTableNode = Spread<{
|
|
|
2843
2867
|
*/
|
|
2844
2868
|
export declare const setMarkdown$: NodeRef<string>;
|
|
2845
2869
|
|
|
2846
|
-
|
|
2870
|
+
export declare const showLinkTitleField$: NodeRef<boolean>;
|
|
2847
2871
|
|
|
2848
2872
|
/**
|
|
2849
2873
|
* A component that displays the focused live code block's name.
|
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$,
|
|
@@ -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$,
|
|
@@ -13,6 +13,7 @@ createCommand();
|
|
|
13
13
|
function LinkEditForm({
|
|
14
14
|
url,
|
|
15
15
|
title,
|
|
16
|
+
text,
|
|
16
17
|
onSubmit,
|
|
17
18
|
onCancel,
|
|
18
19
|
linkAutocompleteSuggestions,
|
|
@@ -29,8 +30,7 @@ function LinkEditForm({
|
|
|
29
30
|
values: {
|
|
30
31
|
url,
|
|
31
32
|
title,
|
|
32
|
-
text
|
|
33
|
-
// text is only for freshly created links with no content, it always starts empty
|
|
33
|
+
text
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
const t = useTranslation();
|
|
@@ -46,6 +46,12 @@ function LinkEditForm({
|
|
|
46
46
|
e.stopPropagation();
|
|
47
47
|
onCancel();
|
|
48
48
|
},
|
|
49
|
+
onKeyDown: (e) => {
|
|
50
|
+
if (e.key === "Escape") {
|
|
51
|
+
e.stopPropagation();
|
|
52
|
+
onCancel();
|
|
53
|
+
}
|
|
54
|
+
},
|
|
49
55
|
className: classNames(styles.multiFieldForm, styles.linkDialogEditForm)
|
|
50
56
|
},
|
|
51
57
|
/* @__PURE__ */ React__default.createElement("div", { className: styles.formField }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "link-url" }, t("createLink.url", "URL")), /* @__PURE__ */ React__default.createElement(
|
|
@@ -153,11 +159,12 @@ const LinkDialog = () => {
|
|
|
153
159
|
{
|
|
154
160
|
url: linkDialogState.url,
|
|
155
161
|
title: linkDialogState.title,
|
|
162
|
+
text: linkDialogState.text,
|
|
156
163
|
onSubmit: updateLink,
|
|
157
164
|
onCancel: cancelLinkEdit.bind(null),
|
|
158
165
|
linkAutocompleteSuggestions,
|
|
159
166
|
showLinkTitleField,
|
|
160
|
-
showAnchorTextField:
|
|
167
|
+
showAnchorTextField: linkDialogState.withAnchorText
|
|
161
168
|
}
|
|
162
169
|
),
|
|
163
170
|
linkDialogState.type === "preview" && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $createLinkNode, TOGGLE_LINK_COMMAND,
|
|
1
|
+
import { $isLinkNode, $createLinkNode, TOGGLE_LINK_COMMAND, LinkNode } from "@lexical/link";
|
|
2
2
|
import { Signal, Cell, Action, withLatestFrom, map, filter } from "@mdxeditor/gurx";
|
|
3
|
-
import { KEY_ESCAPE_COMMAND, COMMAND_PRIORITY_LOW, KEY_MODIFIER_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_HIGH, $createTextNode, $insertNodes, $getNearestNodeFromDOMNode } from "lexical";
|
|
3
|
+
import { KEY_ESCAPE_COMMAND, COMMAND_PRIORITY_LOW, KEY_MODIFIER_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_HIGH, $getNodeByKey, $createTextNode, $insertNodes, $isTextNode, $getNearestNodeFromDOMNode } from "lexical";
|
|
4
4
|
import { realmPlugin } from "../../RealmWithPlugins.js";
|
|
5
5
|
import { IS_APPLE } from "../../utils/detectMac.js";
|
|
6
6
|
import { getSelectionRectangle, getSelectedNode } from "../../utils/lexicalHelpers.js";
|
|
@@ -64,28 +64,29 @@ const linkDialogState$ = Cell({ type: "inactive" }, (r) => {
|
|
|
64
64
|
COMMAND_PRIORITY_HIGH
|
|
65
65
|
);
|
|
66
66
|
});
|
|
67
|
-
r.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
r.sub(r.pipe(switchFromPreviewToLinkEdit$, withLatestFrom(linkDialogState$, activeEditor$)), ([, state, editor]) => {
|
|
68
|
+
if (state.type === "preview") {
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
editor == null ? void 0 : editor.getEditorState().read(() => {
|
|
71
|
+
const node = $getNodeByKey(state.linkNodeKey);
|
|
72
|
+
const withAnchorText = $isLinkNode(node) ? node.getTextContent().length > 0 && node.getChildrenSize() <= 1 : false;
|
|
73
|
+
const text = withAnchorText && node ? node.getTextContent() : "";
|
|
74
|
+
r.pub(linkDialogState$, {
|
|
74
75
|
type: "edit",
|
|
75
76
|
initialUrl: state.url,
|
|
76
|
-
hasInitialText: true,
|
|
77
77
|
url: state.url,
|
|
78
78
|
title: state.title,
|
|
79
|
+
text,
|
|
80
|
+
withAnchorText,
|
|
79
81
|
linkNodeKey: state.linkNodeKey,
|
|
80
82
|
rectangle: state.rectangle
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
throw new Error("Cannot switch to edit mode when not in preview mode");
|
|
88
|
+
}
|
|
89
|
+
});
|
|
89
90
|
r.sub(r.pipe(updateLink$, withLatestFrom(activeEditor$, linkDialogState$, currentSelection$)), ([payload, editor, state, selection]) => {
|
|
90
91
|
var _a, _b, _c;
|
|
91
92
|
const text = ((_a = payload.text) == null ? void 0 : _a.trim()) ?? "";
|
|
@@ -105,11 +106,15 @@ const linkDialogState$ = Cell({ type: "inactive" }, (r) => {
|
|
|
105
106
|
} else {
|
|
106
107
|
linkNode.setURL(url);
|
|
107
108
|
linkNode.setTitle(title);
|
|
109
|
+
updateLinkText(linkNode.getFirstChild(), text);
|
|
108
110
|
}
|
|
109
111
|
},
|
|
110
112
|
{ discrete: true }
|
|
111
113
|
);
|
|
112
114
|
} else {
|
|
115
|
+
editor == null ? void 0 : editor.update(() => {
|
|
116
|
+
updateLinkText(selection == null ? void 0 : selection.anchor.getNode(), text);
|
|
117
|
+
});
|
|
113
118
|
editor == null ? void 0 : editor.dispatchCommand(TOGGLE_LINK_COMMAND, { url, title });
|
|
114
119
|
}
|
|
115
120
|
r.pub(linkDialogState$, {
|
|
@@ -204,29 +209,24 @@ const openLinkEditDialog$ = Action((r) => {
|
|
|
204
209
|
editor == null ? void 0 : editor.focus(() => {
|
|
205
210
|
setTimeout(() => {
|
|
206
211
|
editor.getEditorState().read(() => {
|
|
207
|
-
const
|
|
212
|
+
const linkNode = getLinkNodeInSelection(selection);
|
|
208
213
|
const rectangle = getSelectionRectangle(editor);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
url: "",
|
|
226
|
-
linkNodeKey: "",
|
|
227
|
-
rectangle
|
|
228
|
-
});
|
|
229
|
-
}
|
|
214
|
+
const initialUrl = (linkNode == null ? void 0 : linkNode.getURL()) ?? "";
|
|
215
|
+
const url = (linkNode == null ? void 0 : linkNode.getURL()) ?? "";
|
|
216
|
+
const title = (linkNode == null ? void 0 : linkNode.getTitle()) ?? "";
|
|
217
|
+
const linkNodeKey = (linkNode == null ? void 0 : linkNode.getKey()) ?? "";
|
|
218
|
+
const withAnchorText = linkNode ? linkNode.getTextContent().length > 0 && linkNode.getChildrenSize() <= 1 : Boolean(selection == null ? void 0 : selection.isCollapsed());
|
|
219
|
+
const text = withAnchorText && linkNode ? linkNode.getTextContent() : "";
|
|
220
|
+
r.pub(linkDialogState$, {
|
|
221
|
+
type: "edit",
|
|
222
|
+
initialUrl,
|
|
223
|
+
url,
|
|
224
|
+
title,
|
|
225
|
+
text,
|
|
226
|
+
withAnchorText,
|
|
227
|
+
linkNodeKey,
|
|
228
|
+
rectangle
|
|
229
|
+
});
|
|
230
230
|
});
|
|
231
231
|
});
|
|
232
232
|
});
|
|
@@ -262,6 +262,12 @@ const onReadOnlyClickLinkCallback$ = Cell(null, (r) => {
|
|
|
262
262
|
});
|
|
263
263
|
});
|
|
264
264
|
});
|
|
265
|
+
function updateLinkText(node, text) {
|
|
266
|
+
if ($isTextNode(node) && text) {
|
|
267
|
+
node.setTextContent(text);
|
|
268
|
+
node.selectStart();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
265
271
|
const showLinkTitleField$ = Cell(true);
|
|
266
272
|
const linkDialogPlugin = realmPlugin({
|
|
267
273
|
init(r, params) {
|
|
@@ -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.51.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"
|
|
@@ -145,7 +146,7 @@
|
|
|
145
146
|
"prettier": "^3.1.1",
|
|
146
147
|
"react": "^19.1.0",
|
|
147
148
|
"react-dom": "^19.1.0",
|
|
148
|
-
"semantic-release": "^
|
|
149
|
+
"semantic-release": "^25.0.2",
|
|
149
150
|
"svgo": "^3.3.2",
|
|
150
151
|
"terser": "^5.26.0",
|
|
151
152
|
"typedoc": "^0.25.13",
|
|
@@ -161,7 +162,8 @@
|
|
|
161
162
|
"vitest": "^1.1.1"
|
|
162
163
|
},
|
|
163
164
|
"publishConfig": {
|
|
164
|
-
"access": "public"
|
|
165
|
+
"access": "public",
|
|
166
|
+
"provenance": true
|
|
165
167
|
},
|
|
166
168
|
"engines": {
|
|
167
169
|
"node": ">=16"
|