@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.
- package/es/editor-kernel/kernel.d.ts +4 -0
- package/es/editor-kernel/kernel.js +75 -24
- package/es/plugins/common/plugin/index.js +3 -2
- package/es/plugins/common/react/Placeholder/index.d.ts +1 -0
- package/es/plugins/common/react/Placeholder/index.js +40 -3
- package/es/plugins/common/react/ReactPlainText.js +3 -1
- package/es/plugins/common/react/style.js +1 -1
- package/es/plugins/common/react/type.d.ts +1 -0
- package/es/plugins/markdown/command/index.d.ts +3 -1
- package/es/plugins/markdown/command/index.js +32 -14
- package/es/plugins/markdown/plugin/index.js +3 -1
- package/es/plugins/markdown/react/index.js +3 -3
- package/es/react/Editor/Editor.js +2 -0
- package/es/types/kernel.d.ts +13 -3
- package/package.json +23 -23
|
@@ -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
|
|
343
|
-
|
|
393
|
+
var _iterator3 = _createForOfIteratorHelper(decoratorNames),
|
|
394
|
+
_step3;
|
|
344
395
|
try {
|
|
345
|
-
for (
|
|
346
|
-
var decoratorName =
|
|
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
|
-
|
|
402
|
+
_iterator3.e(err);
|
|
352
403
|
} finally {
|
|
353
|
-
|
|
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
|
|
385
|
-
|
|
435
|
+
var _iterator4 = _createForOfIteratorHelper(plugins),
|
|
436
|
+
_step4;
|
|
386
437
|
try {
|
|
387
|
-
for (
|
|
388
|
-
var plugin =
|
|
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
|
-
|
|
447
|
+
_iterator4.e(err);
|
|
397
448
|
} finally {
|
|
398
|
-
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
645
|
+
var listenerInPriorityOrder = _this5._commands.get(command);
|
|
595
646
|
if (listenerInPriorityOrder !== undefined) {
|
|
596
647
|
var listenersSet = listenerInPriorityOrder[i];
|
|
597
|
-
var
|
|
598
|
-
|
|
648
|
+
var _iterator5 = _createForOfIteratorHelper(listenersSet),
|
|
649
|
+
_step5;
|
|
599
650
|
try {
|
|
600
|
-
for (
|
|
601
|
-
var _listener =
|
|
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
|
-
|
|
658
|
+
_iterator5.e(err);
|
|
608
659
|
} finally {
|
|
609
|
-
|
|
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
|
|
682
|
+
var _this5$_commandsClean;
|
|
632
683
|
commandsMap.delete(command);
|
|
633
|
-
(
|
|
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 {
|
|
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,
|
|
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)
|
|
@@ -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 {
|
|
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);
|
|
@@ -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
|
-
|
|
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.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
})
|
package/es/types/kernel.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
31
|
-
"@floating-ui/react": "^0.27.
|
|
32
|
-
"@lexical/code": "^0.
|
|
33
|
-
"@lexical/code-shiki": "^0.
|
|
34
|
-
"@lexical/dragon": "^0.
|
|
35
|
-
"@lexical/history": "^0.
|
|
36
|
-
"@lexical/link": "^0.
|
|
37
|
-
"@lexical/list": "^0.
|
|
38
|
-
"@lexical/rich-text": "^0.
|
|
39
|
-
"@lexical/selection": "^0.
|
|
40
|
-
"@lexical/table": "^0.
|
|
41
|
-
"@lexical/utils": "^0.
|
|
42
|
-
"@shikijs/core": "^3.
|
|
43
|
-
"@shikijs/engine-javascript": "^3.
|
|
44
|
-
"ahooks": "^3.9.
|
|
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.
|
|
46
|
+
"debug": "^4.4.3",
|
|
47
47
|
"eventemitter3": "^5.0.1",
|
|
48
|
-
"framer-motion": "^12.23.
|
|
48
|
+
"framer-motion": "^12.23.24",
|
|
49
49
|
"fuse.js": "^7.1.0",
|
|
50
|
-
"katex": "^0.16.
|
|
51
|
-
"lexical": "^0.
|
|
50
|
+
"katex": "^0.16.25",
|
|
51
|
+
"lexical": "^0.38.2",
|
|
52
52
|
"lodash-es": "^4.17.21",
|
|
53
|
-
"lucide-react": "^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.
|
|
59
|
+
"remark-cjk-friendly": "^1.2.3",
|
|
60
60
|
"remark-supersub": "^1.0.0",
|
|
61
|
-
"shiki": "^3.
|
|
61
|
+
"shiki": "^3.15.0",
|
|
62
62
|
"ts-key-enum": "^3.0.13",
|
|
63
63
|
"use-merge-value": "^1.2.0"
|
|
64
64
|
},
|