@lobehub/editor 1.16.3 → 1.17.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/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
  },
@@ -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
+ }
@@ -68,6 +68,10 @@ function convertMdastToLexical(node, index, ctx) {
68
68
  var htmlStack = []; // 当前循环是否包含 HTML 标签
69
69
  _children = node.children.reduce(function (ret, child, index) {
70
70
  if (child.type === 'html') {
71
+ var isComment = child.value.startsWith('<!--') && child.value.endsWith('-->');
72
+ if (isComment) {
73
+ return ret;
74
+ }
71
75
  var tag = child.value.replaceAll(/^<\/?|>$/g, '');
72
76
  var isEndTag = child.value.startsWith('</');
73
77
  if (selfClosingHtmlTags.has(tag)) {
@@ -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);
@@ -165,10 +165,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
165
165
  });
166
166
  if (hasMarkdownContent) {
167
167
  // Handle markdown paste
168
- return _this2.handleMarkdownPaste(editor, text);
168
+ // return this.handleMarkdownPaste(editor, text);
169
+ var cacheState = editor.getEditorState();
170
+ _this2.kernel.emit('markdownParse', {
171
+ cacheState: cacheState,
172
+ markdown: text
173
+ });
174
+ // setTimeout(() => {
175
+ // editor.setEditorState(cacheState);
176
+ // editor.update(() => {
177
+ // this.handleMarkdownPaste(editor, text);
178
+ // });
179
+ // }, 5000);
180
+ return false;
169
181
  }
170
182
  return false;
171
183
  }, COMMAND_PRIORITY_CRITICAL));
184
+ this.register(registerMarkdownCommand(editor, this.service));
172
185
  }
173
186
 
174
187
  /**
@@ -260,24 +273,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
260
273
  });
261
274
  }
262
275
 
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
- }
276
+ // /**
277
+ // * Handle markdown paste by parsing and inserting as structured content
278
+ // */
279
+ // private handleMarkdownPaste(editor: LexicalEditor, text: string): boolean {
280
+ // try {
281
+ // // Use the markdown data source to parse the content
282
+ // const root = parseMarkdownToLexical(text, this.service.markdownReaders);
283
+ // const selection = $getSelection();
284
+ // const nodes = $generateNodesFromSerializedNodes(root.children);
285
+ // $insertGeneratedNodes(editor, nodes, selection!);
286
+ // return true;
287
+ // } catch (error) {
288
+ // this.logger.error('Failed to handle markdown paste:', error);
289
+ // }
290
+
291
+ // return false;
292
+ // }
281
293
  }]);
282
294
  return MarkdownPlugin;
283
295
  }(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, Space, notification } from 'antd';
10
+ import { UNDO_COMMAND } from 'lexical';
11
+ import { useLayoutEffect } from 'react';
12
+ import { useLexicalComposerContext } from "../../../editor-kernel/react";
13
+ import { useTranslation } from "../../../editor-kernel/react/useTranslation";
14
+ import { INSERT_MARKDOWN_COMMAND } from "../command";
15
+ import { MarkdownPlugin } from "../plugin";
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ import { jsxs as _jsxs } from "react/jsx-runtime";
18
+ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
19
+ var _useLexicalComposerCo = useLexicalComposerContext(),
20
+ _useLexicalComposerCo2 = _slicedToArray(_useLexicalComposerCo, 1),
21
+ editor = _useLexicalComposerCo2[0];
22
+ var _notification$useNoti = notification.useNotification(),
23
+ _notification$useNoti2 = _slicedToArray(_notification$useNoti, 2),
24
+ api = _notification$useNoti2[0],
25
+ contextHolder = _notification$useNoti2[1];
26
+ var t = useTranslation();
27
+ useLayoutEffect(function () {
28
+ editor.registerPlugin(MarkdownPlugin);
29
+ var handleEvent = function handleEvent(_ref) {
30
+ var markdown = _ref.markdown;
31
+ var key = "open".concat(Date.now());
32
+ var actions = /*#__PURE__*/_jsxs(Space, {
33
+ children: [/*#__PURE__*/_jsx(Button, {
34
+ onClick: function onClick() {
35
+ return api.destroy();
36
+ },
37
+ size: "small",
38
+ type: "link",
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
+ onClose: close
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.0",
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",