@lobehub/editor 1.6.2 → 1.7.1

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.
@@ -4,7 +4,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
4
4
  import { $isCodeHighlightNode } from '@lexical/code';
5
5
  import { $getSelection, $insertNodes, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
6
6
  import { $createCursorNode } from "../../common";
7
- import { $createCodeNode, $isCodeInlineNode } from "../node/code";
7
+ import { $createCodeNode, $isCodeInlineNode, getCodeInlineNode } from "../node/code";
8
8
  export var INSERT_CODEINLINE_COMMAND = createCommand('INSERT_CODEINLINE_COMMAND');
9
9
  export function registerCodeInlineCommand(editor) {
10
10
  return editor.registerCommand(INSERT_CODEINLINE_COMMAND, function () {
@@ -18,24 +18,24 @@ export function registerCodeInlineCommand(editor) {
18
18
  if ($isCodeHighlightNode(focusNode) || $isCodeHighlightNode(anchorNode)) {
19
19
  return false;
20
20
  }
21
- if (focusNode.getParent() !== anchorNode.getParent()) {
21
+ var code = getCodeInlineNode(focusNode);
22
+ if (code !== getCodeInlineNode(anchorNode)) {
22
23
  return false;
23
24
  }
24
- var parentNode = focusNode.getParent();
25
- if ($isCodeInlineNode(parentNode)) {
26
- var _iterator = _createForOfIteratorHelper(parentNode.getChildren().slice(0)),
25
+ if ($isCodeInlineNode(code)) {
26
+ var _iterator = _createForOfIteratorHelper(code.getChildren().slice(0)),
27
27
  _step;
28
28
  try {
29
29
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
30
30
  var node = _step.value;
31
- parentNode.insertBefore(node);
31
+ code.insertBefore(node);
32
32
  }
33
33
  } catch (err) {
34
34
  _iterator.e(err);
35
35
  } finally {
36
36
  _iterator.f();
37
37
  }
38
- parentNode.remove();
38
+ code.remove();
39
39
  return true;
40
40
  }
41
41
  var codeNode = $createCodeNode(selection.getTextContent());
@@ -1,4 +1,4 @@
1
- import { EditorConfig, LexicalEditor, SerializedElementNode } from 'lexical';
1
+ import { EditorConfig, LexicalEditor, LexicalNode, SerializedElementNode } from 'lexical';
2
2
  import { CardLikeElementNode } from "../../common";
3
3
  export type SerializedCodeNode = SerializedElementNode;
4
4
  export declare class CodeNode extends CardLikeElementNode {
@@ -17,4 +17,5 @@ export declare class CodeNode extends CardLikeElementNode {
17
17
  }
18
18
  export declare function $createCodeNode(textContent?: string): CodeNode;
19
19
  export declare function $isCodeInlineNode(node: unknown): node is CodeNode;
20
+ export declare function getCodeInlineNode(node: LexicalNode): LexicalNode | null;
20
21
  export declare function $isSelectionInCodeInline(editor: LexicalEditor): boolean;
@@ -16,7 +16,7 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g
16
16
  /* eslint-disable @typescript-eslint/no-use-before-define */
17
17
  import { addClassNamesToElement } from '@lexical/utils';
18
18
  import { $applyNodeReplacement, $createTextNode, $getSelection, $isNodeSelection, $isRangeSelection } from 'lexical';
19
- import { $createCursorNode, CardLikeElementNode } from "../../common";
19
+ import { $createCursorNode, $isCursorNode, CardLikeElementNode } from "../../common";
20
20
  export var CodeNode = /*#__PURE__*/function (_CardLikeElementNode) {
21
21
  _inherits(CodeNode, _CardLikeElementNode);
22
22
  var _super = _createSuper(CodeNode);
@@ -120,6 +120,25 @@ export function $createCodeNode(textContent) {
120
120
  export function $isCodeInlineNode(node) {
121
121
  return node instanceof CodeNode;
122
122
  }
123
+ export function getCodeInlineNode(node) {
124
+ if ($isCursorNode(node)) {
125
+ var parent = node.getParent();
126
+ if ($isCodeInlineNode(parent)) {
127
+ return parent;
128
+ }
129
+ if ($isCodeInlineNode(node.getNextSibling())) {
130
+ return node.getNextSibling();
131
+ }
132
+ if ($isCodeInlineNode(node.getPreviousSibling())) {
133
+ return node.getPreviousSibling();
134
+ }
135
+ return null;
136
+ }
137
+ if ($isCodeInlineNode(node.getParent())) {
138
+ return node.getParent();
139
+ }
140
+ return null;
141
+ }
123
142
  export function $isSelectionInCodeInline(editor) {
124
143
  return editor.read(function () {
125
144
  var selection = $getSelection();
@@ -129,11 +148,11 @@ export function $isSelectionInCodeInline(editor) {
129
148
  if ($isRangeSelection(selection)) {
130
149
  var focusNode = selection.focus.getNode();
131
150
  var anchorNode = selection.anchor.getNode();
132
- if (focusNode.getParent() !== anchorNode.getParent()) {
151
+ var code = getCodeInlineNode(focusNode);
152
+ if (code !== getCodeInlineNode(anchorNode)) {
133
153
  return false;
134
154
  }
135
- var parentNode = focusNode.getParent();
136
- if ($isCodeInlineNode(parentNode)) {
155
+ if ($isCodeInlineNode(code)) {
137
156
  return true;
138
157
  }
139
158
  return false;
@@ -13,10 +13,12 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g
13
13
  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; }
14
14
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
15
15
  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); }
16
+ import { $setSelection } from 'lexical';
16
17
  import { KernelPlugin } from "../../../editor-kernel/plugin";
18
+ import { $createCursorNode } from "../../common";
17
19
  import { IMarkdownShortCutService } from "../../markdown/service/shortcut";
18
20
  import { registerCodeInlineCommand } from "../command";
19
- import { CodeNode } from "../node/code";
21
+ import { $createCodeNode, CodeNode } from "../node/code";
20
22
  import { registerCodeInline } from "./registry";
21
23
  export var CodePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
22
24
  _inherits(CodePlugin, _KernelPlugin);
@@ -49,6 +51,16 @@ export var CodePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
49
51
  ctx.appendLine("`".concat(node.getTextContent(), "`"));
50
52
  return true;
51
53
  });
54
+ markdownService.registerMarkdownShortCuts([{
55
+ process: function process(selection) {
56
+ var text = selection.getTextContent();
57
+ selection.removeText();
58
+ selection.insertNodes([$createCodeNode(text), $createCursorNode()]);
59
+ $setSelection(selection);
60
+ },
61
+ tag: '`',
62
+ type: 'text-format'
63
+ }]);
52
64
  }
53
65
  }]);
54
66
  return CodePlugin;
@@ -3,6 +3,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
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
5
  import { $getNodeByKey } from 'lexical';
6
+ import { $createCursorNode } from "../../common";
6
7
  import { HotkeyEnum } from "../../../types/hotkey";
7
8
  import { INSERT_CODEINLINE_COMMAND } from "../command";
8
9
  import { CodeNode } from "../node/code";
@@ -14,6 +15,7 @@ export function registerCodeInline(editor, kernel, options) {
14
15
  var mutatedNodes = _ref2.mutatedNodes;
15
16
  var codeChanged = mutatedNodes === null || mutatedNodes === void 0 ? void 0 : mutatedNodes.get(CodeNode);
16
17
  var keys = (codeChanged === null || codeChanged === void 0 ? void 0 : codeChanged.keys()) || [];
18
+ var needAddBefore = new Set();
17
19
  editor.read(function () {
18
20
  var _iterator = _createForOfIteratorHelper(keys),
19
21
  _step;
@@ -25,13 +27,8 @@ export function registerCodeInline(editor, kernel, options) {
25
27
  return;
26
28
  }
27
29
  var parent = node.getParent();
28
- if ((parent === null || parent === void 0 ? void 0 : parent.__last) === key) {
29
- var codeElement = editor.getElementByKey(key);
30
- if (!(codeElement !== null && codeElement !== void 0 && codeElement.nextSibling)) {
31
- parent
32
- // @ts-expect-error not error
33
- .getDOMSlot(editor.getElementByKey(parent.getKey())).setManagedLineBreak('decorator');
34
- }
30
+ if ((parent === null || parent === void 0 ? void 0 : parent.getFirstChild()) === node) {
31
+ needAddBefore.add(node);
35
32
  }
36
33
  }
37
34
  } catch (err) {
@@ -40,6 +37,16 @@ export function registerCodeInline(editor, kernel, options) {
40
37
  _iterator.f();
41
38
  }
42
39
  });
40
+ if (needAddBefore.size > 0) {
41
+ editor.update(function () {
42
+ needAddBefore.forEach(function (node) {
43
+ var prev = node.getPreviousSibling();
44
+ if (!prev) {
45
+ node.insertBefore($createCursorNode());
46
+ }
47
+ });
48
+ });
49
+ }
43
50
  }), kernel.registerHotkey(HotkeyEnum.CodeInline, function () {
44
51
  return editor.dispatchCommand(INSERT_CODEINLINE_COMMAND, undefined);
45
52
  }, {
@@ -1,4 +1,4 @@
1
1
  export { INSERT_HEADING_COMMAND, INSERT_QUOTE_COMMAND } from './command';
2
- export { $createCursorNode, $isCardLikeElementNode, CardLikeElementNode } from './node/cursor';
2
+ export { $createCursorNode, $isCardLikeElementNode, $isCursorNode, CardLikeElementNode, } from './node/cursor';
3
3
  export * from './plugin';
4
4
  export * from './react';
@@ -1,4 +1,4 @@
1
1
  export { INSERT_HEADING_COMMAND, INSERT_QUOTE_COMMAND } from "./command";
2
- export { $createCursorNode, $isCardLikeElementNode, CardLikeElementNode } from "./node/cursor";
2
+ export { $createCursorNode, $isCardLikeElementNode, $isCursorNode, CardLikeElementNode } from "./node/cursor";
3
3
  export * from "./plugin";
4
4
  export * from "./react";
@@ -130,6 +130,14 @@ export function registerCursorNode(editor) {
130
130
  mutation = _step3$value[1];
131
131
  if (mutation === 'updated') {
132
132
  var cursorNode = $getNodeByKey(key);
133
+ if ((cursorNode === null || cursorNode === void 0 ? void 0 : cursorNode.getIndexWithinParent()) === 0) {
134
+ var nextElement = cursorNode.getNextSibling();
135
+ if (!$isCardLikeElementNode(nextElement) && !$isDecoratorNode(nextElement) && !$isCardLikeElementNode(cursorNode === null || cursorNode === void 0 ? void 0 : cursorNode.getParent())) {
136
+ needRemove.add(cursorNode);
137
+ } else {
138
+ continue;
139
+ }
140
+ }
133
141
  var element = cursorNode === null || cursorNode === void 0 ? void 0 : cursorNode.getPreviousSibling();
134
142
  if (!$isCardLikeElementNode(element) && !$isDecoratorNode(element) && !$isCardLikeElementNode(cursorNode === null || cursorNode === void 0 ? void 0 : cursorNode.getParent())) {
135
143
  needRemove.add(cursorNode);
@@ -33,7 +33,7 @@ import TextDataSource from "../data-source/text-data-source";
33
33
  import { patchBreakLine, registerBreakLineClick } from "../node/ElementDOMSlot";
34
34
  import { CursorNode, registerCursorNode } from "../node/cursor";
35
35
  import { createBlockNode } from "../utils";
36
- import { registerHeaderBackspace, registerRichKeydown } from "./register";
36
+ import { registerHeaderBackspace, registerLastElement, registerRichKeydown } from "./register";
37
37
  patchBreakLine();
38
38
  export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
39
39
  _inherits(CommonPlugin, _KernelPlugin);
@@ -117,10 +117,6 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
117
117
  intraword: false,
118
118
  tag: '__',
119
119
  type: 'text-format'
120
- }, {
121
- format: ['code'],
122
- tag: '`',
123
- type: 'text-format'
124
120
  }, {
125
121
  format: ['strikethrough'],
126
122
  tag: '~~',
@@ -244,7 +240,7 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
244
240
  var _this$config;
245
241
  this.registerClears(registerRichText(editor), registerDragonSupport(editor), registerHistory(editor, createEmptyHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel, {
246
242
  enableHotkey: (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enableHotkey
247
- }), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor));
243
+ }), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor), registerLastElement(editor));
248
244
  }
249
245
  }, {
250
246
  key: "destroy",
@@ -7,3 +7,4 @@ export interface RichKeydownOptions {
7
7
  enableHotkey?: boolean;
8
8
  }
9
9
  export declare function registerRichKeydown(editor: LexicalEditor, kernel: IEditor, options?: RichKeydownOptions): () => void;
10
+ export declare function registerLastElement(editor: LexicalEditor): () => void;
@@ -90,7 +90,7 @@ function $isSelectionAtEndOfRoot(selection) {
90
90
  }
91
91
  export function registerHeaderBackspace(editor) {
92
92
  return editor.registerCommand(KEY_BACKSPACE_COMMAND, function (payload) {
93
- // Handle backspace key press
93
+ // Handle backspace key press for heading nodes
94
94
  var headingNode = editor.read(function () {
95
95
  var selection = $getSelection();
96
96
  // Do not handle non-collapsed selection
@@ -289,4 +289,43 @@ export function registerRichKeydown(editor, kernel, options) {
289
289
  }
290
290
  return false;
291
291
  }, COMMAND_PRIORITY_EDITOR));
292
+ }
293
+ var NEEDS_FOLLOWING_PARAGRAPH_TYPES = new Set(['code', 'table']);
294
+ export function registerLastElement(editor) {
295
+ var isProcessing = false;
296
+ return editor.registerUpdateListener(function (_ref2) {
297
+ var dirtyElements = _ref2.dirtyElements;
298
+ // Only process when root node or its direct children have changes
299
+ if (!dirtyElements.has('root') && !Array.from(dirtyElements.keys()).some(function (key) {
300
+ var _node$getParent;
301
+ var node = editor.getEditorState()._nodeMap.get(key);
302
+ return (node === null || node === void 0 || (_node$getParent = node.getParent()) === null || _node$getParent === void 0 ? void 0 : _node$getParent.getKey()) === 'root';
303
+ })) {
304
+ return;
305
+ }
306
+ if (isProcessing) return;
307
+ var needsParagraph = editor.read(function () {
308
+ var root = $getRoot();
309
+ var lastChild = root.getLastChild();
310
+
311
+ // Check if the last element needs a trailing paragraph
312
+ return NEEDS_FOLLOWING_PARAGRAPH_TYPES.has(lastChild === null || lastChild === void 0 ? void 0 : lastChild.getType());
313
+ });
314
+ if (needsParagraph) {
315
+ isProcessing = true;
316
+ queueMicrotask(function () {
317
+ editor.update(function () {
318
+ var root = $getRoot();
319
+ var currentLast = root.getLastChild();
320
+
321
+ // Double check to ensure the state still needs processing
322
+ if (NEEDS_FOLLOWING_PARAGRAPH_TYPES.has(currentLast === null || currentLast === void 0 ? void 0 : currentLast.getType())) {
323
+ var paragraph = $createParagraphNode();
324
+ root.append(paragraph);
325
+ }
326
+ isProcessing = false;
327
+ });
328
+ });
329
+ }
330
+ });
292
331
  }
@@ -1,8 +1,9 @@
1
- import { ElementNode, LexicalNode, TextFormatType, TextNode } from 'lexical';
1
+ import { ElementNode, LexicalNode, RangeSelection, TextFormatType, TextNode } from 'lexical';
2
2
  import { IServiceID } from "../../../types/kernel";
3
3
  export type TextFormatTransformer = Readonly<{
4
- format: ReadonlyArray<TextFormatType>;
4
+ format?: ReadonlyArray<TextFormatType>;
5
5
  intraword?: boolean;
6
+ process?: (selection: RangeSelection) => void;
6
7
  tag: string;
7
8
  type: 'text-format';
8
9
  }>;
@@ -129,8 +130,9 @@ export declare class MarkdownShortCutService implements IMarkdownShortCutService
129
130
  type: "text-match";
130
131
  }>[]>>;
131
132
  get textFormatTransformersByTrigger(): Readonly<Record<string, readonly Readonly<{
132
- format: readonly TextFormatType[];
133
+ format?: readonly TextFormatType[] | undefined;
133
134
  intraword?: boolean | undefined;
135
+ process?: ((selection: RangeSelection) => void) | undefined;
134
136
  tag: string;
135
137
  type: "text-format";
136
138
  }>[]>>;
@@ -234,50 +234,58 @@ function $runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransfor
234
234
  closeNode.setTextContent(closeNodeText);
235
235
  var openNodeText = openNode === closeNode ? closeNodeText : prevOpenNodeText;
236
236
  openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength));
237
- var selection = $getSelection();
237
+ var _selection = $getSelection();
238
238
  var nextSelection = $createRangeSelection();
239
239
  $setSelection(nextSelection);
240
240
  // Adjust offset based on deleted chars
241
241
  var newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1;
242
242
  nextSelection.anchor.set(openNode.__key, openTagStartIndex, 'text');
243
243
  nextSelection.focus.set(closeNode.__key, newOffset, 'text');
244
-
245
- // Apply formatting to selected text
246
- var _iterator5 = _createForOfIteratorHelper(matcher.format),
247
- _step5;
248
- try {
249
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
250
- var format = _step5.value;
251
- if (!nextSelection.hasFormat(format)) {
252
- nextSelection.formatText(format);
244
+ if (matcher.process) {
245
+ matcher.process(nextSelection);
246
+ return true;
247
+ } else if (matcher.format) {
248
+ // Apply formatting to selected text
249
+ var _iterator5 = _createForOfIteratorHelper(matcher.format),
250
+ _step5;
251
+ try {
252
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
253
+ var format = _step5.value;
254
+ if (!nextSelection.hasFormat(format)) {
255
+ nextSelection.formatText(format);
256
+ }
253
257
  }
254
- }
255
258
 
256
- // Collapse selection up to the focus point
257
- } catch (err) {
258
- _iterator5.e(err);
259
- } finally {
260
- _iterator5.f();
261
- }
262
- nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
259
+ // Collapse selection up to the focus point
260
+ } catch (err) {
261
+ _iterator5.e(err);
262
+ } finally {
263
+ _iterator5.f();
264
+ }
265
+ nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
263
266
 
264
- // Remove formatting from collapsed selection
265
- var _iterator6 = _createForOfIteratorHelper(matcher.format),
266
- _step6;
267
- try {
268
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
269
- var _format = _step6.value;
270
- if (nextSelection.hasFormat(_format)) {
271
- nextSelection.toggleFormat(_format);
267
+ // Remove formatting from collapsed selection
268
+ var _iterator6 = _createForOfIteratorHelper(matcher.format),
269
+ _step6;
270
+ try {
271
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
272
+ var _format = _step6.value;
273
+ if (nextSelection.hasFormat(_format)) {
274
+ nextSelection.toggleFormat(_format);
275
+ }
272
276
  }
277
+ } catch (err) {
278
+ _iterator6.e(err);
279
+ } finally {
280
+ _iterator6.f();
273
281
  }
274
- } catch (err) {
275
- _iterator6.e(err);
276
- } finally {
277
- _iterator6.f();
278
- }
279
- if ($isRangeSelection(selection)) {
280
- nextSelection.format = selection.format;
282
+ if ($isRangeSelection(_selection)) {
283
+ nextSelection.format = _selection.format;
284
+ }
285
+ } else {
286
+ // No format or process specified, nothing to do
287
+ $setSelection(_selection);
288
+ continue;
281
289
  }
282
290
  return true;
283
291
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
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",