@lobehub/editor 3.13.2 → 3.14.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.
@@ -271,6 +271,9 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
271
271
  this.logger.error('❌ Editor not initialized');
272
272
  throw new Error("Editor is not initialized.");
273
273
  }
274
+ this.historyState.redoStack = [];
275
+ this.historyState.undoStack = [];
276
+ this.historyState.current = null;
274
277
  datasource.read(this.editor, content, options);
275
278
  this.emit('documentChange', type, content);
276
279
  this.logger.debug("\uD83D\uDCE5 Set ".concat(type, " document"));
@@ -8,6 +8,6 @@
8
8
  import type { JSX } from 'react';
9
9
  export type LexicalErrorBoundaryProps = {
10
10
  children: JSX.Element;
11
- onError: (error: Error) => void;
11
+ onError: (error: unknown) => void;
12
12
  };
13
13
  export declare function LexicalErrorBoundary({ children, onError, }: LexicalErrorBoundaryProps): JSX.Element;
@@ -2,7 +2,7 @@ import { type ComponentClass, type FC, type JSX } from 'react';
2
2
  import { IEditor } from "../../types";
3
3
  type ErrorBoundaryProps = {
4
4
  children: JSX.Element;
5
- onError: (error: Error) => void;
5
+ onError: (error: unknown) => void;
6
6
  };
7
7
  export type ErrorBoundaryType = ComponentClass<ErrorBoundaryProps> | FC<ErrorBoundaryProps>;
8
8
  export declare function useDecorators(editor: IEditor, ErrorBoundary: ErrorBoundaryType): Array<JSX.Element>;
@@ -2,7 +2,7 @@ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol
2
2
  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); }
3
3
  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; }
4
4
  import { mergeRegister } from '@lexical/utils';
5
- import { $getNodeByKey } from 'lexical';
5
+ import { $getNodeByKey, HISTORY_MERGE_TAG } from 'lexical';
6
6
  import { $createCursorNode } from "../../common";
7
7
  import { HotkeyEnum } from "../../../types/hotkey";
8
8
  import { INSERT_CODEINLINE_COMMAND } from "../command";
@@ -45,6 +45,8 @@ export function registerCodeInline(editor, kernel, options) {
45
45
  node.insertBefore($createCursorNode());
46
46
  }
47
47
  });
48
+ }, {
49
+ tag: HISTORY_MERGE_TAG
48
50
  });
49
51
  }
50
52
  }), kernel.registerHotkey(HotkeyEnum.CodeInline, function () {
@@ -19,7 +19,7 @@ function _assertThisInitialized(self) { if (self === void 0) { throw new Referen
19
19
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
20
20
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
21
21
  import { mergeRegister } from '@lexical/utils';
22
- import { $createTextNode, $getNodeByKey, $getSelection, $isDecoratorNode, $isRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, DecoratorNode, ElementNode, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_BACKSPACE_COMMAND, TextNode } from 'lexical';
22
+ import { $createTextNode, $getNodeByKey, $getSelection, $isDecoratorNode, $isRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, DecoratorNode, ElementNode, HISTORY_MERGE_TAG, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_BACKSPACE_COMMAND, TextNode } from 'lexical';
23
23
  import { createDebugLogger } from "../../../utils/debug";
24
24
  var logger = createDebugLogger('common', 'cursor');
25
25
  export var CardLikeElementNode = /*#__PURE__*/function (_ElementNode) {
@@ -120,6 +120,8 @@ export function registerCursorNode(editor) {
120
120
  needAddCursor.forEach(function (node) {
121
121
  node.insertAfter($createCursorNode());
122
122
  });
123
+ }, {
124
+ tag: HISTORY_MERGE_TAG
123
125
  });
124
126
  }
125
127
  return false;
@@ -164,6 +166,8 @@ export function registerCursorNode(editor) {
164
166
  needRemove.forEach(function (node) {
165
167
  node.remove();
166
168
  });
169
+ }, {
170
+ tag: HISTORY_MERGE_TAG
167
171
  });
168
172
  }
169
173
  return false;
@@ -189,6 +193,8 @@ export function registerCursorNode(editor) {
189
193
  node.insertAfter(textNode);
190
194
  textNode.selectEnd();
191
195
  }
196
+ }, {
197
+ tag: HISTORY_MERGE_TAG
192
198
  });
193
199
  }
194
200
  return false;
@@ -152,15 +152,6 @@ var ReactPlainText = /*#__PURE__*/memo(function (_ref) {
152
152
  }
153
153
  });
154
154
  }, [editor, type, content, onChange, onTextChange, isInitialized]);
155
- useEffect(function () {
156
- var handleDocumentChange = function handleDocumentChange() {
157
- onTextChange === null || onTextChange === void 0 || onTextChange(editor);
158
- };
159
- editor.on('documentChange', handleDocumentChange);
160
- return function () {
161
- editor.off('documentChange', handleDocumentChange);
162
- };
163
- }, [editor, onTextChange]);
164
155
  useEffect(function () {
165
156
  if (!isInitialized) return;
166
157
  if (typeof editable === 'boolean') {
@@ -10,7 +10,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
10
10
  /* eslint-disable @typescript-eslint/no-use-before-define */
11
11
  import { $isListItemNode } from '@lexical/list';
12
12
  import { mergeRegister } from '@lexical/utils';
13
- import { $createParagraphNode, $getNodeByKey, $insertNodes, $isElementNode, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
13
+ import { $createParagraphNode, $getNodeByKey, $getRoot, $insertNodes, $isElementNode, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
14
14
  import { $closest } from "../../../editor-kernel";
15
15
  import { createDebugLogger } from "../../../utils/debug";
16
16
  import { $createDiffNode, DiffNode } from "../node/DiffNode";
@@ -361,9 +361,17 @@ function handleInsert(editor, payload, dataSource) {
361
361
  try {
362
362
  var referenceNode = null;
363
363
  if (isBefore) {
364
- referenceNode = $getNodeByKey(charToId(payload.beforeId));
364
+ if (payload.beforeId === 'root') {
365
+ referenceNode = $getRoot().getFirstChild();
366
+ } else {
367
+ referenceNode = $getNodeByKey(charToId(payload.beforeId));
368
+ }
365
369
  } else {
366
- referenceNode = $getNodeByKey(charToId(payload.afterId));
370
+ if (payload.afterId === 'root') {
371
+ referenceNode = $getRoot().getLastChild();
372
+ } else {
373
+ referenceNode = $getNodeByKey(charToId(payload.afterId));
374
+ }
367
375
  }
368
376
  if (!referenceNode) {
369
377
  throw new Error('Reference node not found for insertion.');
@@ -373,7 +381,9 @@ function handleInsert(editor, payload, dataSource) {
373
381
  });
374
382
  if (!delay) {
375
383
  if (isBefore) {
376
- referenceNode = referenceNode.insertBefore(newNodes);
384
+ newNodes.reverse().forEach(function (node) {
385
+ referenceNode = referenceNode.insertBefore(node);
386
+ });
377
387
  } else {
378
388
  newNodes.forEach(function (node) {
379
389
  if (referenceNode) {
@@ -398,7 +408,7 @@ function handleInsert(editor, payload, dataSource) {
398
408
  diffNode.append(node);
399
409
  return diffNode;
400
410
  });
401
- diffNodes.forEach(function (diffNode) {
411
+ diffNodes.reverse().forEach(function (diffNode) {
402
412
  if (referenceNode) {
403
413
  referenceNode = referenceNode.insertBefore(diffNode);
404
414
  }
@@ -1,4 +1,4 @@
1
1
  import { IEditor } from "../../../../types";
2
- export declare function useHasDiffNode(editor: IEditor): {
2
+ export declare function useHasDiffNode(editor?: IEditor): {
3
3
  hasDiff: boolean;
4
4
  };
@@ -8,6 +8,9 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
8
8
  import { useEffect, useState } from 'react';
9
9
  function hasDiffNode(editor) {
10
10
  var _editor$getLexicalEdi;
11
+ if (!editor) {
12
+ return false;
13
+ }
11
14
  var values = (_editor$getLexicalEdi = editor.getLexicalEditor()) === null || _editor$getLexicalEdi === void 0 ? void 0 : _editor$getLexicalEdi.getEditorState()._nodeMap.values();
12
15
  if (!values) {
13
16
  return false;
@@ -29,7 +32,7 @@ function hasDiffNode(editor) {
29
32
  return false;
30
33
  }
31
34
  export function useHasDiffNode(editor) {
32
- var _useState = useState(!!editor.getLexicalEditor()),
35
+ var _useState = useState(!!(editor !== null && editor !== void 0 && editor.getLexicalEditor())),
33
36
  _useState2 = _slicedToArray(_useState, 2),
34
37
  hasInit = _useState2[0],
35
38
  setHasInit = _useState2[1];
@@ -38,6 +41,9 @@ export function useHasDiffNode(editor) {
38
41
  hasDiff = _useState4[0],
39
42
  setHasDiff = _useState4[1];
40
43
  useEffect(function () {
44
+ if (!editor) {
45
+ return;
46
+ }
41
47
  var handle = function handle() {
42
48
  setHasInit(true);
43
49
  };
@@ -48,6 +54,9 @@ export function useHasDiffNode(editor) {
48
54
  }, [editor]);
49
55
  useEffect(function () {
50
56
  var _editor$getLexicalEdi2;
57
+ if (!editor || !hasInit) {
58
+ return;
59
+ }
51
60
  var unregister = (_editor$getLexicalEdi2 = editor.getLexicalEditor()) === null || _editor$getLexicalEdi2 === void 0 ? void 0 : _editor$getLexicalEdi2.registerUpdateListener(function () {
52
61
  setHasDiff(hasDiffNode(editor));
53
62
  });
@@ -54,25 +54,14 @@ var MathEdit = /*#__PURE__*/memo(function (_ref) {
54
54
  // 实时更新节点内容(仅当输入可渲染时才同步到 document)
55
55
  useEffect(function () {
56
56
  if (!mathNode) return;
57
+ // 输入无效时不同步到文档,避免无限循环;提交时会使用 lastValidRef 作为回退
58
+ if (!isInputValidRef.current) return;
57
59
 
58
60
  // 使用防抖来避免过于频繁的更新
59
61
  var timeoutId = setTimeout(function () {
60
62
  // 直接更新节点内容
61
63
  var lexicalEditor = editor.getLexicalEditor();
62
64
  if (lexicalEditor && !isUpdatingRef.current) {
63
- if (!isInputValidRef.current) {
64
- var currentNode = lexicalEditor.getEditorState().read(function () {
65
- return lexicalEditor.getElementByKey(mathNode.getKey());
66
- });
67
- if (currentNode) {
68
- lexicalEditor.update(function () {
69
- var writableNode = mathNode.getWritable();
70
- writableNode.__code = value;
71
- });
72
- }
73
- return;
74
- }
75
-
76
65
  // 检查当前值是否与节点中的值不同,避免不必要的更新
77
66
  var currentCode = mathNode.code;
78
67
  if (value && currentCode && currentCode === value) {
@@ -20,16 +20,23 @@ var MathEditorContainer = /*#__PURE__*/memo(function (_ref) {
20
20
  _useState2 = _slicedToArray(_useState, 2),
21
21
  blockWidth = _useState2[0],
22
22
  setBlockWidth = _useState2[1];
23
+ var lastBlockWidthRef = useRef(undefined);
24
+ var setBlockWidthIfNeeded = useCallback(function (nextWidth) {
25
+ var normalizedWidth = typeof nextWidth === 'number' ? Math.round(nextWidth) : undefined;
26
+ if (lastBlockWidthRef.current === normalizedWidth) return;
27
+ lastBlockWidthRef.current = normalizedWidth;
28
+ setBlockWidth(normalizedWidth);
29
+ }, []);
23
30
  var updateBlockWidth = useCallback(function () {
24
31
  if (!isBlockMode) {
25
- setBlockWidth(undefined);
32
+ setBlockWidthIfNeeded(undefined);
26
33
  return;
27
34
  }
28
35
  var editorContainer = mathDOM === null || mathDOM === void 0 ? void 0 : mathDOM.closest('[contenteditable="true"]');
29
36
  if (editorContainer) {
30
- setBlockWidth(editorContainer.getBoundingClientRect().width);
37
+ setBlockWidthIfNeeded(editorContainer.getBoundingClientRect().width);
31
38
  }
32
- }, [isBlockMode, mathDOM]);
39
+ }, [isBlockMode, mathDOM, setBlockWidthIfNeeded]);
33
40
  var updateAnchorPosition = useCallback(function () {
34
41
  return updatePosition({
35
42
  callback: function callback() {
@@ -43,6 +50,10 @@ var MathEditorContainer = /*#__PURE__*/memo(function (_ref) {
43
50
  reference: mathDOM
44
51
  });
45
52
  }, [isBlockMode, mathDOM, onFocus, updateBlockWidth]);
53
+ var handleAnchorClick = useCallback(function () {
54
+ if (!mathDOM) return;
55
+ updateAnchorPosition();
56
+ }, [mathDOM, updateAnchorPosition]);
46
57
  useEffect(function () {
47
58
  if (!mathDOM || !anchorRef.current) return;
48
59
  var floating = anchorRef.current;
@@ -86,11 +97,13 @@ var MathEditorContainer = /*#__PURE__*/memo(function (_ref) {
86
97
  placement: isBlockMode ? 'bottomLeft' : 'bottom',
87
98
  styles: {
88
99
  content: {
100
+ borderRadius: '6px',
89
101
  padding: 0
90
102
  }
91
103
  },
92
104
  children: /*#__PURE__*/_jsx("span", {
93
105
  className: styles.mathEditorAnchor,
106
+ onClick: handleAnchorClick,
94
107
  ref: anchorRef
95
108
  })
96
109
  });
@@ -21,9 +21,10 @@ var MathInline = function MathInline(_ref) {
21
21
  className = _ref.className;
22
22
  var ref = useRef(null);
23
23
  var _useLexicalNodeSelect = useLexicalNodeSelection(node.getKey()),
24
- _useLexicalNodeSelect2 = _slicedToArray(_useLexicalNodeSelect, 2),
24
+ _useLexicalNodeSelect2 = _slicedToArray(_useLexicalNodeSelect, 3),
25
25
  isSelected = _useLexicalNodeSelect2[0],
26
- setIsSelected = _useLexicalNodeSelect2[1];
26
+ setIsSelected = _useLexicalNodeSelect2[1],
27
+ clearSelected = _useLexicalNodeSelect2[2];
27
28
  var _useState = useState(false),
28
29
  _useState2 = _slicedToArray(_useState, 2),
29
30
  isEditing = _useState2[0],
@@ -116,8 +117,13 @@ var MathInline = function MathInline(_ref) {
116
117
  logger.debug('📊 Math click event:', e.target === ref.current);
117
118
  e.preventDefault();
118
119
  e.stopPropagation();
120
+ if (isSelected) {
121
+ // 强制触发一次 selection 更新,确保打开编辑器面板
122
+ clearSelected();
123
+ }
119
124
  setIsSelected(true);
120
- }, [editor, node]);
125
+ editor.focus();
126
+ }, [clearSelected, editor, isSelected, setIsSelected]);
121
127
  return /*#__PURE__*/_jsx("span", {
122
128
  className: className,
123
129
  onClick: handleClick,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "3.13.2",
3
+ "version": "3.14.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",