@lobehub/editor 1.17.0 → 1.17.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.
|
@@ -24,7 +24,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
|
|
24
24
|
import { registerDragonSupport } from '@lexical/dragon';
|
|
25
25
|
import { createEmptyHistoryState, registerHistory } from '@lexical/history';
|
|
26
26
|
import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode, HeadingNode, QuoteNode, registerRichText } from '@lexical/rich-text';
|
|
27
|
-
import { $createLineBreakNode, $createParagraphNode, $isTextNode } from 'lexical';
|
|
27
|
+
import { $createLineBreakNode, $createParagraphNode, $isTextNode, COMMAND_PRIORITY_HIGH, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND } from 'lexical';
|
|
28
28
|
import { KernelPlugin } from "../../../editor-kernel/plugin";
|
|
29
29
|
import { IMarkdownShortCutService, isPunctuationChar } from "../../markdown";
|
|
30
30
|
import { registerCommands } from "../command";
|
|
@@ -82,7 +82,7 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
82
82
|
// Parse markdown options
|
|
83
83
|
var markdownOption = (_this$config$markdown = (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.markdownOption) !== null && _this$config$markdown !== void 0 ? _this$config$markdown : true;
|
|
84
84
|
var isMarkdownEnabled = markdownOption !== false;
|
|
85
|
-
var
|
|
85
|
+
var breakMark = isMarkdownEnabled ? '\n\n' : '\n';
|
|
86
86
|
|
|
87
87
|
// Determine which formats are enabled
|
|
88
88
|
var formats = {
|
|
@@ -189,11 +189,11 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
189
189
|
markdownService.registerMarkdownShortCuts(textFormatShortcuts);
|
|
190
190
|
}
|
|
191
191
|
markdownService.registerMarkdownWriter('paragraph', function (ctx) {
|
|
192
|
-
ctx.wrap('',
|
|
192
|
+
ctx.wrap('', '\n');
|
|
193
193
|
});
|
|
194
194
|
markdownService.registerMarkdownWriter('quote', function (ctx, node) {
|
|
195
195
|
if ($isQuoteNode(node)) {
|
|
196
|
-
ctx.wrap('> ',
|
|
196
|
+
ctx.wrap('> ', breakMark);
|
|
197
197
|
}
|
|
198
198
|
});
|
|
199
199
|
markdownService.registerMarkdownWriter('heading', function (ctx, node) {
|
|
@@ -201,37 +201,37 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
201
201
|
switch (node.getTag()) {
|
|
202
202
|
case 'h1':
|
|
203
203
|
{
|
|
204
|
-
ctx.wrap('# ',
|
|
204
|
+
ctx.wrap('# ', breakMark);
|
|
205
205
|
break;
|
|
206
206
|
}
|
|
207
207
|
case 'h2':
|
|
208
208
|
{
|
|
209
|
-
ctx.wrap('## ',
|
|
209
|
+
ctx.wrap('## ', breakMark);
|
|
210
210
|
break;
|
|
211
211
|
}
|
|
212
212
|
case 'h3':
|
|
213
213
|
{
|
|
214
|
-
ctx.wrap('### ',
|
|
214
|
+
ctx.wrap('### ', breakMark);
|
|
215
215
|
break;
|
|
216
216
|
}
|
|
217
217
|
case 'h4':
|
|
218
218
|
{
|
|
219
|
-
ctx.wrap('#### ',
|
|
219
|
+
ctx.wrap('#### ', breakMark);
|
|
220
220
|
break;
|
|
221
221
|
}
|
|
222
222
|
case 'h5':
|
|
223
223
|
{
|
|
224
|
-
ctx.wrap('##### ',
|
|
224
|
+
ctx.wrap('##### ', breakMark);
|
|
225
225
|
break;
|
|
226
226
|
}
|
|
227
227
|
case 'h6':
|
|
228
228
|
{
|
|
229
|
-
ctx.wrap('###### ',
|
|
229
|
+
ctx.wrap('###### ', breakMark);
|
|
230
230
|
break;
|
|
231
231
|
}
|
|
232
232
|
default:
|
|
233
233
|
{
|
|
234
|
-
ctx.wrap('',
|
|
234
|
+
ctx.wrap('', '\n');
|
|
235
235
|
break;
|
|
236
236
|
}
|
|
237
237
|
}
|
|
@@ -315,7 +315,14 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
315
315
|
var _this$config2;
|
|
316
316
|
this.registerClears(registerRichText(editor), registerDragonSupport(editor), registerHistory(editor, createEmptyHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel, {
|
|
317
317
|
enableHotkey: (_this$config2 = this.config) === null || _this$config2 === void 0 ? void 0 : _this$config2.enableHotkey
|
|
318
|
-
}), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor), registerLastElement(editor)
|
|
318
|
+
}), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor), registerLastElement(editor),
|
|
319
|
+
// Convert soft line breaks (Shift+Enter) to hard line breaks (paragraph breaks)
|
|
320
|
+
// This allows breaking out of code blocks with Shift+Enter
|
|
321
|
+
editor.registerCommand(INSERT_LINE_BREAK_COMMAND, function () {
|
|
322
|
+
// Dispatch paragraph command instead of line break
|
|
323
|
+
editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);
|
|
324
|
+
return true; // Prevent default line break behavior
|
|
325
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
319
326
|
this.registerMarkdown(this.kernel);
|
|
320
327
|
}
|
|
321
328
|
}, {
|
|
@@ -14,12 +14,13 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
|
|
|
14
14
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
15
15
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
16
16
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
17
|
+
import { preprocessMarkdownContent } from '@lobehub/ui';
|
|
17
18
|
import { remark } from 'remark';
|
|
19
|
+
import remarkCjkFriendly from 'remark-cjk-friendly';
|
|
18
20
|
import remarkGfm from 'remark-gfm';
|
|
19
21
|
import remarkMath from 'remark-math';
|
|
20
22
|
import { INodeHelper } from "../../../../editor-kernel/inode/helper";
|
|
21
23
|
import { logger } from "../../utils/logger";
|
|
22
|
-
import remarkSupersub from "./supersub";
|
|
23
24
|
|
|
24
25
|
// 使用条件类型确保类型匹配
|
|
25
26
|
|
|
@@ -225,9 +226,9 @@ function registerDefaultReaders(markdownReaders) {
|
|
|
225
226
|
}
|
|
226
227
|
export function parseMarkdownToLexical(markdown) {
|
|
227
228
|
var markdownReaders = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
228
|
-
var ast = remark().use(
|
|
229
|
+
var ast = remark().use(remarkCjkFriendly).use(remarkMath).use([[remarkGfm, {
|
|
229
230
|
singleTilde: false
|
|
230
|
-
}]]).parse(markdown);
|
|
231
|
+
}]]).parse(preprocessMarkdownContent(markdown));
|
|
231
232
|
logger.debug('Parsed MDAST:', ast);
|
|
232
233
|
var ctx = new MarkdownContext(ast);
|
|
233
234
|
registerDefaultReaders(markdownReaders);
|
|
@@ -133,63 +133,92 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
133
133
|
|
|
134
134
|
// Check if markdown paste formatting is enabled (default: true)
|
|
135
135
|
var enablePasteMarkdown = (_this2$config$enableP = (_this2$config = _this2.config) === null || _this2$config === void 0 ? void 0 : _this2$config.enablePasteMarkdown) !== null && _this2$config$enableP !== void 0 ? _this2$config$enableP : true;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
editor.update(function () {
|
|
142
|
-
var selection = $getSelection();
|
|
143
|
-
if (!$isRangeSelection(selection)) return;
|
|
136
|
+
_this2.logger.debug('paste content analysis:', {
|
|
137
|
+
enablePasteMarkdown: enablePasteMarkdown,
|
|
138
|
+
hasHTML: !!(html && html.trim()),
|
|
139
|
+
text: text.slice(0, 100) + (text.length > 100 ? '...' : '')
|
|
140
|
+
});
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
// Always force plain text paste first (prevents HTML formatting issues)
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
editor.update(function () {
|
|
146
|
+
var selection = $getSelection();
|
|
147
|
+
if (!$isRangeSelection(selection)) return;
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
// Insert plain text
|
|
150
|
+
selection.insertText(text);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// If markdown formatting is disabled, we're done
|
|
154
|
+
if (!enablePasteMarkdown) {
|
|
155
|
+
_this2.logger.debug('markdown formatting disabled, plain text inserted');
|
|
156
|
+
return true;
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
//
|
|
159
|
+
// Check if the pasted plain text contains markdown patterns
|
|
159
160
|
var hasMarkdownContent = _this2.detectMarkdownContent(text);
|
|
160
|
-
_this2.logger.debug('paste content analysis:', {
|
|
161
|
-
hasHTML: false,
|
|
162
|
-
hasMarkdown: hasMarkdownContent,
|
|
163
|
-
markdownPatterns: _this2.getMarkdownPatterns(text),
|
|
164
|
-
text: text.slice(0, 100) + (text.length > 100 ? '...' : '')
|
|
165
|
-
});
|
|
166
161
|
if (hasMarkdownContent) {
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
// });
|
|
179
|
-
// }, 5000);
|
|
180
|
-
return false;
|
|
162
|
+
// Markdown detected - show confirmation dialog
|
|
163
|
+
_this2.logger.debug('markdown patterns detected:', _this2.getMarkdownPatterns(text));
|
|
164
|
+
setTimeout(function () {
|
|
165
|
+
_this2.kernel.emit('markdownParse', {
|
|
166
|
+
cacheState: editor.getEditorState(),
|
|
167
|
+
markdown: text
|
|
168
|
+
});
|
|
169
|
+
}, 10);
|
|
170
|
+
} else {
|
|
171
|
+
// No markdown detected - plain text is already inserted
|
|
172
|
+
_this2.logger.debug('no markdown patterns detected, keeping as plain text');
|
|
181
173
|
}
|
|
182
|
-
return
|
|
174
|
+
return true; // Command handled
|
|
183
175
|
}, COMMAND_PRIORITY_CRITICAL));
|
|
184
176
|
this.register(registerMarkdownCommand(editor, this.service));
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
/**
|
|
188
180
|
* Detect if text contains markdown patterns
|
|
181
|
+
* Returns false if content is likely code (JSON, HTML, SQL, etc.)
|
|
189
182
|
*/
|
|
190
183
|
}, {
|
|
191
184
|
key: "detectMarkdownContent",
|
|
192
185
|
value: function detectMarkdownContent(text) {
|
|
186
|
+
var trimmed = text.trim();
|
|
187
|
+
|
|
188
|
+
// Check if content is JSON
|
|
189
|
+
if (trimmed.startsWith('{') && trimmed.endsWith('}') || trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
190
|
+
try {
|
|
191
|
+
JSON.parse(trimmed);
|
|
192
|
+
this.logger.debug('content is valid JSON, not treating as markdown');
|
|
193
|
+
return false;
|
|
194
|
+
} catch (_unused) {
|
|
195
|
+
// Not valid JSON, continue checking
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check if content has significant HTML structure
|
|
200
|
+
var htmlTagPattern = /<[a-z][\S\s]*?>/gi;
|
|
201
|
+
var htmlMatches = text.match(htmlTagPattern);
|
|
202
|
+
if (htmlMatches && htmlMatches.length > 5) {
|
|
203
|
+
// More than 5 HTML tags suggests this is HTML content, not markdown
|
|
204
|
+
this.logger.debug('content has significant HTML structure, not treating as markdown');
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Check if content looks like code (SQL, XML, etc.)
|
|
209
|
+
// Common patterns: SQL keywords, XML declarations, file paths
|
|
210
|
+
var codePatterns = [/^\s*(select|insert|update|delete|create|alter|drop)\s+/im,
|
|
211
|
+
// SQL
|
|
212
|
+
/^\s*<\?xml/i,
|
|
213
|
+
// XML declaration
|
|
214
|
+
/^[a-z]:\\|^\/[a-z]/im // File paths (Windows/Unix)
|
|
215
|
+
];
|
|
216
|
+
if (codePatterns.some(function (pattern) {
|
|
217
|
+
return pattern.test(text);
|
|
218
|
+
})) {
|
|
219
|
+
this.logger.debug('content looks like code, not treating as markdown');
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
193
222
|
var markdownPatterns = [
|
|
194
223
|
// Headers
|
|
195
224
|
/^#{1,6}\s+/m,
|
|
@@ -6,7 +6,8 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
6
6
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
7
7
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
8
8
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
9
|
-
import { Button
|
|
9
|
+
import { Button } from '@lobehub/ui';
|
|
10
|
+
import { Space, notification } from 'antd';
|
|
10
11
|
import { UNDO_COMMAND } from 'lexical';
|
|
11
12
|
import { useLayoutEffect } from 'react';
|
|
12
13
|
import { useLexicalComposerContext } from "../../../editor-kernel/react";
|
|
@@ -35,7 +36,6 @@ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
|
|
|
35
36
|
return api.destroy();
|
|
36
37
|
},
|
|
37
38
|
size: "small",
|
|
38
|
-
type: "link",
|
|
39
39
|
children: t('markdown.cancel')
|
|
40
40
|
}), /*#__PURE__*/_jsx(Button, {
|
|
41
41
|
onClick: function onClick() {
|
|
@@ -56,7 +56,7 @@ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
|
|
|
56
56
|
duration: 5,
|
|
57
57
|
key: key,
|
|
58
58
|
message: t('markdown.parseTitle'),
|
|
59
|
-
|
|
59
|
+
showProgress: true
|
|
60
60
|
});
|
|
61
61
|
};
|
|
62
62
|
editor.on('markdownParse', handleEvent);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/editor",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lobehub",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"react-error-boundary": "^6.0.0",
|
|
57
57
|
"react-layout-kit": "^2.0.0",
|
|
58
58
|
"react-merge-refs": "^3.0.2",
|
|
59
|
+
"remark-cjk-friendly": "^1.2.1",
|
|
59
60
|
"remark-supersub": "^1.0.0",
|
|
60
61
|
"shiki": "^3.9.2",
|
|
61
62
|
"ts-key-enum": "^3.0.13",
|