@lobehub/editor 1.22.0 → 1.23.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.
@@ -1,3 +1,4 @@
1
+ import { HistoryState } from '@lexical/history';
1
2
  import EventEmitter from 'eventemitter3';
2
3
  import { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
3
4
  import { HotkeyId } from "../types/hotkey";
@@ -17,8 +18,10 @@ export declare class Kernel extends EventEmitter implements IEditorKernel {
17
18
  private localeMap;
18
19
  private hotReloadMode;
19
20
  private logger;
21
+ private historyState;
20
22
  private editor?;
21
23
  constructor();
24
+ getHistoryState(): HistoryState;
22
25
  private detectDevelopmentMode;
23
26
  /**
24
27
  * Globally enable or disable hot reload mode for all kernel instances
@@ -33,6 +36,7 @@ export declare class Kernel extends EventEmitter implements IEditorKernel {
33
36
  destroy(): void;
34
37
  getRootElement(): HTMLElement | null;
35
38
  setRootElement(dom: HTMLElement): LexicalEditor;
39
+ initNodeEditor(): LexicalEditor;
36
40
  setDocument(type: string, content: any): void;
37
41
  focus(): void;
38
42
  blur(): void;
@@ -19,6 +19,7 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g
19
19
  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; }
20
20
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
21
21
  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); }
22
+ import { createEmptyHistoryState } from '@lexical/history';
22
23
  import EventEmitter from 'eventemitter3';
23
24
  import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, KEY_DOWN_COMMAND, createEditor } from 'lexical';
24
25
  import { get, merge, template, templateSettings } from 'lodash-es';
@@ -48,6 +49,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
48
49
  _defineProperty(_assertThisInitialized(_this), "localeMap", defaultLocale);
49
50
  _defineProperty(_assertThisInitialized(_this), "hotReloadMode", false);
50
51
  _defineProperty(_assertThisInitialized(_this), "logger", createDebugLogger('kernel'));
52
+ _defineProperty(_assertThisInitialized(_this), "historyState", createEmptyHistoryState());
51
53
  _defineProperty(_assertThisInitialized(_this), "editor", void 0);
52
54
  _defineProperty(_assertThisInitialized(_this), "_commands", new Map());
53
55
  _defineProperty(_assertThisInitialized(_this), "_commandsClean", new Map());
@@ -58,6 +60,11 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
58
60
  return _this;
59
61
  }
60
62
  _createClass(Kernel, [{
63
+ key: "getHistoryState",
64
+ value: function getHistoryState() {
65
+ return this.historyState;
66
+ }
67
+ }, {
61
68
  key: "detectDevelopmentMode",
62
69
  value: function detectDevelopmentMode() {
63
70
  var _process$env;
@@ -184,6 +191,50 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
184
191
  this.emit('initialized', editor);
185
192
  return this.editor;
186
193
  }
194
+ }, {
195
+ key: "initNodeEditor",
196
+ value: function initNodeEditor() {
197
+ var _this3 = this;
198
+ if (this.editor) {
199
+ return this.editor;
200
+ }
201
+ // Initialize plugins if not already done
202
+ if (this.pluginsInstances.length === 0) {
203
+ this.logger.info("\uD83D\uDD0C Initializing ".concat(this.plugins.length, " plugins"));
204
+ var _iterator2 = _createForOfIteratorHelper(this.plugins),
205
+ _step2;
206
+ try {
207
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
208
+ var plugin = _step2.value;
209
+ var instance = new plugin(this, plugin.__config);
210
+ this.pluginsInstances.push(instance);
211
+ }
212
+ } catch (err) {
213
+ _iterator2.e(err);
214
+ } finally {
215
+ _iterator2.f();
216
+ }
217
+ }
218
+ this.logger.info("\uD83D\uDCDD Creating editor with ".concat(this.nodes.length, " nodes"));
219
+ var editor = this.editor = createEditor({
220
+ // @ts-expect-error Inject into lexical editor instance
221
+ __kernel: this,
222
+ namespace: 'lobehub',
223
+ nodes: this.nodes,
224
+ onError: function onError(error) {
225
+ _this3.logger.error('❌ Lexical editor error:', error);
226
+ _this3.emit('error', error);
227
+ },
228
+ theme: this.themes
229
+ });
230
+ this.pluginsInstances.forEach(function (plugin) {
231
+ var _plugin$onInit2;
232
+ (_plugin$onInit2 = plugin.onInit) === null || _plugin$onInit2 === void 0 || _plugin$onInit2.call(plugin, editor);
233
+ });
234
+ this.logger.info("\u2705 Editor ready with ".concat(this.pluginsInstances.length, " plugins"));
235
+ this.emit('initialized', editor);
236
+ return editor || null;
237
+ }
187
238
  }, {
188
239
  key: "setDocument",
189
240
  value: function setDocument(type, content) {
@@ -339,18 +390,18 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
339
390
  // Clean up decorators registered by the old plugin instance
340
391
  if (oldInstance instanceof KernelPlugin) {
341
392
  var decoratorNames = oldInstance.getRegisteredDecorators();
342
- var _iterator2 = _createForOfIteratorHelper(decoratorNames),
343
- _step2;
393
+ var _iterator3 = _createForOfIteratorHelper(decoratorNames),
394
+ _step3;
344
395
  try {
345
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
346
- var decoratorName = _step2.value;
396
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
397
+ var decoratorName = _step3.value;
347
398
  this.unregisterDecorator(decoratorName);
348
399
  this.logger.debug("\uD83E\uDDE8 Cleanup: decorator \"".concat(decoratorName, "\""));
349
400
  }
350
401
  } catch (err) {
351
- _iterator2.e(err);
402
+ _iterator3.e(err);
352
403
  } finally {
353
- _iterator2.f();
404
+ _iterator3.f();
354
405
  }
355
406
  }
356
407
  if (oldInstance.destroy) {
@@ -381,11 +432,11 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
381
432
  }, {
382
433
  key: "registerPlugins",
383
434
  value: function registerPlugins(plugins) {
384
- var _iterator3 = _createForOfIteratorHelper(plugins),
385
- _step3;
435
+ var _iterator4 = _createForOfIteratorHelper(plugins),
436
+ _step4;
386
437
  try {
387
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
388
- var plugin = _step3.value;
438
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
439
+ var plugin = _step4.value;
389
440
  if (Array.isArray(plugin)) {
390
441
  this.registerPlugin(plugin[0], plugin[1]);
391
442
  } else {
@@ -393,9 +444,9 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
393
444
  }
394
445
  }
395
446
  } catch (err) {
396
- _iterator3.e(err);
447
+ _iterator4.e(err);
397
448
  } finally {
398
- _iterator3.f();
449
+ _iterator4.f();
399
450
  }
400
451
  this.logger.debug("\uD83D\uDD0C Registered ".concat(plugins.length, " plugins"));
401
452
  return this;
@@ -532,12 +583,12 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
532
583
  }, {
533
584
  key: "isEmpty",
534
585
  get: function get() {
535
- var _this3 = this;
586
+ var _this4 = this;
536
587
  if (!this.editor) {
537
588
  return true;
538
589
  }
539
590
  return this.editor.getEditorState().read(function () {
540
- return $isRootTextContentEmpty(_this3.editor.isComposing(), true);
591
+ return $isRootTextContentEmpty(_this4.editor.isComposing(), true);
541
592
  });
542
593
  }
543
594
  }, {
@@ -580,7 +631,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
580
631
  }, {
581
632
  key: "registerHighCommand",
582
633
  value: function registerHighCommand(command, listener, priority) {
583
- var _this4 = this;
634
+ var _this5 = this;
584
635
  var lexicalEditor = this.editor;
585
636
  if (!lexicalEditor) {
586
637
  throw new Error('Editor is not initialized.');
@@ -591,22 +642,22 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
591
642
  commandsMap.set(command, [new Set(), new Set(), new Set(), new Set(), new Set()]);
592
643
  this._commandsClean.set(command, lexicalEditor.registerCommand(command, function (payload) {
593
644
  for (var i = 4; i >= 0; i--) {
594
- var listenerInPriorityOrder = _this4._commands.get(command);
645
+ var listenerInPriorityOrder = _this5._commands.get(command);
595
646
  if (listenerInPriorityOrder !== undefined) {
596
647
  var listenersSet = listenerInPriorityOrder[i];
597
- var _iterator4 = _createForOfIteratorHelper(listenersSet),
598
- _step4;
648
+ var _iterator5 = _createForOfIteratorHelper(listenersSet),
649
+ _step5;
599
650
  try {
600
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
601
- var _listener = _step4.value;
651
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
652
+ var _listener = _step5.value;
602
653
  if (_listener(payload, lexicalEditor)) {
603
654
  return true;
604
655
  }
605
656
  }
606
657
  } catch (err) {
607
- _iterator4.e(err);
658
+ _iterator5.e(err);
608
659
  } finally {
609
- _iterator4.f();
660
+ _iterator5.f();
610
661
  }
611
662
  }
612
663
  }
@@ -628,9 +679,9 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
628
679
  if (listenersInPriorityOrder.every(function (listenersSet) {
629
680
  return listenersSet.size === 0;
630
681
  })) {
631
- var _this4$_commandsClean;
682
+ var _this5$_commandsClean;
632
683
  commandsMap.delete(command);
633
- (_this4$_commandsClean = _this4._commandsClean.get(command)) === null || _this4$_commandsClean === void 0 || _this4$_commandsClean();
684
+ (_this5$_commandsClean = _this5._commandsClean.get(command)) === null || _this5$_commandsClean === void 0 || _this5$_commandsClean();
634
685
  }
635
686
  };
636
687
  }
@@ -22,8 +22,9 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
22
22
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
23
23
  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); }
24
24
  import { registerDragonSupport } from '@lexical/dragon';
25
- import { createEmptyHistoryState, registerHistory } from '@lexical/history';
25
+ import { registerHistory } from '@lexical/history';
26
26
  import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode, HeadingNode, QuoteNode, registerRichText } from '@lexical/rich-text';
27
+ import { CAN_USE_DOM } from '@lexical/utils';
27
28
  import { $createLineBreakNode, $createParagraphNode, $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_HIGH, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND } from 'lexical';
28
29
  import { KernelPlugin } from "../../../editor-kernel/plugin";
29
30
  import { IMarkdownShortCutService } from "../../markdown/service/shortcut";
@@ -322,7 +323,7 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
322
323
  key: "onInit",
323
324
  value: function onInit(editor) {
324
325
  var _this$config2;
325
- this.registerClears(registerRichText(editor), registerDragonSupport(editor), registerHistory(editor, createEmptyHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel, {
326
+ this.registerClears(registerRichText(editor), CAN_USE_DOM ? registerDragonSupport(editor) : function () {}, registerHistory(editor, this.kernel.getHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel, {
326
327
  enableHotkey: (_this$config2 = this.config) === null || _this$config2 === void 0 ? void 0 : _this$config2.enableHotkey
327
328
  }), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor), registerLastElement(editor),
328
329
  // Convert soft line breaks (Shift+Enter) to hard line breaks (paragraph breaks)
@@ -1,6 +1,7 @@
1
1
  import { type CSSProperties, type ReactNode } from 'react';
2
2
  export interface PlaceholderProps {
3
3
  children: ReactNode;
4
+ lineEmptyPlaceholder?: string;
4
5
  style?: CSSProperties;
5
6
  }
6
7
  declare const Placeholder: import("react").NamedExoticComponent<PlaceholderProps>;
@@ -5,7 +5,8 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
5
5
  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; } }
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
7
  import { mergeRegister } from '@lexical/utils';
8
- import { memo, useState } from 'react';
8
+ import { $getNodeByKey, $getSelection, $isBlockElementNode, $isRangeSelection } from 'lexical';
9
+ import { memo, useRef, useState } from 'react';
9
10
  import { useLexicalEditor } from "../../../../editor-kernel/react";
10
11
  import { $canShowPlaceholderCurry } from "../../utils";
11
12
  import { useStyles } from "./style";
@@ -14,9 +15,17 @@ function canShowPlaceholderFromCurrentEditorState(editor) {
14
15
  var currentCanShowPlaceholder = editor.getEditorState().read($canShowPlaceholderCurry(editor.isComposing()));
15
16
  return currentCanShowPlaceholder;
16
17
  }
18
+
19
+ // 判断 DOM 是否只有一个 br 子元素
20
+ function hasOnlyBrChild(element) {
21
+ var children = element.childNodes;
22
+ return children.length === 1 && children[0].nodeType === Node.ELEMENT_NODE && children[0].tagName.toLowerCase() === 'br';
23
+ }
17
24
  var Placeholder = /*#__PURE__*/memo(function (_ref) {
18
25
  var children = _ref.children,
19
- style = _ref.style;
26
+ style = _ref.style,
27
+ lineEmptyPlaceholder = _ref.lineEmptyPlaceholder;
28
+ var currentPlaceHolderRef = useRef(null);
20
29
  var _useState = useState(function () {
21
30
  return false;
22
31
  }),
@@ -32,10 +41,38 @@ var Placeholder = /*#__PURE__*/memo(function (_ref) {
32
41
  function resetCanShowPlaceholder() {
33
42
  var currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
34
43
  setCanShowPlaceholder(currentCanShowPlaceholder);
44
+ return currentCanShowPlaceholder;
35
45
  }
36
46
  resetCanShowPlaceholder();
37
47
  return mergeRegister(editor.registerUpdateListener(function () {
38
- resetCanShowPlaceholder();
48
+ var show = resetCanShowPlaceholder();
49
+ if (!show && lineEmptyPlaceholder) {
50
+ editor.read(function () {
51
+ var sel = $getSelection();
52
+ if ($isRangeSelection(sel) && sel.isCollapsed()) {
53
+ var anchor = sel.anchor;
54
+ var node = $getNodeByKey(anchor.key);
55
+ while (node && !$isBlockElementNode(node)) {
56
+ node = node.getParent();
57
+ }
58
+ if (node) {
59
+ var dom = editor.getElementByKey(node.getKey());
60
+ if (dom && hasOnlyBrChild(dom)) {
61
+ if (currentPlaceHolderRef.current && currentPlaceHolderRef.current !== dom) {
62
+ currentPlaceHolderRef.current.dataset.placeholder = '';
63
+ }
64
+ currentPlaceHolderRef.current = dom;
65
+ dom.dataset.placeholder = lineEmptyPlaceholder;
66
+ return;
67
+ }
68
+ }
69
+ if (currentPlaceHolderRef.current) {
70
+ currentPlaceHolderRef.current.dataset.placeholder = '';
71
+ currentPlaceHolderRef.current = null;
72
+ }
73
+ }
74
+ });
75
+ }
39
76
  }), editor.registerEditableListener(function () {
40
77
  resetCanShowPlaceholder();
41
78
  }));
@@ -82,7 +82,8 @@ var ReactPlainText = /*#__PURE__*/memo(function (_ref) {
82
82
  _Children$only$props = _Children$only.props,
83
83
  type = _Children$only$props.type,
84
84
  content = _Children$only$props.content,
85
- placeholder = _Children$only$props.placeholder;
85
+ placeholder = _Children$only$props.placeholder,
86
+ lineEmptyPlaceholder = _Children$only$props.lineEmptyPlaceholder;
86
87
  useLayoutEffect(function () {
87
88
  editor.registerPlugin(MarkdownPlugin, {
88
89
  enablePasteMarkdown: enablePasteMarkdown
@@ -202,6 +203,7 @@ var ReactPlainText = /*#__PURE__*/memo(function (_ref) {
202
203
  outline: 'none'
203
204
  }
204
205
  }), /*#__PURE__*/_jsx(Placeholder, {
206
+ lineEmptyPlaceholder: lineEmptyPlaceholder,
205
207
  style: style,
206
208
  children: placeholder
207
209
  }), decorators]
@@ -28,7 +28,7 @@ export var useStyles = createStyles(function (_ref2, _ref3) {
28
28
  marginMultiple = _ref3$marginMultiple === void 0 ? 2 : _ref3$marginMultiple,
29
29
  _ref3$lineHeight = _ref3.lineHeight,
30
30
  lineHeight = _ref3$lineHeight === void 0 ? 1.8 : _ref3$lineHeight;
31
- var __root = css(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n --lobe-markdown-font-size: ", "px;\n --lobe-markdown-header-multiple: ", ";\n --lobe-markdown-margin-multiple: ", ";\n --lobe-markdown-line-height: ", ";\n --lobe-markdown-border-radius: ", ";\n --lobe-markdown-border-color: ", ";\n\n position: relative;\n\n display: flex;\n flex-direction: column;\n\n width: 100%;\n max-width: 100%;\n height: 100%;\n\n font-size: var(--lobe-markdown-font-size);\n line-height: var(--lobe-markdown-line-height);\n word-break: break-word;\n\n @keyframes cursor-blink {\n to {\n visibility: hidden;\n }\n }\n\n [data-lexical-cursor='true'] {\n pointer-events: none;\n position: absolute;\n display: block;\n\n &::after {\n content: '';\n\n position: absolute;\n inset-block-start: -2px;\n\n display: block;\n\n width: 20px;\n border-block-start: 1px solid ", ";\n\n animation: cursor-blink 1.1s steps(2, start) infinite;\n }\n }\n "])), fontSize, headerMultiple, marginMultiple, lineHeight, token.borderRadiusLG, token.colorFillQuaternary, token.colorText);
31
+ var __root = css(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n --lobe-markdown-font-size: ", "px;\n --lobe-markdown-header-multiple: ", ";\n --lobe-markdown-margin-multiple: ", ";\n --lobe-markdown-line-height: ", ";\n --lobe-markdown-border-radius: ", ";\n --lobe-markdown-border-color: ", ";\n\n position: relative;\n\n display: flex;\n flex-direction: column;\n\n width: 100%;\n max-width: 100%;\n height: 100%;\n\n font-size: var(--lobe-markdown-font-size);\n line-height: var(--lobe-markdown-line-height);\n word-break: break-word;\n\n @keyframes cursor-blink {\n to {\n visibility: hidden;\n }\n }\n\n [data-placeholder] {\n position: relative;\n }\n\n [data-placeholder]::after {\n pointer-events: none;\n content: attr(data-placeholder);\n user-select: none;\n user-select: none;\n user-select: none;\n\n position: absolute;\n inset-block-start: 50%;\n transform: translateY(-50%);\n\n padding-inline-start: 2px;\n\n color: ", ";\n white-space: nowrap;\n }\n\n [data-lexical-cursor='true'] {\n pointer-events: none;\n position: absolute;\n display: block;\n\n &::after {\n content: '';\n\n position: absolute;\n inset-block-start: -2px;\n\n display: block;\n\n width: 20px;\n border-block-start: 1px solid ", ";\n\n animation: cursor-blink 1.1s steps(2, start) infinite;\n }\n }\n "])), fontSize, headerMultiple, marginMultiple, lineHeight, token.borderRadiusLG, token.colorFillQuaternary, token.colorTextDescription, token.colorText);
32
32
  var header = css(_templateObject12 || (_templateObject12 = _taggedTemplateLiteral(["\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-block: max(\n calc(var(--lobe-markdown-header-multiple) * var(--lobe-markdown-margin-multiple) * 0.4em),\n var(--lobe-markdown-font-size)\n );\n font-weight: bold;\n line-height: 1.25;\n }\n\n h1 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 1.5 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h2 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + var(--lobe-markdown-header-multiple))\n );\n }\n\n h3 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 0.5 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h4 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 0.25 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h5,\n h6 {\n font-size: calc(var(--lobe-markdown-font-size) * 1);\n }\n "])));
33
33
  var p = css(_templateObject13 || (_templateObject13 = _taggedTemplateLiteral(["\n p {\n margin-block: 4px;\n line-height: var(--lobe-markdown-line-height);\n letter-spacing: 0.02em;\n\n &:not(:first-child) {\n margin-block-start: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n\n &:not(:last-child) {\n margin-block-end: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n }\n "])));
34
34
  var blockquote = css(_templateObject14 || (_templateObject14 = _taggedTemplateLiteral(["\n .editor_quote {\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n margin-inline: 0;\n padding-block: 0;\n padding-inline: 1em;\n border-inline-start: solid 4px ", ";\n\n color: ", ";\n }\n "])), token.colorBorder, token.colorTextSecondary);
@@ -3,6 +3,7 @@ import type { CommonPluginOptions } from "..";
3
3
  import type { IEditor } from "../../../types";
4
4
  export interface ReactEditorContentProps {
5
5
  content: any;
6
+ lineEmptyPlaceholder?: string;
6
7
  placeholder?: ReactNode;
7
8
  type: string;
8
9
  }
@@ -1,6 +1,8 @@
1
+ import { HistoryState, HistoryStateEntry } from '@lexical/history';
1
2
  import { LexicalEditor } from 'lexical';
2
3
  import { MarkdownShortCutService } from '../service/shortcut';
3
4
  export declare const INSERT_MARKDOWN_COMMAND: import("lexical").LexicalCommand<{
5
+ historyState: HistoryStateEntry | null;
4
6
  markdown: string;
5
7
  }>;
6
- export declare function registerMarkdownCommand(editor: LexicalEditor, service: MarkdownShortCutService): () => void;
8
+ export declare function registerMarkdownCommand(editor: LexicalEditor, service: MarkdownShortCutService, history: HistoryState): () => void;
@@ -1,25 +1,43 @@
1
- import { $getSelection, COMMAND_PRIORITY_HIGH, createCommand } from 'lexical';
1
+ import { $getSelection, CAN_UNDO_COMMAND, COMMAND_PRIORITY_HIGH, HISTORIC_TAG, createCommand } from 'lexical';
2
2
  import { createDebugLogger } from "../../../utils/debug";
3
3
  import { parseMarkdownToLexical } from "../data-source/markdown/parse";
4
4
  import { $generateNodesFromSerializedNodes, $insertGeneratedNodes } from "../utils";
5
5
  var logger = createDebugLogger('plugin', 'markdown');
6
6
  export var INSERT_MARKDOWN_COMMAND = createCommand('INSERT_MARKDOWN_COMMAND');
7
- export function registerMarkdownCommand(editor, service) {
7
+ function undoToEntry(editor, historyState, entry) {
8
+ var undoStack = historyState.undoStack;
9
+ var current = historyState.current;
10
+ if (current) {
11
+ undoStack.push(current);
12
+ editor.dispatchCommand(CAN_UNDO_COMMAND, false);
13
+ }
14
+ historyState.current = entry || null;
15
+ if (entry) {
16
+ editor.setEditorState(entry.editorState, {
17
+ tag: HISTORIC_TAG
18
+ });
19
+ }
20
+ return editor.getEditorState();
21
+ }
22
+ export function registerMarkdownCommand(editor, service, history) {
8
23
  return editor.registerCommand(INSERT_MARKDOWN_COMMAND, function (payload) {
9
24
  var markdown = payload.markdown;
10
25
  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
- }
26
+ undoToEntry(editor, history, payload.historyState);
27
+ queueMicrotask(function () {
28
+ editor.update(function () {
29
+ try {
30
+ // Use the markdown data source to parse the content
31
+ var root = parseMarkdownToLexical(markdown, service.markdownReaders);
32
+ var selection = $getSelection();
33
+ var nodes = $generateNodesFromSerializedNodes(root.children);
34
+ logger.debug('INSERT_MARKDOWN_COMMAND nodes:', nodes);
35
+ $insertGeneratedNodes(editor, nodes, selection);
36
+ return true;
37
+ } catch (error) {
38
+ logger.error('Failed to handle markdown paste:', error);
39
+ }
40
+ });
23
41
  });
24
42
  return false;
25
43
  }, COMMAND_PRIORITY_HIGH // Priority
@@ -144,9 +144,11 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
144
144
  if (hasMarkdownContent) {
145
145
  // Markdown detected - show confirmation dialog
146
146
  _this2.logger.debug('markdown patterns detected:', _this2.getMarkdownPatterns(text));
147
+ var historyState = _this2.kernel.getHistoryState().current;
147
148
  setTimeout(function () {
148
149
  _this2.kernel.emit('markdownParse', {
149
150
  cacheState: editor.getEditorState(),
151
+ historyState: historyState,
150
152
  markdown: text
151
153
  });
152
154
  }, 10);
@@ -156,7 +158,7 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
156
158
  }
157
159
  return false;
158
160
  }, COMMAND_PRIORITY_CRITICAL));
159
- this.register(registerMarkdownCommand(editor, this.service));
161
+ this.register(registerMarkdownCommand(editor, this.service, this.kernel.getHistoryState()));
160
162
  }
161
163
 
162
164
  /**
@@ -8,7 +8,6 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
8
8
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
9
9
  import { Button } from '@lobehub/ui';
10
10
  import { Space, notification } from 'antd';
11
- import { UNDO_COMMAND } from 'lexical';
12
11
  import { useLayoutEffect } from 'react';
13
12
  import { useLexicalComposerContext } from "../../../editor-kernel/react";
14
13
  import { useTranslation } from "../../../editor-kernel/react/useTranslation";
@@ -28,7 +27,8 @@ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
28
27
  useLayoutEffect(function () {
29
28
  editor.registerPlugin(MarkdownPlugin);
30
29
  var handleEvent = function handleEvent(_ref) {
31
- var markdown = _ref.markdown;
30
+ var markdown = _ref.markdown,
31
+ historyState = _ref.historyState;
32
32
  var key = "open".concat(Date.now());
33
33
  var actions = /*#__PURE__*/_jsxs(Space, {
34
34
  children: [/*#__PURE__*/_jsx(Button, {
@@ -39,8 +39,8 @@ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
39
39
  children: t('markdown.cancel')
40
40
  }), /*#__PURE__*/_jsx(Button, {
41
41
  onClick: function onClick() {
42
- editor.dispatchCommand(UNDO_COMMAND, undefined);
43
42
  editor.dispatchCommand(INSERT_MARKDOWN_COMMAND, {
43
+ historyState: historyState,
44
44
  markdown: markdown
45
45
  });
46
46
  api.destroy();
@@ -32,6 +32,7 @@ var Editor = /*#__PURE__*/memo(function (_ref) {
32
32
  onInit = _ref.onInit,
33
33
  onChange = _ref.onChange,
34
34
  placeholder = _ref.placeholder,
35
+ lineEmptyPlaceholder = _ref.lineEmptyPlaceholder,
35
36
  _ref$plugins = _ref.plugins,
36
37
  plugins = _ref$plugins === void 0 ? [] : _ref$plugins,
37
38
  _ref$slashOption = _ref.slashOption,
@@ -113,6 +114,7 @@ var Editor = /*#__PURE__*/memo(function (_ref) {
113
114
  variant: variant,
114
115
  children: /*#__PURE__*/_jsx(ReactEditorContent, {
115
116
  content: content,
117
+ lineEmptyPlaceholder: lineEmptyPlaceholder,
116
118
  placeholder: placeholder,
117
119
  type: type
118
120
  })
@@ -1,8 +1,9 @@
1
+ import type { HistoryState, HistoryStateEntry } from '@lexical/history';
1
2
  import type { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, EditorState, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
2
3
  import type DataSource from "../editor-kernel/data-source";
3
- import { HotkeyId } from "./hotkey";
4
- import { HotkeyOptions, HotkeysEvent } from "../utils/hotkey/registerHotkey";
5
- import { ILocaleKeys } from './locale';
4
+ import type { HotkeyId } from "./hotkey";
5
+ import type { HotkeyOptions, HotkeysEvent } from "../utils/hotkey/registerHotkey";
6
+ import type { ILocaleKeys } from './locale';
6
7
  export type Commands = Map<LexicalCommand<unknown>, Array<Set<CommandListener<unknown>>>>;
7
8
  export type CommandsClean = Map<LexicalCommand<unknown>, () => void>;
8
9
  /**
@@ -28,6 +29,7 @@ export interface IKernelEventMap {
28
29
  */
29
30
  markdownParse: (params: {
30
31
  cacheState: EditorState;
32
+ historyState: HistoryStateEntry | null;
31
33
  markdown: string;
32
34
  }) => void;
33
35
  }
@@ -78,6 +80,10 @@ export interface IEditor {
78
80
  * Get editor theme
79
81
  */
80
82
  getTheme(): Record<string, string | Record<string, string>>;
83
+ /**
84
+ * Get node editor instance
85
+ */
86
+ initNodeEditor(): LexicalEditor | null;
81
87
  /**
82
88
  * Check if editor content is empty
83
89
  * @returns true if editor content is empty, false otherwise
@@ -188,6 +194,10 @@ export interface IEditorKernel extends IEditor {
188
194
  * @param name
189
195
  */
190
196
  getDecorator(name: string): ((_node: DecoratorNode<any>, _editor: LexicalEditor) => any) | undefined;
197
+ /**
198
+ * Get editor history state
199
+ */
200
+ getHistoryState(): HistoryState;
191
201
  /**
192
202
  * Get all registered decorator names
193
203
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "1.22.0",
3
+ "version": "1.23.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",
@@ -27,38 +27,38 @@
27
27
  "react.js"
28
28
  ],
29
29
  "dependencies": {
30
- "@floating-ui/dom": "^1.7.3",
31
- "@floating-ui/react": "^0.27.15",
32
- "@lexical/code": "^0.34.0",
33
- "@lexical/code-shiki": "^0.34.0",
34
- "@lexical/dragon": "^0.34.0",
35
- "@lexical/history": "^0.34.0",
36
- "@lexical/link": "^0.34.0",
37
- "@lexical/list": "^0.34.0",
38
- "@lexical/rich-text": "^0.34.0",
39
- "@lexical/selection": "^0.34.0",
40
- "@lexical/table": "^0.34.0",
41
- "@lexical/utils": "^0.34.0",
42
- "@shikijs/core": "^3.9.2",
43
- "@shikijs/engine-javascript": "^3.9.2",
44
- "ahooks": "^3.9.3",
30
+ "@floating-ui/dom": "^1.7.4",
31
+ "@floating-ui/react": "^0.27.16",
32
+ "@lexical/code": "^0.38.2",
33
+ "@lexical/code-shiki": "^0.38.2",
34
+ "@lexical/dragon": "^0.38.2",
35
+ "@lexical/history": "^0.38.2",
36
+ "@lexical/link": "^0.38.2",
37
+ "@lexical/list": "^0.38.2",
38
+ "@lexical/rich-text": "^0.38.2",
39
+ "@lexical/selection": "^0.38.2",
40
+ "@lexical/table": "^0.38.2",
41
+ "@lexical/utils": "^0.38.2",
42
+ "@shikijs/core": "^3.15.0",
43
+ "@shikijs/engine-javascript": "^3.15.0",
44
+ "ahooks": "^3.9.6",
45
45
  "antd-style": "^3.7.1",
46
- "debug": "^4.4.1",
46
+ "debug": "^4.4.3",
47
47
  "eventemitter3": "^5.0.1",
48
- "framer-motion": "^12.23.12",
48
+ "framer-motion": "^12.23.24",
49
49
  "fuse.js": "^7.1.0",
50
- "katex": "^0.16.22",
51
- "lexical": "^0.34.0",
50
+ "katex": "^0.16.25",
51
+ "lexical": "^0.38.2",
52
52
  "lodash-es": "^4.17.21",
53
- "lucide-react": "^0.536.0",
53
+ "lucide-react": "^0.553.0",
54
54
  "polished": "^4.3.1",
55
55
  "re-resizable": "^6.11.2",
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
+ "remark-cjk-friendly": "^1.2.3",
60
60
  "remark-supersub": "^1.0.0",
61
- "shiki": "^3.9.2",
61
+ "shiki": "^3.15.0",
62
62
  "ts-key-enum": "^3.0.13",
63
63
  "use-merge-value": "^1.2.0"
64
64
  },