@lobehub/editor 4.17.2 → 4.18.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.
Files changed (36) hide show
  1. package/es/headless/index.js +12 -2
  2. package/es/headless.js +3119 -1224
  3. package/es/index.d.ts +1 -1
  4. package/es/index.js +13 -13
  5. package/es/plugins/codeblock/command/index.d.ts +2 -8
  6. package/es/plugins/codeblock/command/index.js +3 -3
  7. package/es/plugins/codeblock/command/symbols.d.ts +8 -0
  8. package/es/plugins/codeblock/command/symbols.js +5 -0
  9. package/es/plugins/codeblock/index.d.ts +1 -1
  10. package/es/plugins/codeblock/index.js +1 -1
  11. package/es/plugins/codeblock/plugin/FacadeShiki.js +1 -1
  12. package/es/plugins/codeblock/plugin/index.js +1 -1
  13. package/es/plugins/codemirror-block/command/index.js +1 -1
  14. package/es/plugins/codemirror-block/node/CodeMirrorNode.js +10 -1
  15. package/es/plugins/codemirror-block/plugin/index.d.ts +1 -1
  16. package/es/plugins/file/plugin/index.d.ts +2 -2
  17. package/es/plugins/file/plugin/index.js +26 -23
  18. package/es/plugins/image/node/block-image-node.d.ts +1 -0
  19. package/es/plugins/image/node/block-image-node.js +6 -0
  20. package/es/plugins/image/node/image-node.d.ts +1 -0
  21. package/es/plugins/image/node/image-node.js +6 -0
  22. package/es/plugins/image/plugin/index.d.ts +3 -3
  23. package/es/plugins/image/plugin/index.js +5 -23
  24. package/es/plugins/image/react/ReactImagePlugin.js +18 -0
  25. package/es/plugins/image/react/components/Image.js +1 -1
  26. package/es/plugins/math/plugin/index.d.ts +1 -1
  27. package/es/plugins/math/react/components/MathEditor.js +1 -1
  28. package/es/plugins/math/react/components/MathInline.js +1 -1
  29. package/es/plugins/mention/plugin/index.d.ts +1 -1
  30. package/es/plugins/mention/plugin/index.js +1 -1
  31. package/es/react/hooks/useEditorState/index.js +2 -2
  32. package/es/renderer/engine/shiki.js +1 -1
  33. package/es/renderer/nodes/index.js +4 -4
  34. package/es/renderer/renderers/codeblock.js +1 -0
  35. package/package.json +1 -1
  36. package/es/headless/plugins/codeblock.js +0 -82
package/es/index.d.ts CHANGED
@@ -26,7 +26,7 @@ import { ANCHOR_PADDING_CSS_VAR, DEFAULT_BLOCK_ANCHOR_PADDING } from "./plugins/
26
26
  import { INSERT_CODEINLINE_COMMAND } from "./plugins/code/command/index.js";
27
27
  import { CodePlugin } from "./plugins/code/plugin/index.js";
28
28
  import { ReactCodePlugin } from "./plugins/code/react/CodeReactPlugin.js";
29
- import { UPDATE_CODEBLOCK_LANG } from "./plugins/codeblock/command/index.js";
29
+ import { UPDATE_CODEBLOCK_LANG } from "./plugins/codeblock/command/symbols.js";
30
30
  import { CodeblockPlugin, CodeblockPluginOptions } from "./plugins/codeblock/plugin/index.js";
31
31
  import { ReactCodeblockPluginProps } from "./plugins/codeblock/react/type.js";
32
32
  import { ReactCodeblockPlugin } from "./plugins/codeblock/react/ReactCodeblockPlugin.js";
package/es/index.js CHANGED
@@ -35,13 +35,26 @@ import ReactEditorContent from "./plugins/common/react/ReactEditorContent.js";
35
35
  import ReactPlainText from "./plugins/common/react/ReactPlainText.js";
36
36
  import { INSERT_CODEINLINE_COMMAND } from "./plugins/code/command/index.js";
37
37
  import { CodePlugin } from "./plugins/code/plugin/index.js";
38
+ import { UPDATE_CODEBLOCK_LANG } from "./plugins/codeblock/command/symbols.js";
39
+ import { INSERT_CODEMIRROR_COMMAND, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND } from "./plugins/codemirror-block/command/index.js";
40
+ import { CodemirrorPlugin } from "./plugins/codemirror-block/plugin/index.js";
41
+ import { IUploadService, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM } from "./plugins/upload/service/i-upload-service.js";
42
+ import { UploadPlugin } from "./plugins/upload/plugin/index.js";
43
+ import { INSERT_FILE_COMMAND } from "./plugins/file/command/index.js";
44
+ import { FilePlugin } from "./plugins/file/plugin/index.js";
38
45
  import { INSERT_HORIZONTAL_RULE_COMMAND } from "./plugins/hr/command/index.js";
39
46
  import { HRPlugin } from "./plugins/hr/plugin/index.js";
47
+ import { INSERT_IMAGE_COMMAND } from "./plugins/image/command/index.js";
48
+ import { ImagePlugin } from "./plugins/image/plugin/index.js";
40
49
  import { INSERT_LINK_COMMAND } from "./plugins/link/command/index.js";
41
50
  import { ILinkService } from "./plugins/link/service/i-link-service.js";
42
51
  import { LinkPlugin } from "./plugins/link/plugin/index.js";
43
52
  import { INSERT_CHECK_LIST_COMMAND } from "./plugins/list/plugin/checkList.js";
44
53
  import { ListPlugin } from "./plugins/list/plugin/index.js";
54
+ import { INSERT_MATH_COMMAND } from "./plugins/math/command/index.js";
55
+ import { MathPlugin } from "./plugins/math/plugin/index.js";
56
+ import { INSERT_MENTION_COMMAND } from "./plugins/mention/command/index.js";
57
+ import { MentionPlugin } from "./plugins/mention/plugin/index.js";
45
58
  import { BlockMenuService, IBlockMenuService } from "./plugins/block/service/i-block-menu-service.js";
46
59
  import { INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, SELECT_TABLE_COMMAND } from "./plugins/table/command/index.js";
47
60
  import { ITableControllerMenuService, TableControllerMenuService } from "./plugins/table/service/i-table-controller-menu-service.js";
@@ -55,26 +68,17 @@ import { BlockPlugin } from "./plugins/block/plugin/index.js";
55
68
  import { ANCHOR_PADDING_CSS_VAR, DEFAULT_BLOCK_ANCHOR_PADDING } from "./plugins/block/react/style.js";
56
69
  import ReactBlockPlugin from "./plugins/block/react/ReactBlockPlugin.js";
57
70
  import ReactCodePlugin from "./plugins/code/react/CodeReactPlugin.js";
58
- import { UPDATE_CODEBLOCK_LANG } from "./plugins/codeblock/command/index.js";
59
71
  import { CodeblockPlugin } from "./plugins/codeblock/plugin/index.js";
60
72
  import ReactCodeblockPlugin from "./plugins/codeblock/react/ReactCodeblockPlugin.js";
61
73
  import { bundledLanguagesInfo } from "./plugins/codeblock/index.js";
62
- import { INSERT_CODEMIRROR_COMMAND, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND } from "./plugins/codemirror-block/command/index.js";
63
- import { CodemirrorPlugin } from "./plugins/codemirror-block/plugin/index.js";
64
74
  import ReactCodemirrorPlugin from "./plugins/codemirror-block/react/ReactCodemirrorNode.js";
65
75
  import { CONTENT_BLOCKS_DATA_TYPE } from "./plugins/content-blocks/types.js";
66
76
  import { extractContentBlocks } from "./plugins/content-blocks/utils/extract.js";
67
77
  import { ContentBlocksDataSource } from "./plugins/content-blocks/data-source/content-blocks-data-source.js";
68
78
  import { ContentBlocksPlugin } from "./plugins/content-blocks/plugin/index.js";
69
79
  import { extractMediaLists } from "./plugins/content-blocks/utils/extract-media-lists.js";
70
- import { INSERT_FILE_COMMAND } from "./plugins/file/command/index.js";
71
- import { IUploadService, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM } from "./plugins/upload/service/i-upload-service.js";
72
- import { UploadPlugin } from "./plugins/upload/plugin/index.js";
73
- import { FilePlugin } from "./plugins/file/plugin/index.js";
74
80
  import ReactFilePlugin from "./plugins/file/react/ReactFilePlugin.js";
75
81
  import ReactHRPlugin from "./plugins/hr/react/ReactHRPlugin.js";
76
- import { INSERT_IMAGE_COMMAND } from "./plugins/image/command/index.js";
77
- import { ImagePlugin } from "./plugins/image/plugin/index.js";
78
82
  import ReactImagePlugin from "./plugins/image/react/ReactImagePlugin.js";
79
83
  import ReactLinkPlugin from "./plugins/link/react/ReactLinkPlugin.js";
80
84
  import { INSERT_LINK_HIGHLIGHT_COMMAND, registerLinkHighlightCommand } from "./plugins/link-highlight/command/index.js";
@@ -82,11 +86,7 @@ import { LinkHighlightPlugin } from "./plugins/link-highlight/plugin/index.js";
82
86
  import ReactLinkHighlightPlugin from "./plugins/link-highlight/react/ReactLinkHighlightPlugin.js";
83
87
  import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, UPDATE_LIST_START_COMMAND } from "./plugins/list/command/index.js";
84
88
  import ReactListPlugin from "./plugins/list/react/ReactListPlugin.js";
85
- import { INSERT_MATH_COMMAND } from "./plugins/math/command/index.js";
86
- import { MathPlugin } from "./plugins/math/plugin/index.js";
87
89
  import { ReactMathPlugin } from "./plugins/math/react/index.js";
88
- import { INSERT_MENTION_COMMAND } from "./plugins/mention/command/index.js";
89
- import { MentionPlugin } from "./plugins/mention/plugin/index.js";
90
90
  import ReactMentionPlugin from "./plugins/mention/react/ReactMentionPlugin.js";
91
91
  import { SlashPlugin } from "./plugins/slash/plugin/index.js";
92
92
  import SlashMenu from "./plugins/slash/react/components/SlashMenu.js";
@@ -1,8 +1,2 @@
1
- import * as _$lexical from "lexical";
2
- import { LexicalEditor } from "lexical";
3
- //#region src/plugins/codeblock/command/index.d.ts
4
- declare const UPDATE_CODEBLOCK_LANG: _$lexical.LexicalCommand<{
5
- lang: string;
6
- }>;
7
- //#endregion
8
- export { UPDATE_CODEBLOCK_LANG };
1
+ import { UPDATE_CODEBLOCK_LANG } from "./symbols.js";
2
+ import { LexicalEditor } from "lexical";
@@ -1,5 +1,6 @@
1
+ import { UPDATE_CODEBLOCK_LANG } from "./symbols.js";
1
2
  import { ShikiTokenizer } from "../plugin/CodeHighlighterShiki.js";
2
- import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createCommand } from "lexical";
3
+ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from "lexical";
3
4
  import { $findMatchingParent } from "@lexical/utils";
4
5
  import { $isCodeNode } from "@lexical/code-core";
5
6
  //#region src/plugins/codeblock/command/index.ts
@@ -9,7 +10,6 @@ const CustomShikiTokenizer = {
9
10
  defaultLanguage: ShikiTokenizer.defaultLanguage,
10
11
  defaultTheme: ShikiTokenizer.defaultTheme
11
12
  };
12
- const UPDATE_CODEBLOCK_LANG = createCommand("UPDATE_CODEBLOCK_LANG");
13
13
  function registerCodeCommand(editor) {
14
14
  const unregisterLangCommand = editor.registerCommand(UPDATE_CODEBLOCK_LANG, (payload) => {
15
15
  CustomShikiTokenizer.defaultLanguage = payload.lang;
@@ -37,4 +37,4 @@ function registerCodeCommand(editor) {
37
37
  };
38
38
  }
39
39
  //#endregion
40
- export { CustomShikiTokenizer, UPDATE_CODEBLOCK_LANG, registerCodeCommand };
40
+ export { CustomShikiTokenizer, registerCodeCommand };
@@ -0,0 +1,8 @@
1
+ import * as _$lexical from "lexical";
2
+
3
+ //#region src/plugins/codeblock/command/symbols.d.ts
4
+ declare const UPDATE_CODEBLOCK_LANG: _$lexical.LexicalCommand<{
5
+ lang: string;
6
+ }>;
7
+ //#endregion
8
+ export { UPDATE_CODEBLOCK_LANG };
@@ -0,0 +1,5 @@
1
+ import { createCommand } from "lexical";
2
+ //#region src/plugins/codeblock/command/symbols.ts
3
+ const UPDATE_CODEBLOCK_LANG = createCommand("UPDATE_CODEBLOCK_LANG");
4
+ //#endregion
5
+ export { UPDATE_CODEBLOCK_LANG };
@@ -1,4 +1,4 @@
1
- import { UPDATE_CODEBLOCK_LANG } from "./command/index.js";
1
+ import { UPDATE_CODEBLOCK_LANG } from "./command/symbols.js";
2
2
  import { CodeblockPlugin, CodeblockPluginOptions } from "./plugin/index.js";
3
3
  import { ReactCodeblockPluginProps } from "./react/type.js";
4
4
  import { ReactCodeblockPlugin } from "./react/ReactCodeblockPlugin.js";
@@ -1,4 +1,4 @@
1
- import "./command/index.js";
1
+ import "./command/symbols.js";
2
2
  import "./plugin/index.js";
3
3
  import "./react/ReactCodeblockPlugin.js";
4
4
  import { bundledLanguagesInfo as bundledLanguagesInfo$1 } from "shiki";
@@ -2,9 +2,9 @@ import { INodeHelper, init_helper } from "../../../editor-kernel/inode/helper.js
2
2
  import { ShikiLobeTheme } from "@lobehub/ui";
3
3
  import { $createLineBreakNode, $createTabNode, $getNodeByKey } from "lexical";
4
4
  import { $createCodeHighlightNode, $isCodeNode } from "@lexical/code-core";
5
- import { bundledLanguagesInfo, bundledThemesInfo } from "shiki";
6
5
  import { createHighlighterCoreSync, isSpecialLang, isSpecialTheme, stringifyTokenStyle } from "@shikijs/core";
7
6
  import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
7
+ import { bundledLanguagesInfo, bundledThemesInfo } from "shiki";
8
8
  //#region src/plugins/codeblock/plugin/FacadeShiki.ts
9
9
  init_helper();
10
10
  const shiki = createHighlighterCoreSync({
@@ -3,9 +3,9 @@ import { KernelPlugin, init_plugin } from "../../../editor-kernel/plugin.js";
3
3
  import { ILitexmlService } from "../../litexml/service/litexml-service.js";
4
4
  import { IMarkdownShortCutService } from "../../markdown/service/shortcut.js";
5
5
  import { IBlockMenuService } from "../../block/service/i-block-menu-service.js";
6
- import { getCodeLanguageByInput } from "../utils/language.js";
7
6
  import { registerCodeHighlighting, toCodeTheme } from "./CodeHighlighterShiki.js";
8
7
  import { CustomShikiTokenizer, registerCodeCommand } from "../command/index.js";
8
+ import { getCodeLanguageByInput } from "../utils/language.js";
9
9
  import { $createRangeSelection, $getSelection, $isRangeSelection, $setSelection, COMMAND_PRIORITY_EDITOR, PASTE_COMMAND, TabNode } from "lexical";
10
10
  import { $createCodeNode, $isCodeHighlightNode, $isCodeNode, CodeHighlightNode, CodeNode } from "@lexical/code-core";
11
11
  //#region src/plugins/codeblock/plugin/index.ts
@@ -1,5 +1,5 @@
1
1
  import { $createCodeMirrorNode, $isCodeMirrorNode } from "../node/CodeMirrorNode.js";
2
- import { UPDATE_CODEBLOCK_LANG } from "../../codeblock/command/index.js";
2
+ import { UPDATE_CODEBLOCK_LANG } from "../../codeblock/command/symbols.js";
3
3
  import { $createNodeSelection, $createParagraphNode, $getNodeByKey, $getSelection, $insertNodes, $isRangeSelection, $setSelection, COMMAND_PRIORITY_EDITOR, createCommand } from "lexical";
4
4
  import { $findMatchingParent, mergeRegister } from "@lexical/utils";
5
5
  //#region src/plugins/codemirror-block/command/index.ts
@@ -10,6 +10,15 @@ const DEFAULT_OPTIONS = {
10
10
  lineNumbers: false,
11
11
  tabSize: 2
12
12
  };
13
+ const extractSerializedCodeText = (children) => children.map((child) => {
14
+ if (!child || typeof child !== "object") return "";
15
+ const record = child;
16
+ if (record.type === "linebreak") return "\n";
17
+ if (record.type === "tab") return " ";
18
+ if (typeof record.text === "string") return record.text;
19
+ if (Array.isArray(record.children)) return extractSerializedCodeText(record.children);
20
+ return "";
21
+ }).join("");
13
22
  function hasChildDOMNodeTag(node, tagName) {
14
23
  for (const child of node.childNodes) {
15
24
  if (isHTMLElement(child) && child.tagName === tagName) return true;
@@ -32,7 +41,7 @@ var CodeMirrorNode = class CodeMirrorNode extends DecoratorNode {
32
41
  }
33
42
  static importJSON(serializedNode) {
34
43
  let code = serializedNode.code;
35
- if ("children" in serializedNode) code = serializedNode.children?.map((child) => child.text).join("") || "";
44
+ if ("children" in serializedNode && Array.isArray(serializedNode.children)) code = extractSerializedCodeText(serializedNode.children);
36
45
  return $createCodeMirrorNode(serializedNode.language, code, serializedNode.codeTheme, serializedNode.options).updateFromJSON(serializedNode);
37
46
  }
38
47
  static importDOM() {
@@ -4,7 +4,7 @@ import { LexicalEditor } from "lexical";
4
4
 
5
5
  //#region src/plugins/codemirror-block/plugin/index.d.ts
6
6
  interface CodemirrorPluginOptions {
7
- decorator: (node: CodeMirrorNode, editor: LexicalEditor) => any;
7
+ decorator?: (node: CodeMirrorNode, editor: LexicalEditor) => any;
8
8
  theme?: string;
9
9
  }
10
10
  declare const CodemirrorPlugin: IEditorPluginConstructor<CodemirrorPluginOptions>;
@@ -4,8 +4,8 @@ import { LexicalEditor } from "lexical";
4
4
 
5
5
  //#region src/plugins/file/plugin/index.d.ts
6
6
  interface FilePluginOptions {
7
- decorator: (node: FileNode, editor: LexicalEditor) => any;
8
- handleUpload: (file: File) => Promise<{
7
+ decorator?: (node: FileNode, editor: LexicalEditor) => any;
8
+ handleUpload?: (file: File) => Promise<{
9
9
  url: string;
10
10
  }>;
11
11
  markdownWriter?: (file: FileNode) => string;
@@ -3,9 +3,9 @@ import { INodeHelper, init_helper } from "../../../editor-kernel/inode/helper.js
3
3
  import { KernelPlugin, init_plugin } from "../../../editor-kernel/plugin.js";
4
4
  import { ILitexmlService } from "../../litexml/service/litexml-service.js";
5
5
  import { IMarkdownShortCutService } from "../../markdown/service/shortcut.js";
6
+ import { IUploadService } from "../../upload/service/i-upload-service.js";
6
7
  import { $createFileNode, $isFileNode, FileNode } from "../node/FileNode.js";
7
8
  import { registerFileCommand } from "../command/index.js";
8
- import { IUploadService } from "../../upload/service/i-upload-service.js";
9
9
  import { registerFileNodeSelectionObserver } from "../utils/index.js";
10
10
  import { $createParagraphNode, $createRangeSelection, $insertNodes, $isRootOrShadowRoot, $setSelection } from "lexical";
11
11
  import { $wrapNodeInElement } from "@lexical/utils";
@@ -29,31 +29,34 @@ const FilePlugin = class extends KernelPlugin {
29
29
  });
30
30
  }
31
31
  onInit(editor) {
32
- this.kernel.requireService(IUploadService)?.registerUpload(async (file, from, range) => {
33
- editor.update(() => {
34
- if (range) {
35
- const rangeSelection = $createRangeSelection();
36
- if (range !== null && range !== void 0) rangeSelection.applyDOMRange(range);
37
- $setSelection(rangeSelection);
38
- }
39
- const fileNode = $createFileNode(file.name);
40
- $insertNodes([fileNode]);
41
- if ($isRootOrShadowRoot(fileNode.getParentOrThrow())) $wrapNodeInElement(fileNode, $createParagraphNode).selectEnd();
42
- this.config.handleUpload(file).then((url) => {
43
- editor.update(() => {
44
- fileNode.setUploaded(url.url);
45
- });
46
- }).catch((error) => {
47
- this.logger.error("File upload failed:", error);
48
- editor.update(() => {
49
- fileNode.setError("File upload failed : " + error.message);
32
+ const handleUpload = this.config?.handleUpload;
33
+ if (handleUpload) {
34
+ this.kernel.requireService(IUploadService)?.registerUpload(async (file, from, range) => {
35
+ editor.update(() => {
36
+ if (range) {
37
+ const rangeSelection = $createRangeSelection();
38
+ if (range !== null && range !== void 0) rangeSelection.applyDOMRange(range);
39
+ $setSelection(rangeSelection);
40
+ }
41
+ const fileNode = $createFileNode(file.name);
42
+ $insertNodes([fileNode]);
43
+ if ($isRootOrShadowRoot(fileNode.getParentOrThrow())) $wrapNodeInElement(fileNode, $createParagraphNode).selectEnd();
44
+ handleUpload(file).then((url) => {
45
+ editor.update(() => {
46
+ fileNode.setUploaded(url.url);
47
+ });
48
+ }).catch((error) => {
49
+ this.logger.error("File upload failed:", error);
50
+ editor.update(() => {
51
+ fileNode.setError("File upload failed : " + error.message);
52
+ });
50
53
  });
51
54
  });
55
+ return null;
52
56
  });
53
- return null;
54
- });
55
- this.register(registerFileCommand(editor, this.config.handleUpload));
56
- this.register(registerFileNodeSelectionObserver(editor));
57
+ this.register(registerFileCommand(editor, handleUpload));
58
+ }
59
+ if (this.config?.decorator) this.register(registerFileNodeSelectionObserver(editor));
57
60
  this.registerLiteXml();
58
61
  this.registerMarkdownWriter();
59
62
  }
@@ -37,6 +37,7 @@ declare class BlockImageNode extends BaseImageNode {
37
37
  static importJSON(serializedNode: SerializedImageNode): BlockImageNode;
38
38
  static importDOM(): DOMConversionMap | null;
39
39
  decorate(): any;
40
+ exportJSON(): SerializedImageNode;
40
41
  createDOM(config: EditorConfig): HTMLElement;
41
42
  }
42
43
  //#endregion
@@ -101,6 +101,12 @@ var BlockImageNode = class BlockImageNode extends BaseImageNode {
101
101
  decorate() {
102
102
  return BlockImageNode._decorate(this);
103
103
  }
104
+ exportJSON() {
105
+ return {
106
+ ...super.exportJSON(),
107
+ status: this.__status
108
+ };
109
+ }
104
110
  createDOM(config) {
105
111
  const span = document.createElement("div");
106
112
  const className = config.theme.blockImage;
@@ -36,6 +36,7 @@ declare class ImageNode extends BaseImageNode {
36
36
  static importJSON(serializedNode: SerializedImageNode): ImageNode;
37
37
  static importDOM(): DOMConversionMap | null;
38
38
  decorate(): any;
39
+ exportJSON(): SerializedImageNode;
39
40
  }
40
41
  //#endregion
41
42
  export { ImageNode };
@@ -98,6 +98,12 @@ var ImageNode = class ImageNode extends BaseImageNode {
98
98
  decorate() {
99
99
  return ImageNode._decorate(this);
100
100
  }
101
+ exportJSON() {
102
+ return {
103
+ ...super.exportJSON(),
104
+ status: this.__status
105
+ };
106
+ }
101
107
  };
102
108
  function $createImageNode({ altText, height, maxWidth = 500, src, width, key, status }) {
103
109
  return $applyNodeReplacement(new ImageNode({
@@ -1,19 +1,19 @@
1
1
  import { IEditorPluginConstructor } from "../../../types/kernel.js";
2
2
  import { BlockImageNode } from "../node/block-image-node.js";
3
3
  import { ImageNode } from "../node/image-node.js";
4
- import { JSX } from "react";
5
4
 
6
5
  //#region src/plugins/image/plugin/index.d.ts
7
6
  interface ImagePluginOptions {
8
7
  defaultBlockImage?: boolean;
8
+ getImageWidth?: (file: File) => Promise<number>;
9
9
  handleRehost?: (url: string) => Promise<{
10
10
  url: string;
11
11
  }>;
12
- handleUpload: (file: File) => Promise<{
12
+ handleUpload?: (file: File) => Promise<{
13
13
  url: string;
14
14
  }>;
15
15
  needRehost?: (url: string) => boolean;
16
- renderImage: (node: ImageNode | BlockImageNode) => JSX.Element | null;
16
+ renderImage?: (node: ImageNode | BlockImageNode) => unknown;
17
17
  theme?: {
18
18
  blockImage?: string;
19
19
  image?: string;
@@ -19,12 +19,12 @@ const ImagePlugin = class extends KernelPlugin {
19
19
  this.kernel = kernel;
20
20
  this.config = config;
21
21
  kernel.registerNodes([ImageNode, BlockImageNode]);
22
- ImageNode.setDecorate(config.renderImage);
23
- BlockImageNode.setDecorate(config.renderImage);
22
+ ImageNode.setDecorate(config?.renderImage ?? (() => null));
23
+ BlockImageNode.setDecorate(config?.renderImage ?? (() => null));
24
24
  if (config?.theme) kernel.registerThemes(config.theme);
25
25
  }
26
26
  onInit(editor) {
27
- this.register(registerImageCommand(editor, this.config.handleUpload, this.config?.defaultBlockImage !== false));
27
+ if (this.config?.handleUpload) this.register(registerImageCommand(editor, this.config.handleUpload, this.config?.defaultBlockImage !== false));
28
28
  this.registerMarkdown();
29
29
  this.registerLiteXml();
30
30
  this.registerINode();
@@ -65,8 +65,9 @@ const ImagePlugin = class extends KernelPlugin {
65
65
  registerUpload(editor) {
66
66
  const uploadService = this.kernel.requireService(IUploadService);
67
67
  if (!uploadService) return;
68
+ if (!this.config?.handleUpload) return;
68
69
  uploadService.registerUpload(async (file, from, range) => {
69
- const imageWidth = await this.getImageWidth(file);
70
+ const imageWidth = await this.config?.getImageWidth?.(file);
70
71
  return editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
71
72
  block: this.config?.defaultBlockImage !== false,
72
73
  file,
@@ -159,25 +160,6 @@ const ImagePlugin = class extends KernelPlugin {
159
160
  });
160
161
  });
161
162
  }
162
- getImageWidth(file) {
163
- return new Promise((resolve) => {
164
- const reader = new FileReader();
165
- reader.addEventListener("load", (e) => {
166
- const img = new Image();
167
- img.addEventListener("load", () => {
168
- resolve(img.naturalWidth);
169
- });
170
- img.addEventListener("error", () => {
171
- resolve(800);
172
- });
173
- img.src = e.target?.result;
174
- });
175
- reader.addEventListener("error", () => {
176
- resolve(800);
177
- });
178
- reader.readAsDataURL(file);
179
- });
180
- }
181
163
  };
182
164
  //#endregion
183
165
  export { ImagePlugin };
@@ -7,6 +7,23 @@ import Image from "./components/Image.js";
7
7
  import { useLayoutEffect } from "react";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  //#region src/plugins/image/react/ReactImagePlugin.tsx
10
+ const getImageWidth = (file) => new Promise((resolve) => {
11
+ const reader = new FileReader();
12
+ reader.addEventListener("load", (event) => {
13
+ const img = new window.Image();
14
+ img.addEventListener("load", () => {
15
+ resolve(img.naturalWidth);
16
+ });
17
+ img.addEventListener("error", () => {
18
+ resolve(800);
19
+ });
20
+ img.src = event.target?.result;
21
+ });
22
+ reader.addEventListener("error", () => {
23
+ resolve(800);
24
+ });
25
+ reader.readAsDataURL(file);
26
+ });
10
27
  const defaultUpload = (file) => {
11
28
  return new Promise((resolve) => {
12
29
  setTimeout(() => {
@@ -20,6 +37,7 @@ const ReactImagePlugin = ({ theme, className, defaultBlockImage, handleUpload, n
20
37
  editor.registerPlugin(UploadPlugin);
21
38
  editor.registerPlugin(ImagePlugin, {
22
39
  defaultBlockImage,
40
+ getImageWidth,
23
41
  handleRehost,
24
42
  handleUpload: handleUpload || defaultUpload,
25
43
  needRehost,
@@ -1,6 +1,6 @@
1
1
  import { useLexicalEditor } from "../../../../editor-kernel/react/useLexicalEditor.js";
2
- import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
3
2
  import { $isBlockImageNode } from "../../node/block-image-node.js";
3
+ import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
4
4
  import { styles } from "./style.js";
5
5
  import BrokenImage from "./BrokenImage.js";
6
6
  import ImageEditPopover from "./ImageEditPopover.js";
@@ -4,7 +4,7 @@ import { LexicalEditor } from "lexical";
4
4
 
5
5
  //#region src/plugins/math/plugin/index.d.ts
6
6
  interface MathPluginOptions {
7
- decorator: (node: MathInlineNode | MathBlockNode, editor: LexicalEditor) => unknown;
7
+ decorator?: (node: MathInlineNode | MathBlockNode, editor: LexicalEditor) => unknown;
8
8
  theme?: {
9
9
  mathBlock?: string;
10
10
  mathInline?: string;
@@ -1,9 +1,9 @@
1
1
  import { compareNodeOrder, init_utils } from "../../../../editor-kernel/utils.js";
2
2
  import { useLexicalComposerContext } from "../../../../editor-kernel/react/react-context.js";
3
3
  import { useLexicalEditor } from "../../../../editor-kernel/react/useLexicalEditor.js";
4
- import PortalAnchor from "../../../../editor-kernel/react/PortalAnchor.js";
5
4
  import { $isMathNode, MathBlockNode } from "../../node/index.js";
6
5
  import { SELECT_MATH_SIDE_COMMAND, UPDATE_MATH_COMMAND } from "../../command/index.js";
6
+ import PortalAnchor from "../../../../editor-kernel/react/PortalAnchor.js";
7
7
  import MathEditorContainer from "./MathEditorContainer.js";
8
8
  import MathEditorContent from "./MathEditorContent.js";
9
9
  import { memo, useCallback, useEffect, useRef, useState } from "react";
@@ -1,7 +1,7 @@
1
1
  import { createDebugLogger, init_debug } from "../../../../utils/debug.js";
2
2
  import { useLexicalEditor } from "../../../../editor-kernel/react/useLexicalEditor.js";
3
- import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
4
3
  import { $isMathNode, MathBlockNode } from "../../node/index.js";
4
+ import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
5
5
  import Placeholder from "./Placeholder.js";
6
6
  import { useCallback, useEffect, useRef, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
@@ -6,7 +6,7 @@ import { LexicalEditor } from "lexical";
6
6
 
7
7
  //#region src/plugins/mention/plugin/index.d.ts
8
8
  interface MentionPluginOptions {
9
- decorator: (node: MentionNode, editor: LexicalEditor) => any;
9
+ decorator?: (node: MentionNode, editor: LexicalEditor) => any;
10
10
  markdownReader?: (node: Html, children: INode[]) => SerializedMentionNode | null | false;
11
11
  markdownWriter?: (mention: MentionNode) => string;
12
12
  theme?: {
@@ -24,7 +24,7 @@ const MentionPlugin = class extends KernelPlugin {
24
24
  }
25
25
  onInit(editor) {
26
26
  this.register(registerMentionCommand(editor));
27
- this.register(registerMentionNodeSelectionObserver(editor));
27
+ if (this.config?.decorator) this.register(registerMentionNodeSelectionObserver(editor));
28
28
  this.registerMarkdown();
29
29
  this.registerLiteXml();
30
30
  }
@@ -3,13 +3,13 @@ import { noop } from "../../../editor-kernel/utils.js";
3
3
  import { $createCodeMirrorNode, $isCodeMirrorNode } from "../../../plugins/codemirror-block/node/CodeMirrorNode.js";
4
4
  import { $isSelectionInCodeInline } from "../../../plugins/code/node/code.js";
5
5
  import { INSERT_CODEINLINE_COMMAND } from "../../../plugins/code/command/index.js";
6
+ import { UPDATE_CODEBLOCK_LANG } from "../../../plugins/codeblock/command/symbols.js";
6
7
  import { $isLinkNode, TOGGLE_LINK_COMMAND, formatUrl } from "../../../plugins/link/node/LinkNode.js";
7
8
  import { extractUrlFromText, sanitizeUrl, validateUrl } from "../../../plugins/link/utils/index.js";
8
9
  import { INSERT_CHECK_LIST_COMMAND } from "../../../plugins/list/plugin/checkList.js";
9
- import { UPDATE_CODEBLOCK_LANG } from "../../../plugins/codeblock/command/index.js";
10
+ import { $createMathBlockNode, $createMathInlineNode } from "../../../plugins/math/node/index.js";
10
11
  import { $isLinkHighlightNode } from "../../../plugins/link-highlight/node/link-highlight.js";
11
12
  import { INSERT_LINK_HIGHLIGHT_COMMAND } from "../../../plugins/link-highlight/command/index.js";
12
- import { $createMathBlockNode, $createMathInlineNode } from "../../../plugins/math/node/index.js";
13
13
  import { $findTopLevelElement, formatParagraph, getSelectedNode } from "./utils.js";
14
14
  import { useCallback, useEffect, useMemo, useState } from "react";
15
15
  import { $createNodeSelection, $getSelection, $isParagraphNode, $isRangeSelection, $setSelection, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, FORMAT_TEXT_COMMAND, REDO_COMMAND, SELECTION_CHANGE_COMMAND, UNDO_COMMAND } from "lexical";
@@ -1,6 +1,6 @@
1
- import { bundledLanguagesInfo } from "shiki";
2
1
  import { createHighlighterCoreSync, isSpecialLang } from "@shikijs/core";
3
2
  import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
3
+ import { bundledLanguagesInfo } from "shiki";
4
4
  //#region src/renderer/engine/shiki.ts
5
5
  let _highlighter = null;
6
6
  function getHighlighter() {
@@ -2,15 +2,15 @@ import { CursorNode } from "../../plugins/common/node/cursor.js";
2
2
  import { DiffNode } from "../../plugins/litexml/node/DiffNode.js";
3
3
  import { CodeMirrorNode } from "../../plugins/codemirror-block/node/CodeMirrorNode.js";
4
4
  import { CodeNode } from "../../plugins/code/node/code.js";
5
- import { HorizontalRuleNode } from "../../plugins/hr/node/HorizontalRuleNode.js";
6
- import { AutoLinkNode, LinkNode } from "../../plugins/link/node/LinkNode.js";
7
- import { PlaceholderBlockNode, PlaceholderNode } from "../../plugins/auto-complete/node/placeholderNode.js";
8
5
  import { FileNode } from "../../plugins/file/node/FileNode.js";
6
+ import { HorizontalRuleNode } from "../../plugins/hr/node/HorizontalRuleNode.js";
9
7
  import { BlockImageNode } from "../../plugins/image/node/block-image-node.js";
10
8
  import { ImageNode } from "../../plugins/image/node/image-node.js";
11
- import { LinkHighlightNode } from "../../plugins/link-highlight/node/link-highlight.js";
9
+ import { AutoLinkNode, LinkNode } from "../../plugins/link/node/LinkNode.js";
12
10
  import { MathBlockNode, MathInlineNode } from "../../plugins/math/node/index.js";
13
11
  import { MentionNode } from "../../plugins/mention/node/MentionNode.js";
12
+ import { PlaceholderBlockNode, PlaceholderNode } from "../../plugins/auto-complete/node/placeholderNode.js";
13
+ import { LinkHighlightNode } from "../../plugins/link-highlight/node/link-highlight.js";
14
14
  import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
15
15
  import { HeadingNode, QuoteNode } from "@lexical/rich-text";
16
16
  import { ListItemNode, ListNode } from "@lexical/list";
@@ -10,6 +10,7 @@ function CodeBlockRenderer({ node }) {
10
10
  defaultExpand: true,
11
11
  language: language || "text",
12
12
  variant: "filled",
13
+ wrap: true,
13
14
  children: code
14
15
  });
15
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.17.2",
3
+ "version": "4.18.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",