@lobehub/editor 4.8.4 → 4.9.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/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as IEditor$1, S as ReactPlainTextProps, V as _default, a as ReactSlashOptionProps, g as ReactMentionPluginProps, i as MenuRenderProps, x as ReactEditorContentProps } from "./index-BfKEHYDe.js";
1
+ import { P as IEditor$1, S as ReactPlainTextProps, V as _default, a as ReactSlashOptionProps, g as ReactMentionPluginProps, i as MenuRenderProps, x as ReactEditorContentProps } from "./index-BXj6uAM3.js";
2
2
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
3
  import * as _$react from "react";
4
4
  import { CSSProperties, ComponentProps, FC, ReactNode, Ref } from "react";
package/es/react.js CHANGED
@@ -1,15 +1,15 @@
1
- import { A as $createCodeMirrorNode, B as Editor$2, Bt as $isRootTextContentEmpty, S as formatUrl, T as $isSelectionInCodeInline, Ut as init_utils, a as $createMathBlockNode, d as $isLinkHighlightNode, h as $isLinkNode, j as $isCodeMirrorNode, mt as noop, o as $createMathInlineNode, x as TOGGLE_LINK_COMMAND } from "./style-Tlcvrhqp.js";
2
- import { C as ReactEditorContent, J as ReactEditor, N as ReactMarkdownPlugin, S as ReactPlainText, a as ReactMentionPlugin, b as INSERT_CODEINLINE_COMMAND, c as INSERT_CHECK_LIST_COMMAND, f as extractUrlFromText, h as validateUrl, m as sanitizeUrl, n as ReactSlashOption, t as ReactSlashPlugin, u as INSERT_LINK_HIGHLIGHT_COMMAND, y as UPDATE_CODEBLOCK_LANG } from "./ReactSlashPlugin-BZvB0g1k.js";
1
+ import { A as $createCodeMirrorNode, B as Editor$2, Bt as $isRootTextContentEmpty, S as formatUrl, T as $isSelectionInCodeInline, Ut as init_utils, a as $createMathBlockNode, d as $isLinkHighlightNode, h as $isLinkNode, j as $isCodeMirrorNode, mt as noop, o as $createMathInlineNode, x as TOGGLE_LINK_COMMAND } from "./style-DAKdXzC4.js";
2
+ import { C as ReactPlainText, E as ReactMarkdownPlugin, Y as ReactEditor, _ as UPDATE_CODEBLOCK_LANG, a as ReactMentionPlugin, c as INSERT_LINK_HIGHLIGHT_COMMAND, f as sanitizeUrl, n as ReactSlashOption, p as validateUrl, t as ReactSlashPlugin, u as extractUrlFromText, w as ReactEditorContent, x as INSERT_CODEINLINE_COMMAND, y as INSERT_CHECK_LIST_COMMAND } from "./ReactSlashPlugin-Dn5VWUzS.js";
3
3
  import { $createNodeSelection, $createParagraphNode, $getSelection, $isParagraphNode, $isRangeSelection, $isRootOrShadowRoot, $setSelection, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, FORMAT_TEXT_COMMAND, REDO_COMMAND, SELECTION_CHANGE_COMMAND, UNDO_COMMAND } from "lexical";
4
4
  import { $createQuoteNode, $isHeadingNode, $isQuoteNode } from "@lexical/rich-text";
5
5
  import { $findMatchingParent, $getNearestNodeOfType, mergeRegister } from "@lexical/utils";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { createContext, createElement, isValidElement, memo, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
8
- import { ActionIcon, Block, Button, Dropdown, Flexbox, Icon, MaterialFileTypeIcon, Menu, Popover, Select, Text, TooltipGroup, useMotionComponent } from "@lobehub/ui";
9
- import { $createCodeNode, $isCodeNode } from "@lexical/code-core";
10
- import { createStaticStyles, cssVar, cx, useThemeMode } from "antd-style";
11
8
  import { $isAtNodeEnd, $setBlocksType } from "@lexical/selection";
12
9
  import { $isListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode } from "@lexical/list";
10
+ import { $createCodeNode, $isCodeNode } from "@lexical/code-core";
11
+ import { ActionIcon, Block, Button, Dropdown, Flexbox, Icon, MaterialFileTypeIcon, Menu, Popover, Select, Text, TooltipGroup, useMotionComponent } from "@lobehub/ui";
12
+ import { createStaticStyles, cssVar, cx, useThemeMode } from "antd-style";
13
13
  import { ChevronDownIcon, CircleChevronLeftIcon, CircleChevronRightIcon, CircleChevronUpIcon } from "lucide-react";
14
14
  import { createPortal } from "react-dom";
15
15
  import { bundledLanguagesInfo } from "shiki";
package/es/renderer.js CHANGED
@@ -1,18 +1,18 @@
1
- import { E as CodeNode, L as CursorNode, M as CodeMirrorNode, O as styles, _ as AutoLinkNode, b as LinkNode, c as MathBlockNode, f as LinkHighlightNode, i as MentionNode, l as MathInlineNode, t as styles$1 } from "./style-Tlcvrhqp.js";
2
- import { S as PlaceholderNode, a as styles$5, b as DiffNode, c as ImageNode, d as BlockImageNode, h as styles$6, m as HorizontalRuleNode, n as styles$4, r as styles$2, t as styles$3, v as FileNode, x as PlaceholderBlockNode } from "./style-B7Vfm0cE.js";
1
+ import { E as CodeNode, L as CursorNode, M as CodeMirrorNode, O as styles, _ as AutoLinkNode, b as LinkNode, c as MathBlockNode, f as LinkHighlightNode, i as MentionNode, l as MathInlineNode, t as styles$1 } from "./style-DAKdXzC4.js";
2
+ import { S as DiffNode, _ as PlaceholderNode, a as styles$5, b as HorizontalRuleNode, c as ImageNode, d as BlockImageNode, f as styles$6, g as PlaceholderBlockNode, h as FileNode, n as styles$4, r as styles$2, t as styles$3 } from "./style-CcDKrOoJ.js";
3
+ import { createHeadlessEditor } from "@lexical/headless";
3
4
  import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
4
5
  import { $getRoot, $isElementNode, $isTextNode } from "lexical";
5
6
  import { HeadingNode, QuoteNode } from "@lexical/rich-text";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
  import { createElement, useMemo } from "react";
8
- import { Highlighter, Mermaid } from "@lobehub/ui";
9
+ import { ListItemNode, ListNode } from "@lexical/list";
9
10
  import katex from "katex";
11
+ import { Highlighter, Mermaid } from "@lobehub/ui";
10
12
  import { createStaticStyles, cx } from "antd-style";
11
- import { ListItemNode, ListNode } from "@lexical/list";
13
+ import { bundledLanguagesInfo } from "shiki";
12
14
  import { createHighlighterCoreSync, isSpecialLang } from "@shikijs/core";
13
15
  import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
14
- import { bundledLanguagesInfo } from "shiki";
15
- import { createHeadlessEditor } from "@lexical/headless";
16
16
  //#region src/renderer/engine/shiki.ts
17
17
  let _highlighter = null;
18
18
  function getHighlighter() {
@@ -121,6 +121,65 @@ function formatLinkHighlightUrl(url) {
121
121
  function textToSlug(text) {
122
122
  return text.toLowerCase().trim().replaceAll(/[^\s\w\u3000-\u9FFF\uAC00-\uD7AF\uFF00-\uFFEF-]/g, "").replaceAll(/[\s_]+/g, "-").replaceAll(/^-+|-+$/g, "");
123
123
  }
124
+ const DIFF_ROOT_STYLE = { position: "relative" };
125
+ const DIFF_LIST_ITEM_ROOT_STYLE = {
126
+ display: "inline-block",
127
+ minWidth: "100%",
128
+ position: "relative"
129
+ };
130
+ const DIFF_DELETED_STYLE = {
131
+ color: "var(--ant-color-text-quaternary, rgba(0, 0, 0, 0.45))",
132
+ textDecoration: "line-through"
133
+ };
134
+ function renderDiffNode(node, key, children) {
135
+ const diffType = typeof node.diffType === "string" ? node.diffType : "unchanged";
136
+ const renderedChildren = children ?? [];
137
+ const sharedContentStyle = {
138
+ marginBlockStart: "calc(var(--lobe-markdown-margin-multiple, 1) * 0.5em)",
139
+ paddingInlineEnd: 4
140
+ };
141
+ const borderColor = diffType === "add" || diffType === "listItemAdd" ? "var(--ant-color-success, #52c41a)" : diffType === "remove" || diffType === "listItemRemove" ? "var(--ant-color-error, #ff4d4f)" : "var(--ant-color-warning, #faad14)";
142
+ const contentStyle = diffType === "unchanged" ? sharedContentStyle : {
143
+ ...sharedContentStyle,
144
+ borderInlineEnd: `3px solid ${borderColor}`
145
+ };
146
+ const rootStyle = diffType === "listItemAdd" || diffType === "listItemModify" || diffType === "listItemRemove" ? DIFF_LIST_ITEM_ROOT_STYLE : DIFF_ROOT_STYLE;
147
+ const wrapChild = (child, childKey, style) => {
148
+ if (child === void 0 || child === null) return null;
149
+ return /* @__PURE__ */ jsx("div", {
150
+ style,
151
+ children: child
152
+ }, childKey);
153
+ };
154
+ let content;
155
+ switch (diffType) {
156
+ case "add":
157
+ case "listItemAdd":
158
+ content = wrapChild(renderedChildren[0], `${key}-add`);
159
+ break;
160
+ case "remove":
161
+ case "listItemRemove":
162
+ content = wrapChild(renderedChildren[0], `${key}-remove`, DIFF_DELETED_STYLE);
163
+ break;
164
+ case "modify":
165
+ case "listItemModify":
166
+ content = [wrapChild(renderedChildren[0], `${key}-old`, DIFF_DELETED_STYLE), wrapChild(renderedChildren[1], `${key}-new`)];
167
+ break;
168
+ default:
169
+ content = renderedChildren;
170
+ break;
171
+ }
172
+ return /* @__PURE__ */ jsx("div", {
173
+ className: "ne-diff",
174
+ "data-diff-type": diffType,
175
+ style: rootStyle,
176
+ children: /* @__PURE__ */ jsx("div", {
177
+ className: "content",
178
+ style: contentStyle,
179
+ children: content
180
+ })
181
+ }, key);
182
+ }
124
183
  function renderBuiltinNode(node, key, children, headingSlugs, textContent) {
125
184
  switch (node.type) {
126
185
  case "root": return children;
@@ -216,6 +275,7 @@ function renderBuiltinNode(node, key, children, headingSlugs, textContent) {
216
275
  children: node.text
217
276
  }, key);
218
277
  return /* @__PURE__ */ jsx("span", { children: node.text }, key);
278
+ case "diff": return renderDiffNode(node, key, children);
219
279
  case "cursor": return null;
220
280
  default:
221
281
  console.warn(`[LexicalRenderer] Unknown node type: "${node.type}"`);
@@ -1,93 +1,7 @@
1
- import { I as CardLikeElementNode, ht as reconcileDecorator, ot as getKernelFromEditor, st as getKernelFromEditorConfig, ut as init_utils } from "./style-Tlcvrhqp.js";
1
+ import { I as CardLikeElementNode, ht as reconcileDecorator, ot as getKernelFromEditor, st as getKernelFromEditorConfig, ut as init_utils } from "./style-DAKdXzC4.js";
2
2
  import { $applyNodeReplacement, DecoratorNode, ElementNode } from "lexical";
3
3
  import { addClassNamesToElement } from "@lexical/utils";
4
4
  import { createStaticStyles, cx } from "antd-style";
5
- //#region src/plugins/auto-complete/node/placeholderNode.ts
6
- var PlaceholderNode = class PlaceholderNode extends ElementNode {
7
- static getType() {
8
- return "PlaceholderInline";
9
- }
10
- static clone(node) {
11
- return new PlaceholderNode(node.__key);
12
- }
13
- static importJSON(serializedNode) {
14
- return $createPlaceholderNode().updateFromJSON(serializedNode);
15
- }
16
- createDOM(config) {
17
- const element = document.createElement("span");
18
- element.setAttribute("data-lexical-key", this.getKey());
19
- addClassNamesToElement(element, config.theme.placeholderInline);
20
- return element;
21
- }
22
- updateDOM(prevNode, dom, config) {
23
- if ((prevNode ? prevNode : null) !== this) addClassNamesToElement(dom, config.theme.placeholderInline);
24
- return false;
25
- }
26
- canBeEmpty() {
27
- return false;
28
- }
29
- isCardLike() {
30
- return true;
31
- }
32
- isInline() {
33
- return true;
34
- }
35
- canIndent() {
36
- return false;
37
- }
38
- canInsertTextBefore() {
39
- return true;
40
- }
41
- canInsertTextAfter() {
42
- return true;
43
- }
44
- };
45
- var PlaceholderBlockNode = class PlaceholderBlockNode extends ElementNode {
46
- static getType() {
47
- return "PlaceholderBlock";
48
- }
49
- static clone(node) {
50
- return new PlaceholderBlockNode(node.__key);
51
- }
52
- static importJSON(serializedNode) {
53
- return $createPlaceholderBlockNode().updateFromJSON(serializedNode);
54
- }
55
- createDOM(config) {
56
- const element = document.createElement("div");
57
- element.setAttribute("data-lexical-key", this.getKey());
58
- addClassNamesToElement(element, config.theme.placeholderBlock);
59
- return element;
60
- }
61
- updateDOM(prevNode, dom, config) {
62
- if ((prevNode ? prevNode : null) !== this) addClassNamesToElement(dom, config.theme.placeholderBlock);
63
- return false;
64
- }
65
- canBeEmpty() {
66
- return false;
67
- }
68
- isCardLike() {
69
- return true;
70
- }
71
- isInline() {
72
- return false;
73
- }
74
- canIndent() {
75
- return false;
76
- }
77
- canInsertTextBefore() {
78
- return false;
79
- }
80
- canInsertTextAfter() {
81
- return false;
82
- }
83
- };
84
- function $createPlaceholderNode() {
85
- return $applyNodeReplacement(new PlaceholderNode());
86
- }
87
- function $createPlaceholderBlockNode() {
88
- return $applyNodeReplacement(new PlaceholderBlockNode());
89
- }
90
- //#endregion
91
5
  //#region src/plugins/litexml/node/DiffNode.ts
92
6
  init_utils();
93
7
  /** DiffNode - contains two block children: original and modified */
@@ -179,6 +93,147 @@ function $createDiffNode(diffType = "unchanged") {
179
93
  return $applyNodeReplacement(new DiffNode(diffType));
180
94
  }
181
95
  //#endregion
96
+ //#region src/plugins/hr/node/HorizontalRuleNode.ts
97
+ init_utils();
98
+ var HorizontalRuleNode = class HorizontalRuleNode extends DecoratorNode {
99
+ static getType() {
100
+ return "horizontalrule";
101
+ }
102
+ static clone(node) {
103
+ return new HorizontalRuleNode(node.__key);
104
+ }
105
+ static importJSON(serializedNode) {
106
+ return $createHorizontalRuleNode().updateFromJSON(serializedNode);
107
+ }
108
+ static importDOM() {
109
+ return { hr: () => ({
110
+ conversion: $convertHorizontalRuleElement,
111
+ priority: 0
112
+ }) };
113
+ }
114
+ exportDOM() {
115
+ return { element: document.createElement("hr") };
116
+ }
117
+ createDOM(config) {
118
+ const element = document.createElement("div");
119
+ addClassNamesToElement(element, config.theme.hr);
120
+ return element;
121
+ }
122
+ getTextContent() {
123
+ return "\n";
124
+ }
125
+ isInline() {
126
+ return false;
127
+ }
128
+ updateDOM() {
129
+ return false;
130
+ }
131
+ decorate(editor) {
132
+ const decorator = getKernelFromEditor(editor)?.getDecorator("horizontalrule");
133
+ if (!decorator) return null;
134
+ if (typeof decorator === "function") return decorator(this, editor);
135
+ return {
136
+ queryDOM: decorator.queryDOM,
137
+ render: decorator.render(this, editor)
138
+ };
139
+ }
140
+ };
141
+ function $createHorizontalRuleNode() {
142
+ return $applyNodeReplacement(new HorizontalRuleNode());
143
+ }
144
+ function $convertHorizontalRuleElement() {
145
+ return { node: $createHorizontalRuleNode() };
146
+ }
147
+ function $isHorizontalRuleNode(node) {
148
+ return node.getType() === HorizontalRuleNode.getType();
149
+ }
150
+ //#endregion
151
+ //#region src/plugins/auto-complete/node/placeholderNode.ts
152
+ var PlaceholderNode = class PlaceholderNode extends ElementNode {
153
+ static getType() {
154
+ return "PlaceholderInline";
155
+ }
156
+ static clone(node) {
157
+ return new PlaceholderNode(node.__key);
158
+ }
159
+ static importJSON(serializedNode) {
160
+ return $createPlaceholderNode().updateFromJSON(serializedNode);
161
+ }
162
+ createDOM(config) {
163
+ const element = document.createElement("span");
164
+ element.setAttribute("data-lexical-key", this.getKey());
165
+ addClassNamesToElement(element, config.theme.placeholderInline);
166
+ return element;
167
+ }
168
+ updateDOM(prevNode, dom, config) {
169
+ if ((prevNode ? prevNode : null) !== this) addClassNamesToElement(dom, config.theme.placeholderInline);
170
+ return false;
171
+ }
172
+ canBeEmpty() {
173
+ return false;
174
+ }
175
+ isCardLike() {
176
+ return true;
177
+ }
178
+ isInline() {
179
+ return true;
180
+ }
181
+ canIndent() {
182
+ return false;
183
+ }
184
+ canInsertTextBefore() {
185
+ return true;
186
+ }
187
+ canInsertTextAfter() {
188
+ return true;
189
+ }
190
+ };
191
+ var PlaceholderBlockNode = class PlaceholderBlockNode extends ElementNode {
192
+ static getType() {
193
+ return "PlaceholderBlock";
194
+ }
195
+ static clone(node) {
196
+ return new PlaceholderBlockNode(node.__key);
197
+ }
198
+ static importJSON(serializedNode) {
199
+ return $createPlaceholderBlockNode().updateFromJSON(serializedNode);
200
+ }
201
+ createDOM(config) {
202
+ const element = document.createElement("div");
203
+ element.setAttribute("data-lexical-key", this.getKey());
204
+ addClassNamesToElement(element, config.theme.placeholderBlock);
205
+ return element;
206
+ }
207
+ updateDOM(prevNode, dom, config) {
208
+ if ((prevNode ? prevNode : null) !== this) addClassNamesToElement(dom, config.theme.placeholderBlock);
209
+ return false;
210
+ }
211
+ canBeEmpty() {
212
+ return false;
213
+ }
214
+ isCardLike() {
215
+ return true;
216
+ }
217
+ isInline() {
218
+ return false;
219
+ }
220
+ canIndent() {
221
+ return false;
222
+ }
223
+ canInsertTextBefore() {
224
+ return false;
225
+ }
226
+ canInsertTextAfter() {
227
+ return false;
228
+ }
229
+ };
230
+ function $createPlaceholderNode() {
231
+ return $applyNodeReplacement(new PlaceholderNode());
232
+ }
233
+ function $createPlaceholderBlockNode() {
234
+ return $applyNodeReplacement(new PlaceholderBlockNode());
235
+ }
236
+ //#endregion
182
237
  //#region src/plugins/file/node/FileNode.ts
183
238
  init_utils();
184
239
  var FileNode = class FileNode extends DecoratorNode {
@@ -311,61 +366,6 @@ const styles$4 = createStaticStyles(({ css, cssVar }) => ({ file: css`
311
366
  }
312
367
  ` }));
313
368
  //#endregion
314
- //#region src/plugins/hr/node/HorizontalRuleNode.ts
315
- init_utils();
316
- var HorizontalRuleNode = class HorizontalRuleNode extends DecoratorNode {
317
- static getType() {
318
- return "horizontalrule";
319
- }
320
- static clone(node) {
321
- return new HorizontalRuleNode(node.__key);
322
- }
323
- static importJSON(serializedNode) {
324
- return $createHorizontalRuleNode().updateFromJSON(serializedNode);
325
- }
326
- static importDOM() {
327
- return { hr: () => ({
328
- conversion: $convertHorizontalRuleElement,
329
- priority: 0
330
- }) };
331
- }
332
- exportDOM() {
333
- return { element: document.createElement("hr") };
334
- }
335
- createDOM(config) {
336
- const element = document.createElement("div");
337
- addClassNamesToElement(element, config.theme.hr);
338
- return element;
339
- }
340
- getTextContent() {
341
- return "\n";
342
- }
343
- isInline() {
344
- return false;
345
- }
346
- updateDOM() {
347
- return false;
348
- }
349
- decorate(editor) {
350
- const decorator = getKernelFromEditor(editor)?.getDecorator("horizontalrule");
351
- if (!decorator) return null;
352
- if (typeof decorator === "function") return decorator(this, editor);
353
- return {
354
- queryDOM: decorator.queryDOM,
355
- render: decorator.render(this, editor)
356
- };
357
- }
358
- };
359
- function $createHorizontalRuleNode() {
360
- return $applyNodeReplacement(new HorizontalRuleNode());
361
- }
362
- function $convertHorizontalRuleElement() {
363
- return { node: $createHorizontalRuleNode() };
364
- }
365
- function $isHorizontalRuleNode(node) {
366
- return node.getType() === HorizontalRuleNode.getType();
367
- }
368
- //#endregion
369
369
  //#region src/plugins/image/node/basie-image-node.ts
370
370
  var BaseImageNode = class BaseImageNode extends DecoratorNode {
371
371
  static clone(node) {
@@ -996,4 +996,4 @@ const styles = createStaticStyles(({ css, cssVar }) => css`
996
996
  }
997
997
  `);
998
998
  //#endregion
999
- export { PlaceholderNode as S, $isFileNode as _, styles$3 as a, DiffNode as b, ImageNode as c, BlockImageNode as d, $createHorizontalRuleNode as f, $createFileNode as g, styles$4 as h, imageBroken as i, $createBlockImageNode as l, HorizontalRuleNode as m, styles$1 as n, $createImageNode as o, $isHorizontalRuleNode as p, styles$2 as r, $isImageNode as s, styles as t, $isBlockImageNode as u, FileNode as v, PlaceholderBlockNode as x, $createDiffNode as y };
999
+ export { DiffNode as S, PlaceholderNode as _, styles$3 as a, HorizontalRuleNode as b, ImageNode as c, BlockImageNode as d, styles$4 as f, PlaceholderBlockNode as g, FileNode as h, imageBroken as i, $createBlockImageNode as l, $isFileNode as m, styles$1 as n, $createImageNode as o, $createFileNode as p, styles$2 as r, $isImageNode as s, styles as t, $isBlockImageNode as u, $createHorizontalRuleNode as v, $createDiffNode as x, $isHorizontalRuleNode as y };
@@ -1,3 +1,4 @@
1
+ import { createHeadlessEditor } from "@lexical/headless";
1
2
  import { createEmptyHistoryState } from "@lexical/history";
2
3
  import { $createTableSelection, $isTableCellNode, $isTableNode, $isTableSelection } from "@lexical/table";
3
4
  import { get, merge, template, templateSettings } from "es-toolkit/compat";
@@ -990,6 +991,7 @@ var init_kernel = __esmMin((() => {
990
991
  this.hotReloadMode = false;
991
992
  this.logger = createDebugLogger("kernel");
992
993
  this.historyState = createEmptyHistoryState();
994
+ this.headlessEditor = false;
993
995
  this._commands = /* @__PURE__ */ new Map();
994
996
  this._commandsClean = /* @__PURE__ */ new Map();
995
997
  this.dataTypeMap = /* @__PURE__ */ new Map();
@@ -1042,7 +1044,11 @@ var init_kernel = __esmMin((() => {
1042
1044
  destroy() {
1043
1045
  unregisterEditorKernel(this.themes[EDITOR_THEME_KEY]);
1044
1046
  this.logger.info(`🗑️ Destroying editor with ${this.pluginsInstances.length} plugins`);
1045
- this.editor?.setEditorState(createEmptyEditorState());
1047
+ try {
1048
+ this.editor?.setEditorState(createEmptyEditorState());
1049
+ } catch (error) {
1050
+ this.logger.warn("Failed to reset editor state during destroy:", error);
1051
+ }
1046
1052
  this.dataTypeMap.clear();
1047
1053
  this.pluginsInstances.forEach((plugin) => {
1048
1054
  if (plugin.destroy) plugin.destroy();
@@ -1051,13 +1057,16 @@ var init_kernel = __esmMin((() => {
1051
1057
  this.serviceMap.clear();
1052
1058
  this.decorators = {};
1053
1059
  this.themes = {};
1060
+ this.headlessEditor = false;
1054
1061
  this.logger.info("✅ Editor destroyed");
1055
1062
  }
1056
1063
  getRootElement() {
1064
+ if (this.headlessEditor) return null;
1057
1065
  return this.editor?.getRootElement() || null;
1058
1066
  }
1059
1067
  setRootElement(dom, editable = true) {
1060
1068
  if (this.editor) {
1069
+ if (this.headlessEditor) throw new Error("Headless editor cannot be attached to a root element.");
1061
1070
  this.logger.warn("[Editor] Editor is already initialized, updating root element only");
1062
1071
  this.editor.setRootElement(dom);
1063
1072
  return this.editor;
@@ -1082,6 +1091,7 @@ var init_kernel = __esmMin((() => {
1082
1091
  },
1083
1092
  theme: this.themes
1084
1093
  });
1094
+ this.headlessEditor = false;
1085
1095
  this.editor.setRootElement(dom);
1086
1096
  registerEvent(editor, dom);
1087
1097
  this.pluginsInstances.forEach((plugin) => {
@@ -1120,6 +1130,7 @@ var init_kernel = __esmMin((() => {
1120
1130
  },
1121
1131
  theme: this.themes
1122
1132
  });
1133
+ this.headlessEditor = false;
1123
1134
  this.pluginsInstances.forEach((plugin) => {
1124
1135
  plugin.onInit?.(editor);
1125
1136
  });
@@ -1127,6 +1138,34 @@ var init_kernel = __esmMin((() => {
1127
1138
  this.emit("initialized", editor);
1128
1139
  return editor || null;
1129
1140
  }
1141
+ initHeadlessEditor() {
1142
+ if (this.editor) return this.editor;
1143
+ if (this.pluginsInstances.length === 0) {
1144
+ this.logger.info(`🔌 Initializing ${this.plugins.length} plugins`);
1145
+ for (const plugin of this.plugins) {
1146
+ const instance = new plugin(this, this.pluginsConfig.get(plugin));
1147
+ this.pluginsInstances.push(instance);
1148
+ }
1149
+ }
1150
+ this.logger.info(`📝 Creating headless editor with ${this.nodes.length} nodes`);
1151
+ const editor = this.editor = createHeadlessEditor({
1152
+ __kernel: this,
1153
+ namespace: "lobehub-headless",
1154
+ nodes: this.nodes,
1155
+ onError: (error) => {
1156
+ this.logger.error("❌ Lexical headless editor error:", error);
1157
+ this.emit("error", error);
1158
+ },
1159
+ theme: this.themes
1160
+ });
1161
+ this.headlessEditor = true;
1162
+ this.pluginsInstances.forEach((plugin) => {
1163
+ plugin.onInit?.(editor);
1164
+ });
1165
+ this.logger.info(`✅ Headless editor ready with ${this.pluginsInstances.length} plugins`);
1166
+ this.emit("initialized", editor);
1167
+ return editor || null;
1168
+ }
1130
1169
  setDocument(type, content, options) {
1131
1170
  const datasource = this.dataTypeMap.get(type);
1132
1171
  if (!datasource) {
@@ -1255,9 +1294,11 @@ var init_kernel = __esmMin((() => {
1255
1294
  });
1256
1295
  }
1257
1296
  focus() {
1297
+ if (this.headlessEditor) return;
1258
1298
  this.editor?.focus();
1259
1299
  }
1260
1300
  blur() {
1301
+ if (this.headlessEditor) return;
1261
1302
  this.editor?.blur();
1262
1303
  }
1263
1304
  getDocument(type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.8.4",
3
+ "version": "4.9.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",
@@ -26,6 +26,10 @@
26
26
  "types": "./es/index.d.ts",
27
27
  "import": "./es/index.js"
28
28
  },
29
+ "./headless": {
30
+ "types": "./es/headless.d.ts",
31
+ "import": "./es/headless.js"
32
+ },
29
33
  "./react": {
30
34
  "types": "./es/react.d.ts",
31
35
  "import": "./es/react.js"