@lobehub/editor 4.10.2 → 4.10.6

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.
@@ -73,10 +73,12 @@ const ReactEditor = ({ editor: editorProp, children, config, onInit }) => {
73
73
  const composerContext = useMemo(() => {
74
74
  return [editorProp || Editor.createEditor(), createLexicalComposerContext(null, null)];
75
75
  }, [editorProp]);
76
+ const onInitRef = useRef(onInit);
77
+ onInitRef.current = onInit;
76
78
  useEffect(() => {
77
79
  const editor = composerContext[0];
78
- if (onInit) onInit(editor);
79
- }, [composerContext, onInit]);
80
+ onInitRef.current?.(editor);
81
+ }, [composerContext]);
80
82
  return /* @__PURE__ */ jsxs(LexicalComposerContext, {
81
83
  value: composerContext,
82
84
  children: [/* @__PURE__ */ jsx(ConfigInjector, { config }), children]
package/es/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { $ as DOM_TEXT_TYPE, A as $createCodeMirrorNode, At as createDebugLogger, B as Editor, C as $createCodeNode$1, Ct as CONTROL_OR_META, Dt as KeyEnum, E as CodeNode$1, Et as HotkeyScopeEnum, F as $isCursorNode, Ft as init_debug, G as kernel_exports, Gt as INodeHelper, H as DataSource, I as CardLikeElementNode, It as prodSafeLogger, J as $getNearestNodeFromDOMNode, K as $closest, Kt as init_helper, M as CodeMirrorNode, Mt as debugLoggers, N as $createCursorNode, Nt as debug_exports, Ot as init_hotkey, P as $isCardLikeElementNode, Pt as devConsole, Q as DOM_ELEMENT_TYPE, R as cursorNodeSerialized, S as formatUrl, St as init_registerHotkey, Tt as HotkeyEnum, U as Kernel, V as resetRandomKey, W as init_kernel, X as DOM_DOCUMENT_FRAGMENT_TYPE, Y as $getNodeFromDOMNode, Yt as __toCommonJS, Z as DOM_DOCUMENT_TYPE, _ as AutoLinkNode, _t as unregisterEditorKernel, a as $createMathBlockNode, at as generateEditorId, b as LinkNode, bt as HOVER_COMMAND, c as MathBlockNode, ct as getNodeKeyFromDOMNode, dt as isDOMNode, et as EDITOR_THEME_KEY, f as LinkHighlightNode, ft as isDocumentFragment, g as $toggleLink, gt as registerEditorKernel, h as $isLinkNode, ht as reconcileDecorator, it as genServiceId, j as $isCodeMirrorNode, jt as debugLogger, kt as browserDebug, l as MathInlineNode, lt as getParentElement, m as $createLinkNode, mt as noop, nt as compareNodeOrder, o as $createMathInlineNode, ot as getKernelFromEditor, pt as moment, q as $closestNodeType, rt as createEmptyEditorState, s as $isMathNode, st as getKernelFromEditorConfig, tt as assert, u as $createLinkHighlightNode, ut as init_utils, v as HOVER_LINK_COMMAND, vt as KernelPlugin, wt as init_sys, x as TOGGLE_LINK_COMMAND, xt as getHotkeyById, y as HOVER_OUT_LINK_COMMAND, yt as init_plugin } from "./style-CLtp6okE.js";
2
- import { A as detectLanguage, B as INodePlugin, C as ReactPlainText, D as useTranslation, E as ReactMarkdownPlugin, F as GET_MARKDOWN_SELECTION_COMMAND, G as idToChar, H as $cloneNode, I as INSERT_MARKDOWN_COMMAND, J as useLexicalEditor, K as INSERT_HEADING_COMMAND, L as isPunctuationChar, M as MARKDOWN_READER_LEVEL_HIGH, N as MARKDOWN_READER_LEVEL_NORMAL, O as MarkdownPlugin, P as MARKDOWN_WRITER_LEVEL_MAX, R as ILitexmlService, S as registerCodeInlineCommand, T as CommonPlugin, U as $parseSerializedNodeImpl, V as INodeService, W as charToId, X as useLexicalComposerContext, Y as ReactEditor, Z as LexicalErrorBoundary, _ as extractUrlFromText, a as ReactMentionPlugin, c as INSERT_LINK_HIGHLIGHT_COMMAND, d as bundledLanguagesInfo, f as CodeblockPlugin, g as registerCheckList, h as INSERT_CHECK_LIST_COMMAND, i as SlashPlugin, j as IMarkdownShortCutService, k as detectCodeLanguage, l as registerLinkHighlightCommand, m as getCodeLanguageByInput, n as ReactSlashOption, o as MentionPlugin, p as UPDATE_CODEBLOCK_LANG, q as INSERT_QUOTE_COMMAND, r as SlashMenu, s as INSERT_MENTION_COMMAND, t as ReactSlashPlugin, u as useLexicalNodeSelection, v as getSelectedNode, w as ReactEditorContent, x as INSERT_CODEINLINE_COMMAND, y as sanitizeUrl, z as LitexmlService } from "./ReactSlashPlugin-CBLFF1e6.js";
2
+ import { A as detectLanguage, B as INodePlugin, C as ReactPlainText, D as useTranslation, E as ReactMarkdownPlugin, F as GET_MARKDOWN_SELECTION_COMMAND, G as idToChar, H as $cloneNode, I as INSERT_MARKDOWN_COMMAND, J as useLexicalEditor, K as INSERT_HEADING_COMMAND, L as isPunctuationChar, M as MARKDOWN_READER_LEVEL_HIGH, N as MARKDOWN_READER_LEVEL_NORMAL, O as MarkdownPlugin, P as MARKDOWN_WRITER_LEVEL_MAX, R as ILitexmlService, S as registerCodeInlineCommand, T as CommonPlugin, U as $parseSerializedNodeImpl, V as INodeService, W as charToId, X as useLexicalComposerContext, Y as ReactEditor, Z as LexicalErrorBoundary, _ as extractUrlFromText, a as ReactMentionPlugin, c as INSERT_LINK_HIGHLIGHT_COMMAND, d as bundledLanguagesInfo, f as CodeblockPlugin, g as registerCheckList, h as INSERT_CHECK_LIST_COMMAND, i as SlashPlugin, j as IMarkdownShortCutService, k as detectCodeLanguage, l as registerLinkHighlightCommand, m as getCodeLanguageByInput, n as ReactSlashOption, o as MentionPlugin, p as UPDATE_CODEBLOCK_LANG, q as INSERT_QUOTE_COMMAND, r as SlashMenu, s as INSERT_MENTION_COMMAND, t as ReactSlashPlugin, u as useLexicalNodeSelection, v as getSelectedNode, w as ReactEditorContent, x as INSERT_CODEINLINE_COMMAND, y as sanitizeUrl, z as LitexmlService } from "./ReactSlashPlugin-DftZMdq9.js";
3
3
  import { S as DiffNode, _ as PlaceholderNode, a as styles$16, b as HorizontalRuleNode, c as ImageNode, d as BlockImageNode, f as styles$15, g as PlaceholderBlockNode, h as FileNode, i as imageBroken, l as $createBlockImageNode, m as $isFileNode, n as styles$18, o as $createImageNode, p as $createFileNode, r as styles$17, s as $isImageNode, t as styles$19, u as $isBlockImageNode, v as $createHorizontalRuleNode, x as $createDiffNode, y as $isHorizontalRuleNode } from "./style-D-dIPHv5.js";
4
4
  import { $computeTableMapSkipCellCheck, $createTableNodeWithDimensions, $createTableSelection, $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $findTableNode, $getElementForTableNode, $getNodeTriplet, $getTableAndElementByKey, $getTableCellNodeFromLexicalNode, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isTableCellNode, $isTableNode, $isTableRowNode, $isTableSelection, $mergeCells, $unmergeCell, TableCellHeaderStates, TableCellNode, TableNode, TableNode as TableNode$1, TableRowNode, getDOMCellFromTarget, getTableElement, getTableObserverFromTableElement, registerTableCellUnmergeTransform, registerTablePlugin, registerTableSelectionObserver, setScrollableTablesActive } from "@lexical/table";
5
5
  import { debounce } from "es-toolkit/compat";
6
6
  import EventEmitter from "eventemitter3";
7
- import { $createNodeSelection, $createParagraphNode, $createRangeSelection, $createTextNode, $getNearestNodeFromDOMNode as $getNearestNodeFromDOMNode$1, $getNodeByKey, $getPreviousSelection, $getRoot, $getSelection, $insertNodes, $isBlockElementNode, $isDecoratorNode, $isElementNode, $isNodeSelection, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTextNode, $nodesOfType, $normalizeSelection__EXPERIMENTAL, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, DROP_COMMAND, HISTORY_MERGE_TAG, INDENT_CONTENT_COMMAND, INSERT_TAB_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, ParagraphNode, SELECTION_CHANGE_COMMAND, SKIP_SCROLL_INTO_VIEW_TAG, TabNode, TextNode, createCommand, getDOMSelection, getDOMSelectionFromTarget, isHTMLElement, isModifierMatch } from "lexical";
7
+ import { $createNodeSelection, $createParagraphNode, $createRangeSelection, $createTextNode, $getNearestNodeFromDOMNode as $getNearestNodeFromDOMNode$1, $getNodeByKey, $getPreviousSelection, $getRoot, $getSelection, $insertNodes, $isBlockElementNode, $isDecoratorNode, $isElementNode, $isNodeSelection, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTextNode, $nodesOfType, $normalizeSelection__EXPERIMENTAL, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, DROP_COMMAND, HISTORY_MERGE_TAG, INDENT_CONTENT_COMMAND, INSERT_TAB_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, ParagraphNode, SELECTION_CHANGE_COMMAND, SKIP_SCROLL_INTO_VIEW_TAG, TabNode, TextNode, createCommand, getDOMSelection, getDOMSelectionFromTarget, isHTMLElement, isModifierMatch } from "lexical";
8
8
  import { DRAG_DROP_PASTE } from "@lexical/rich-text";
9
9
  import { $filter, $findMatchingParent, $getNearestBlockElementAncestorOrThrow, $getNearestNodeOfType, $insertNodeToNearestRoot, $wrapNodeInElement, addClassNamesToElement, calculateZoomLevel, mergeRegister, removeClassNamesFromElement } from "@lexical/utils";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -2271,12 +2271,9 @@ function createHeadlessEditor(options) {
2271
2271
  }
2272
2272
  //#endregion
2273
2273
  //#region src/plugins/auto-complete/plugin/index.ts
2274
- init_helper();
2275
2274
  init_plugin();
2276
2275
  init_debug();
2277
2276
  const AUTO_COMPLETE_GUARD_LIMIT = 5e4;
2278
- const CLEAR_PLACEHOLDER_BURST_LIMIT = 20;
2279
- const CLEAR_PLACEHOLDER_BURST_WINDOW_MS = 1e3;
2280
2277
  const AutoCompletePlugin = class extends KernelPlugin {
2281
2278
  static {
2282
2279
  this.pluginName = "AutoCompletePlugin";
@@ -2289,11 +2286,11 @@ const AutoCompletePlugin = class extends KernelPlugin {
2289
2286
  this.lastCursorPosition = null;
2290
2287
  this.cursorStableTimer = null;
2291
2288
  this.abortController = null;
2292
- this.placeholderNodes = [];
2293
2289
  this.currentSuggestion = null;
2290
+ this.placeholderAnchorPosition = null;
2291
+ this.placeholderSelectionSnapshot = null;
2294
2292
  this.markdownService = null;
2295
2293
  this.skipNextTextContentListener = false;
2296
- this.clearPlaceholderCallTimestamps = [];
2297
2294
  this.delay = config?.delay ?? 1e3;
2298
2295
  kernel.registerNodes([PlaceholderNode, PlaceholderBlockNode]);
2299
2296
  if (config?.theme) kernel.registerThemes(config?.theme);
@@ -2308,13 +2305,13 @@ const AutoCompletePlugin = class extends KernelPlugin {
2308
2305
  editorState.read(() => {
2309
2306
  if (editor.isComposing()) {
2310
2307
  this.clearTimer();
2311
- this.clearPlaceholderNodes(editor);
2308
+ if (this.currentSuggestion) this.clearPlaceholderNodes(editor, { restoreSelection: false });
2312
2309
  return;
2313
2310
  }
2314
2311
  const selection = $getSelection();
2315
2312
  if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
2316
2313
  this.clearTimer();
2317
- this.clearPlaceholderNodes(editor);
2314
+ if (this.currentSuggestion) this.clearPlaceholderNodes(editor, { restoreSelection: false });
2318
2315
  return;
2319
2316
  }
2320
2317
  const currentPosition = {
@@ -2324,7 +2321,7 @@ const AutoCompletePlugin = class extends KernelPlugin {
2324
2321
  };
2325
2322
  if (this.hasPositionChanged(currentPosition)) {
2326
2323
  this.clearTimer();
2327
- this.clearPlaceholderNodes(editor);
2324
+ if (this.currentSuggestion) this.clearPlaceholderNodes(editor, { restoreSelection: false });
2328
2325
  this.abortController = new AbortController();
2329
2326
  this.cursorStableTimer = window.setTimeout(() => {
2330
2327
  this.handleCursorStable(editor, currentPosition);
@@ -2340,11 +2337,24 @@ const AutoCompletePlugin = class extends KernelPlugin {
2340
2337
  }
2341
2338
  return false;
2342
2339
  }, COMMAND_PRIORITY_HIGH));
2340
+ this.register(editor.registerCommand(KEY_ARROW_LEFT_COMMAND, () => {
2341
+ if (this.currentSuggestion) {
2342
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2343
+ return false;
2344
+ }
2345
+ return false;
2346
+ }, COMMAND_PRIORITY_CRITICAL));
2347
+ this.register(editor.registerCommand(KEY_ARROW_RIGHT_COMMAND, () => {
2348
+ if (this.currentSuggestion) {
2349
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2350
+ return false;
2351
+ }
2352
+ return false;
2353
+ }, COMMAND_PRIORITY_CRITICAL));
2343
2354
  this.register(editor.registerCommand(KEY_ESCAPE_COMMAND, (event) => {
2344
2355
  if (this.currentSuggestion) {
2345
2356
  event?.preventDefault();
2346
2357
  this.clearPlaceholderNodes(editor);
2347
- this.currentSuggestion = null;
2348
2358
  return true;
2349
2359
  }
2350
2360
  return false;
@@ -2354,7 +2364,7 @@ const AutoCompletePlugin = class extends KernelPlugin {
2354
2364
  this.skipNextTextContentListener = false;
2355
2365
  return;
2356
2366
  }
2357
- if (this.currentSuggestion) this.clearPlaceholderNodes(editor);
2367
+ if (this.currentSuggestion) this.clearPlaceholderNodes(editor, { restoreSelection: false });
2358
2368
  }));
2359
2369
  }
2360
2370
  hasPositionChanged(currentPosition) {
@@ -2372,7 +2382,7 @@ const AutoCompletePlugin = class extends KernelPlugin {
2372
2382
  editor.getEditorState().read(() => {
2373
2383
  if (editor.isComposing()) {
2374
2384
  this.clearTimer();
2375
- this.clearPlaceholderNodes(editor);
2385
+ if (this.currentSuggestion) this.clearPlaceholderNodes(editor, { restoreSelection: false });
2376
2386
  return;
2377
2387
  }
2378
2388
  if (!this.abortController || this.abortController.signal.aborted) return;
@@ -2387,9 +2397,8 @@ const AutoCompletePlugin = class extends KernelPlugin {
2387
2397
  if (this.lastCursorPosition && this.isSamePosition(position, this.lastCursorPosition)) return;
2388
2398
  this.lastCursorPosition = currentPosition;
2389
2399
  const anchorNode = selection.anchor.getNode();
2390
- let selectionType = "unknown";
2391
2400
  const textRet = this.getTextBeforeCursor(selection);
2392
- selectionType = anchorNode.getType();
2401
+ const selectionType = anchorNode.getType();
2393
2402
  if (this.config?.onAutoComplete) this.config.onAutoComplete({
2394
2403
  abortSignal: this.abortController.signal,
2395
2404
  afterText: textRet.textAfter,
@@ -2402,11 +2411,11 @@ const AutoCompletePlugin = class extends KernelPlugin {
2402
2411
  currentSelection = $getSelection();
2403
2412
  });
2404
2413
  if (editor.isComposing()) {
2405
- this.clearPlaceholderNodes(editor);
2414
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2406
2415
  return;
2407
2416
  }
2408
2417
  if (!currentSelection || !$isRangeSelection(currentSelection) || !currentSelection.isCollapsed()) {
2409
- this.clearPlaceholderNodes(editor);
2418
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2410
2419
  return;
2411
2420
  }
2412
2421
  const newPosition = {
@@ -2415,11 +2424,12 @@ const AutoCompletePlugin = class extends KernelPlugin {
2415
2424
  type: currentSelection.anchor.type
2416
2425
  };
2417
2426
  if (!this.isSamePosition(currentPosition, newPosition)) {
2418
- this.clearPlaceholderNodes(editor);
2427
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2419
2428
  return;
2420
2429
  }
2421
2430
  if (result) {
2422
2431
  this.currentSuggestion = result;
2432
+ this.placeholderAnchorPosition = currentPosition;
2423
2433
  this.showPlaceholderNodes(editor, result);
2424
2434
  this.logger.debug("🔍 Auto-complete triggered:", {
2425
2435
  afterText: textRet.textAfter,
@@ -2428,15 +2438,11 @@ const AutoCompletePlugin = class extends KernelPlugin {
2428
2438
  result,
2429
2439
  selectionType
2430
2440
  });
2431
- } else this.clearPlaceholderNodes(editor);
2441
+ } else this.clearPlaceholderNodes(editor, { restoreSelection: false });
2432
2442
  });
2433
2443
  });
2434
2444
  }
2435
2445
  getTextBeforeCursor(selection) {
2436
- const ret = {
2437
- textAfter: "",
2438
- textBefore: ""
2439
- };
2440
2446
  const anchorNode = selection.anchor.getNode();
2441
2447
  const anchorOffset = selection.anchor.offset;
2442
2448
  let paragraphNode = anchorNode;
@@ -2448,7 +2454,10 @@ const AutoCompletePlugin = class extends KernelPlugin {
2448
2454
  if (!parent) break;
2449
2455
  paragraphNode = parent;
2450
2456
  }
2451
- if (!paragraphNode) return ret;
2457
+ if (!paragraphNode) return {
2458
+ textAfter: "",
2459
+ textBefore: ""
2460
+ };
2452
2461
  this.logger.debug("🔍 Paragraph Node Type:", paragraphNode, anchorNode);
2453
2462
  let founded = false;
2454
2463
  let recursionDepth = 0;
@@ -2504,6 +2513,8 @@ const AutoCompletePlugin = class extends KernelPlugin {
2504
2513
  this.logger.warn("⚠️ No valid markdown service for placeholder");
2505
2514
  return;
2506
2515
  }
2516
+ for (const node of $nodesOfType(PlaceholderNode)) node.remove();
2517
+ for (const node of $nodesOfType(PlaceholderBlockNode)) node.remove();
2507
2518
  const nodes = this.markdownService.parseMarkdownToLexical(suggestion);
2508
2519
  if (nodes.children[0]) {
2509
2520
  const firstChild = nodes.children[0];
@@ -2519,51 +2530,32 @@ const AutoCompletePlugin = class extends KernelPlugin {
2519
2530
  type: "PlaceholderBlock"
2520
2531
  };
2521
2532
  }
2522
- const markerNode = INodeHelper.createTextNode("​");
2523
- nodes.children.push({
2524
- children: [markerNode],
2525
- name: "",
2526
- type: "PlaceholderInline"
2527
- });
2528
2533
  const saveSel = selection.clone();
2534
+ this.placeholderSelectionSnapshot = saveSel;
2529
2535
  this.markdownService.insertIRootNode(editor, nodes, selection);
2530
2536
  $setSelection(saveSel);
2531
2537
  });
2532
2538
  }
2533
- clearPlaceholderNodes(editor) {
2534
- const now = Date.now();
2535
- this.clearPlaceholderCallTimestamps = this.clearPlaceholderCallTimestamps.filter((ts) => now - ts <= CLEAR_PLACEHOLDER_BURST_WINDOW_MS);
2536
- if (this.clearPlaceholderCallTimestamps.length >= CLEAR_PLACEHOLDER_BURST_LIMIT) return;
2537
- this.clearPlaceholderCallTimestamps.push(now);
2538
- this.skipNextTextContentListener = true;
2539
+ clearPlaceholderNodes(editor, options) {
2540
+ const shouldRestoreSelection = options?.restoreSelection ?? true;
2541
+ const restoreSelection = this.placeholderSelectionSnapshot;
2539
2542
  this.currentSuggestion = null;
2540
- this.placeholderNodes = [];
2543
+ this.placeholderAnchorPosition = null;
2544
+ this.placeholderSelectionSnapshot = null;
2545
+ this.clearTimer();
2546
+ let hasPlaceholderNodes = false;
2547
+ editor.getEditorState().read(() => {
2548
+ hasPlaceholderNodes = $nodesOfType(PlaceholderNode).length > 0 || $nodesOfType(PlaceholderBlockNode).length > 0;
2549
+ });
2550
+ if (!hasPlaceholderNodes && !(shouldRestoreSelection && restoreSelection)) {
2551
+ this.skipNextTextContentListener = false;
2552
+ return;
2553
+ }
2554
+ this.skipNextTextContentListener = true;
2541
2555
  editor.update(() => {
2542
- let iterCount = 0;
2543
- editor.getEditorState()._nodeMap.forEach((node) => {
2544
- iterCount++;
2545
- if (iterCount > AUTO_COMPLETE_GUARD_LIMIT) throw new Error(`clearPlaceholderNodes: forEach loop > ${AUTO_COMPLETE_GUARD_LIMIT} iterations`);
2546
- const selection = $getSelection();
2547
- const clonedSelection = selection ? selection.clone() : null;
2548
- if (node.isAttached() && ["PlaceholderBlock", "PlaceholderInline"].includes(node.getType())) {
2549
- if (node.getType() === "PlaceholderInline" && node.getTextContent().includes("​") && node.getPreviousSibling() === null) {
2550
- const siblings = [];
2551
- let sibling = node.getNextSibling();
2552
- let siblingLoopCount = 0;
2553
- while (sibling && siblingLoopCount < AUTO_COMPLETE_GUARD_LIMIT) {
2554
- siblings.push(sibling);
2555
- sibling = sibling.getNextSibling();
2556
- siblingLoopCount++;
2557
- }
2558
- if (siblingLoopCount >= AUTO_COMPLETE_GUARD_LIMIT) throw new Error(`clearPlaceholderNodes: too many siblings (${siblingLoopCount}/${AUTO_COMPLETE_GUARD_LIMIT})`);
2559
- node.getParent()?.remove();
2560
- if (siblings.length > 0) $insertNodes(siblings);
2561
- $setSelection(clonedSelection);
2562
- return;
2563
- }
2564
- node.remove();
2565
- }
2566
- });
2556
+ for (const node of $nodesOfType(PlaceholderNode)) node.remove();
2557
+ for (const node of $nodesOfType(PlaceholderBlockNode)) node.remove();
2558
+ if (shouldRestoreSelection && restoreSelection) $setSelection(restoreSelection);
2567
2559
  });
2568
2560
  }
2569
2561
  applySuggestion(editor) {
@@ -2572,13 +2564,11 @@ const AutoCompletePlugin = class extends KernelPlugin {
2572
2564
  editor.update(() => {
2573
2565
  const selection = $getSelection();
2574
2566
  if (!$isRangeSelection(selection) || !selection.isCollapsed() || !this.markdownService) return;
2575
- editor.getEditorState()._nodeMap.forEach((node) => {
2576
- if (node.isAttached() && ["PlaceholderBlock", "PlaceholderInline"].includes(node.getType())) node.remove();
2577
- });
2567
+ for (const node of $nodesOfType(PlaceholderNode)) node.remove();
2568
+ for (const node of $nodesOfType(PlaceholderBlockNode)) node.remove();
2578
2569
  const nodes = this.markdownService.parseMarkdownToLexical(markdown);
2579
2570
  this.markdownService.insertIRootNode(editor, nodes, selection);
2580
- this.clearPlaceholderNodes(editor);
2581
- this.currentSuggestion = null;
2571
+ this.clearPlaceholderNodes(editor, { restoreSelection: false });
2582
2572
  });
2583
2573
  }
2584
2574
  isSamePosition(pos1, pos2) {
@@ -2586,7 +2576,6 @@ const AutoCompletePlugin = class extends KernelPlugin {
2586
2576
  }
2587
2577
  destroy() {
2588
2578
  this.clearTimer();
2589
- this.placeholderNodes = [];
2590
2579
  super.destroy();
2591
2580
  }
2592
2581
  };
@@ -5061,6 +5050,10 @@ const ResizeHandle = ({ imageRef, isBlock, onResize, onResizeEnd, onResizeStart,
5061
5050
  ResizeHandle.displayName = "ResizeHandle";
5062
5051
  //#endregion
5063
5052
  //#region src/plugins/image/react/components/Image.tsx
5053
+ function getResizedImageWidth(startWidth, deltaX, maxWidth) {
5054
+ const adjustedDeltaX = deltaX * 2;
5055
+ return Math.max(50, Math.min(startWidth + adjustedDeltaX, maxWidth));
5056
+ }
5064
5057
  const Image$1 = memo(({ node, className, showScaleInfo = false, handleUpload, onPickFile }) => {
5065
5058
  const [isSelected, setSelected] = useLexicalNodeSelection(node.getKey());
5066
5059
  const [isHovered, setIsHovered] = useState(false);
@@ -5096,8 +5089,7 @@ const Image$1 = memo(({ node, className, showScaleInfo = false, handleUpload, on
5096
5089
  if (!imageRef.current) return;
5097
5090
  const aspectRatio = originalSizeRef.current.width / originalSizeRef.current.height;
5098
5091
  const maxWidth = imageRef.current.parentElement?.clientWidth || window.innerWidth;
5099
- const adjustedDeltaX = deltaX * 2;
5100
- const newWidth = Math.max(50, Math.min(startWidthRef.current + adjustedDeltaX, maxWidth));
5092
+ const newWidth = getResizedImageWidth(startWidthRef.current, deltaX, maxWidth);
5101
5093
  setSize({
5102
5094
  height: newWidth / aspectRatio,
5103
5095
  width: newWidth
@@ -5171,8 +5163,7 @@ const Image$1 = memo(({ node, className, showScaleInfo = false, handleUpload, on
5171
5163
  if (!originalSizeRef.current.width || !originalSizeRef.current.height) return;
5172
5164
  if (!imageRef.current) return;
5173
5165
  const maxWidth = imageRef.current.parentElement?.clientWidth || window.innerWidth;
5174
- const adjustedDeltaX = deltaX / 2;
5175
- const finalWidth = Math.max(50, Math.min(startWidthRef.current + adjustedDeltaX, maxWidth));
5166
+ const finalWidth = getResizedImageWidth(startWidthRef.current, deltaX, maxWidth);
5176
5167
  const editor = editorRef.current;
5177
5168
  if (!editor) return;
5178
5169
  editor.update(() => {
package/es/react.js CHANGED
@@ -1,5 +1,5 @@
1
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-CLtp6okE.js";
2
- import { C as ReactPlainText, E as ReactMarkdownPlugin, Y as ReactEditor, _ as extractUrlFromText, a as ReactMentionPlugin, b as validateUrl, c as INSERT_LINK_HIGHLIGHT_COMMAND, h as INSERT_CHECK_LIST_COMMAND, n as ReactSlashOption, p as UPDATE_CODEBLOCK_LANG, t as ReactSlashPlugin, w as ReactEditorContent, x as INSERT_CODEINLINE_COMMAND, y as sanitizeUrl } from "./ReactSlashPlugin-CBLFF1e6.js";
2
+ import { C as ReactPlainText, E as ReactMarkdownPlugin, Y as ReactEditor, _ as extractUrlFromText, a as ReactMentionPlugin, b as validateUrl, c as INSERT_LINK_HIGHLIGHT_COMMAND, h as INSERT_CHECK_LIST_COMMAND, n as ReactSlashOption, p as UPDATE_CODEBLOCK_LANG, t as ReactSlashPlugin, w as ReactEditorContent, x as INSERT_CODEINLINE_COMMAND, y as sanitizeUrl } from "./ReactSlashPlugin-DftZMdq9.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";
@@ -1442,7 +1442,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
1442
1442
  }));
1443
1443
  //#endregion
1444
1444
  //#region src/react/SendButton/SendButton.tsx
1445
- const SendButton = ({ type = "primary", menu, className, style, loading, generating, size = 32, shape, onSend, onStop, disabled, onClick, ...rest }) => {
1445
+ const SendButton = ({ type = "primary", menu, className, style, loading, generating, size = 32, shape, onSend, onStop, disabled, onClick, styles: _styles, classNames: _classNames, ...rest }) => {
1446
1446
  const cssVariables = useMemo(() => ({ "--send-button-size": `${size}px` }), [size]);
1447
1447
  if (generating) return /* @__PURE__ */ jsx(Button, {
1448
1448
  className: cx(styles.loadingButton, className),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.10.2",
3
+ "version": "4.10.6",
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",