@lobehub/editor 1.16.3 → 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.
package/es/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './plugins/hr';
8
8
  export * from './plugins/image';
9
9
  export * from './plugins/link';
10
10
  export * from './plugins/list';
11
+ export * from './plugins/markdown';
11
12
  export * from './plugins/math';
12
13
  export * from './plugins/mention';
13
14
  export * from './plugins/slash';
package/es/index.js CHANGED
@@ -8,6 +8,7 @@ export * from "./plugins/hr";
8
8
  export * from "./plugins/image";
9
9
  export * from "./plugins/link";
10
10
  export * from "./plugins/list";
11
+ export * from "./plugins/markdown";
11
12
  export * from "./plugins/math";
12
13
  export * from "./plugins/mention";
13
14
  export * from "./plugins/slash";
@@ -16,6 +16,12 @@ declare const _default: {
16
16
  placeholder: string;
17
17
  unlink: string;
18
18
  };
19
+ markdown: {
20
+ cancel: string;
21
+ confirm: string;
22
+ parseMessage: string;
23
+ parseTitle: string;
24
+ };
19
25
  math: {
20
26
  placeholder: string;
21
27
  };
@@ -16,6 +16,12 @@ export default {
16
16
  placeholder: 'Enter link URL',
17
17
  unlink: 'Unlink Link'
18
18
  },
19
+ markdown: {
20
+ cancel: 'Cancel',
21
+ confirm: 'Confirm',
22
+ parseMessage: 'Convert to markdown format, existing content will be overwritten, confirm? (Auto close in 5 seconds)',
23
+ parseTitle: 'Parse Markdown'
24
+ },
19
25
  math: {
20
26
  placeholder: 'Enter TeX formula'
21
27
  },
@@ -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 softBreak = isMarkdownEnabled ? '\n\n' : '\n';
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('', softBreak);
192
+ ctx.wrap('', '\n');
193
193
  });
194
194
  markdownService.registerMarkdownWriter('quote', function (ctx, node) {
195
195
  if ($isQuoteNode(node)) {
196
- ctx.wrap('> ', softBreak);
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('# ', '\n');
204
+ ctx.wrap('# ', breakMark);
205
205
  break;
206
206
  }
207
207
  case 'h2':
208
208
  {
209
- ctx.wrap('## ', '\n');
209
+ ctx.wrap('## ', breakMark);
210
210
  break;
211
211
  }
212
212
  case 'h3':
213
213
  {
214
- ctx.wrap('### ', '\n');
214
+ ctx.wrap('### ', breakMark);
215
215
  break;
216
216
  }
217
217
  case 'h4':
218
218
  {
219
- ctx.wrap('#### ', '\n');
219
+ ctx.wrap('#### ', breakMark);
220
220
  break;
221
221
  }
222
222
  case 'h5':
223
223
  {
224
- ctx.wrap('##### ', '\n');
224
+ ctx.wrap('##### ', breakMark);
225
225
  break;
226
226
  }
227
227
  case 'h6':
228
228
  {
229
- ctx.wrap('###### ', '\n');
229
+ ctx.wrap('###### ', breakMark);
230
230
  break;
231
231
  }
232
232
  default:
233
233
  {
234
- ctx.wrap('', softBreak);
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
  }, {
@@ -0,0 +1,6 @@
1
+ import { LexicalEditor } from 'lexical';
2
+ import { MarkdownShortCutService } from '../service/shortcut';
3
+ export declare const INSERT_MARKDOWN_COMMAND: import("lexical").LexicalCommand<{
4
+ markdown: string;
5
+ }>;
6
+ export declare function registerMarkdownCommand(editor: LexicalEditor, service: MarkdownShortCutService): () => void;
@@ -0,0 +1,27 @@
1
+ import { $getSelection, COMMAND_PRIORITY_HIGH, createCommand } from 'lexical';
2
+ import { createDebugLogger } from "../../../utils/debug";
3
+ import { parseMarkdownToLexical } from "../data-source/markdown/parse";
4
+ import { $generateNodesFromSerializedNodes, $insertGeneratedNodes } from "../utils";
5
+ var logger = createDebugLogger('plugin', 'markdown');
6
+ export var INSERT_MARKDOWN_COMMAND = createCommand('INSERT_MARKDOWN_COMMAND');
7
+ export function registerMarkdownCommand(editor, service) {
8
+ return editor.registerCommand(INSERT_MARKDOWN_COMMAND, function (payload) {
9
+ var markdown = payload.markdown;
10
+ logger.debug('INSERT_MARKDOWN_COMMAND payload:', payload);
11
+ editor.update(function () {
12
+ try {
13
+ // Use the markdown data source to parse the content
14
+ var root = parseMarkdownToLexical(markdown, service.markdownReaders);
15
+ var selection = $getSelection();
16
+ var nodes = $generateNodesFromSerializedNodes(root.children);
17
+ logger.debug('INSERT_MARKDOWN_COMMAND nodes:', nodes);
18
+ $insertGeneratedNodes(editor, nodes, selection);
19
+ return true;
20
+ } catch (error) {
21
+ logger.error('Failed to handle markdown paste:', error);
22
+ }
23
+ });
24
+ return false;
25
+ }, COMMAND_PRIORITY_HIGH // Priority
26
+ );
27
+ }
@@ -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
 
@@ -68,6 +69,10 @@ function convertMdastToLexical(node, index, ctx) {
68
69
  var htmlStack = []; // 当前循环是否包含 HTML 标签
69
70
  _children = node.children.reduce(function (ret, child, index) {
70
71
  if (child.type === 'html') {
72
+ var isComment = child.value.startsWith('<!--') && child.value.endsWith('-->');
73
+ if (isComment) {
74
+ return ret;
75
+ }
71
76
  var tag = child.value.replaceAll(/^<\/?|>$/g, '');
72
77
  var isEndTag = child.value.startsWith('</');
73
78
  if (selfClosingHtmlTags.has(tag)) {
@@ -221,9 +226,9 @@ function registerDefaultReaders(markdownReaders) {
221
226
  }
222
227
  export function parseMarkdownToLexical(markdown) {
223
228
  var markdownReaders = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
224
- var ast = remark().use(remarkMath).use(remarkSupersub).use([[remarkGfm, {
229
+ var ast = remark().use(remarkCjkFriendly).use(remarkMath).use([[remarkGfm, {
225
230
  singleTilde: false
226
- }]]).parse(markdown);
231
+ }]]).parse(preprocessMarkdownContent(markdown));
227
232
  logger.debug('Parsed MDAST:', ast);
228
233
  var ctx = new MarkdownContext(ast);
229
234
  registerDefaultReaders(markdownReaders);
@@ -1,4 +1,6 @@
1
+ export { INSERT_MARKDOWN_COMMAND } from './command';
1
2
  export { MarkdownPlugin } from './plugin';
3
+ export { default as ReactMarkdownPlugin } from './react';
2
4
  export type { MARKDOWN_READER_LEVEL } from './service/shortcut';
3
5
  export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, } from './service/shortcut';
4
6
  export { isPunctuationChar } from './utils';
@@ -1,3 +1,5 @@
1
+ export { INSERT_MARKDOWN_COMMAND } from "./command";
1
2
  export { MarkdownPlugin } from "./plugin";
3
+ export { default as ReactMarkdownPlugin } from "./react";
2
4
  export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX } from "./service/shortcut";
3
5
  export { isPunctuationChar } from "./utils";
@@ -17,10 +17,10 @@ import { $isCodeNode } from '@lexical/code';
17
17
  import { $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, HISTORIC_TAG, KEY_ENTER_COMMAND, PASTE_COMMAND } from 'lexical';
18
18
  import { KernelPlugin } from "../../../editor-kernel/plugin";
19
19
  import { createDebugLogger } from "../../../utils/debug";
20
+ import { registerMarkdownCommand } from "../command";
20
21
  import MarkdownDataSource from "../data-source/markdown-data-source";
21
- import { parseMarkdownToLexical } from "../data-source/markdown/parse";
22
22
  import { IMarkdownShortCutService, MarkdownShortCutService } from "../service/shortcut";
23
- import { $generateNodesFromSerializedNodes, $insertGeneratedNodes, canContainTransformableMarkdown } from "../utils";
23
+ import { canContainTransformableMarkdown } from "../utils";
24
24
  export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
25
25
  _inherits(MarkdownPlugin, _KernelPlugin);
26
26
  var _super = _createSuper(MarkdownPlugin);
@@ -133,50 +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
- if (!enablePasteMarkdown) {
137
- // Force plain text paste - ignore all formatting (like Cmd+Shift+V)
138
- _this2.logger.debug('paste markdown formatting is disabled, inserting as plain text');
139
- event.preventDefault();
140
- event.stopPropagation();
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
- // Simply insert the plain text
146
- selection.insertText(text);
147
- });
148
- return true;
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
- // If there's HTML content, it's a rich text paste
152
- // Let Lexical's rich text handler process it
153
- if (html && html.trim()) {
154
- _this2.logger.debug('paste content analysis: HTML detected, letting Lexical handle it');
155
- return false;
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
- // Only handle plain text paste - check for markdown patterns
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
- // Handle markdown paste
168
- return _this2.handleMarkdownPaste(editor, text);
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');
169
173
  }
170
- return false;
174
+ return true; // Command handled
171
175
  }, COMMAND_PRIORITY_CRITICAL));
176
+ this.register(registerMarkdownCommand(editor, this.service));
172
177
  }
173
178
 
174
179
  /**
175
180
  * Detect if text contains markdown patterns
181
+ * Returns false if content is likely code (JSON, HTML, SQL, etc.)
176
182
  */
177
183
  }, {
178
184
  key: "detectMarkdownContent",
179
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
+ }
180
222
  var markdownPatterns = [
181
223
  // Headers
182
224
  /^#{1,6}\s+/m,
@@ -260,24 +302,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
260
302
  });
261
303
  }
262
304
 
263
- /**
264
- * Handle markdown paste by parsing and inserting as structured content
265
- */
266
- }, {
267
- key: "handleMarkdownPaste",
268
- value: function handleMarkdownPaste(editor, text) {
269
- try {
270
- // Use the markdown data source to parse the content
271
- var root = parseMarkdownToLexical(text, this.service.markdownReaders);
272
- var selection = $getSelection();
273
- var nodes = $generateNodesFromSerializedNodes(root.children);
274
- $insertGeneratedNodes(editor, nodes, selection);
275
- return true;
276
- } catch (error) {
277
- this.logger.error('Failed to handle markdown paste:', error);
278
- }
279
- return false;
280
- }
305
+ // /**
306
+ // * Handle markdown paste by parsing and inserting as structured content
307
+ // */
308
+ // private handleMarkdownPaste(editor: LexicalEditor, text: string): boolean {
309
+ // try {
310
+ // // Use the markdown data source to parse the content
311
+ // const root = parseMarkdownToLexical(text, this.service.markdownReaders);
312
+ // const selection = $getSelection();
313
+ // const nodes = $generateNodesFromSerializedNodes(root.children);
314
+ // $insertGeneratedNodes(editor, nodes, selection!);
315
+ // return true;
316
+ // } catch (error) {
317
+ // this.logger.error('Failed to handle markdown paste:', error);
318
+ // }
319
+
320
+ // return false;
321
+ // }
281
322
  }]);
282
323
  return MarkdownPlugin;
283
324
  }(KernelPlugin), _defineProperty(_class, "pluginName", 'MarkdownPlugin'), _class);
@@ -0,0 +1,3 @@
1
+ import { type FC } from 'react';
2
+ declare const ReactMarkdownPlugin: FC<void>;
3
+ export default ReactMarkdownPlugin;
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+
3
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
4
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
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
+ 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
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
9
+ import { Button } from '@lobehub/ui';
10
+ import { Space, notification } from 'antd';
11
+ import { UNDO_COMMAND } from 'lexical';
12
+ import { useLayoutEffect } from 'react';
13
+ import { useLexicalComposerContext } from "../../../editor-kernel/react";
14
+ import { useTranslation } from "../../../editor-kernel/react/useTranslation";
15
+ import { INSERT_MARKDOWN_COMMAND } from "../command";
16
+ import { MarkdownPlugin } from "../plugin";
17
+ import { jsx as _jsx } from "react/jsx-runtime";
18
+ import { jsxs as _jsxs } from "react/jsx-runtime";
19
+ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
20
+ var _useLexicalComposerCo = useLexicalComposerContext(),
21
+ _useLexicalComposerCo2 = _slicedToArray(_useLexicalComposerCo, 1),
22
+ editor = _useLexicalComposerCo2[0];
23
+ var _notification$useNoti = notification.useNotification(),
24
+ _notification$useNoti2 = _slicedToArray(_notification$useNoti, 2),
25
+ api = _notification$useNoti2[0],
26
+ contextHolder = _notification$useNoti2[1];
27
+ var t = useTranslation();
28
+ useLayoutEffect(function () {
29
+ editor.registerPlugin(MarkdownPlugin);
30
+ var handleEvent = function handleEvent(_ref) {
31
+ var markdown = _ref.markdown;
32
+ var key = "open".concat(Date.now());
33
+ var actions = /*#__PURE__*/_jsxs(Space, {
34
+ children: [/*#__PURE__*/_jsx(Button, {
35
+ onClick: function onClick() {
36
+ return api.destroy();
37
+ },
38
+ size: "small",
39
+ children: t('markdown.cancel')
40
+ }), /*#__PURE__*/_jsx(Button, {
41
+ onClick: function onClick() {
42
+ editor.dispatchCommand(UNDO_COMMAND, undefined);
43
+ editor.dispatchCommand(INSERT_MARKDOWN_COMMAND, {
44
+ markdown: markdown
45
+ });
46
+ api.destroy();
47
+ },
48
+ size: "small",
49
+ type: "primary",
50
+ children: t('markdown.confirm')
51
+ })]
52
+ });
53
+ api.open({
54
+ actions: actions,
55
+ description: t('markdown.parseMessage'),
56
+ duration: 5,
57
+ key: key,
58
+ message: t('markdown.parseTitle'),
59
+ showProgress: true
60
+ });
61
+ };
62
+ editor.on('markdownParse', handleEvent);
63
+ return function () {
64
+ editor.off('markdownParse', handleEvent);
65
+ };
66
+ }, [editor]);
67
+ return contextHolder;
68
+ };
69
+ ReactMarkdownPlugin.displayName = 'ReactMarkdownPlugin';
70
+ export default ReactMarkdownPlugin;
@@ -1,4 +1,4 @@
1
- import type { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
1
+ import type { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, EditorState, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
2
2
  import type DataSource from "../editor-kernel/data-source";
3
3
  import { HotkeyId } from "./hotkey";
4
4
  import { HotkeyOptions, HotkeysEvent } from "../utils/hotkey/registerHotkey";
@@ -23,6 +23,13 @@ export interface IKernelEventMap {
23
23
  * @returns
24
24
  */
25
25
  initialized: (editor: LexicalEditor) => void;
26
+ /**
27
+ * handle markdown parse event
28
+ */
29
+ markdownParse: (params: {
30
+ cacheState: EditorState;
31
+ markdown: string;
32
+ }) => void;
26
33
  }
27
34
  /**
28
35
  * External API
@@ -175,6 +182,7 @@ export interface IEditor {
175
182
  * API provided to plugins
176
183
  */
177
184
  export interface IEditorKernel extends IEditor {
185
+ emit<T extends keyof IKernelEventMap>(event: T, params: Parameters<IKernelEventMap[T]>[0]): void;
178
186
  /**
179
187
  * Get editor Node decorator for specific Node rendering
180
188
  * @param name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "1.16.3",
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",