@lobehub/editor 1.5.10 → 1.6.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.
Files changed (55) hide show
  1. package/es/common/sys.d.ts +2 -0
  2. package/es/common/sys.js +5 -0
  3. package/es/const/hotkey.d.ts +3 -0
  4. package/es/const/hotkey.js +58 -0
  5. package/es/editor-kernel/kernel.d.ts +3 -0
  6. package/es/editor-kernel/kernel.js +20 -1
  7. package/es/index.d.ts +2 -0
  8. package/es/index.js +4 -0
  9. package/es/plugins/code/plugin/index.d.ts +1 -0
  10. package/es/plugins/code/plugin/index.js +7 -6
  11. package/es/plugins/code/plugin/registry.d.ts +4 -1
  12. package/es/plugins/code/plugin/registry.js +15 -13
  13. package/es/plugins/code/react/CodeReactPlugin.js +5 -2
  14. package/es/plugins/code/react/type.d.ts +1 -0
  15. package/es/plugins/common/plugin/index.d.ts +1 -0
  16. package/es/plugins/common/plugin/index.js +4 -1
  17. package/es/plugins/common/plugin/register.d.ts +4 -1
  18. package/es/plugins/common/plugin/register.js +43 -14
  19. package/es/plugins/common/react/ReactPlainText.js +4 -1
  20. package/es/plugins/common/react/type.d.ts +1 -0
  21. package/es/plugins/link/node/LinkNode.js +1 -3
  22. package/es/plugins/link/plugin/index.d.ts +4 -0
  23. package/es/plugins/link/plugin/index.js +11 -1
  24. package/es/plugins/link/plugin/registry.d.ts +9 -0
  25. package/es/plugins/link/plugin/registry.js +108 -0
  26. package/es/plugins/link/react/ReactLinkPlugin.js +23 -50
  27. package/es/plugins/link/react/components/LinkEdit.js +41 -21
  28. package/es/plugins/link/react/components/LinkToolbar.js +58 -24
  29. package/es/plugins/link/react/type.d.ts +1 -0
  30. package/es/plugins/link/utils/index.d.ts +5 -0
  31. package/es/plugins/link/utils/index.js +14 -0
  32. package/es/plugins/list/plugin/index.d.ts +1 -0
  33. package/es/plugins/list/plugin/index.js +9 -76
  34. package/es/plugins/list/plugin/registry.d.ts +6 -0
  35. package/es/plugins/list/plugin/registry.js +98 -0
  36. package/es/plugins/list/react/ReactListPlugin.js +5 -2
  37. package/es/plugins/list/react/type.d.ts +1 -0
  38. package/es/plugins/math/react/component/MathEditor.js +41 -5
  39. package/es/plugins/math/react/component/MathEditorContainer.js +1 -0
  40. package/es/plugins/math/react/component/MathEditorContent.d.ts +2 -0
  41. package/es/plugins/math/react/component/MathEditorContent.js +7 -3
  42. package/es/react/ChatInputActions/components/ActionItem.js +8 -2
  43. package/es/react/ChatInputActions/components/ActionRender.js +10 -3
  44. package/es/react/ChatInputActions/type.d.ts +2 -1
  45. package/es/react/hooks/useEditorState/index.js +44 -8
  46. package/es/types/hotkey.d.ts +71 -0
  47. package/es/types/hotkey.js +71 -0
  48. package/es/types/kernel.d.ts +9 -0
  49. package/es/utils/hotkey/isHotkeyMatch.d.ts +1 -0
  50. package/es/utils/hotkey/isHotkeyMatch.js +9 -0
  51. package/es/utils/hotkey/parseHotkeys.d.ts +6 -0
  52. package/es/utils/hotkey/parseHotkeys.js +42 -0
  53. package/es/utils/hotkey/registerHotkey.d.ts +15 -0
  54. package/es/utils/hotkey/registerHotkey.js +32 -0
  55. package/package.json +2 -1
@@ -4,10 +4,12 @@ export declare const isNode: boolean;
4
4
  export declare const isBrowser: boolean;
5
5
  export declare const macOSDetect: () => boolean;
6
6
  export declare const isMac: boolean;
7
+ /** @deprecated 请使用 @/const/hotkey 中的 PLATFORM_MODIFIER.MOD */
7
8
  export declare const CONTROL_OR_META: {
8
9
  ctrlKey: boolean;
9
10
  metaKey: boolean;
10
11
  };
12
+ /** @deprecated 请使用 @/const/hotkey 中的 PLATFORM_MODIFIER.MOD_SHIFT */
11
13
  export declare const CONTROL_OR_META_AND_SHIFT: {
12
14
  ctrlKey: boolean;
13
15
  metaKey: boolean;
package/es/common/sys.js CHANGED
@@ -17,10 +17,15 @@ export var macOSDetect = function macOSDetect() {
17
17
  return false;
18
18
  };
19
19
  export var isMac = macOSDetect();
20
+
21
+ // TODO: 这些常量已经迁移到 @/const/hotkey,建议使用新的统一定义
22
+ // 为了向后兼容性保留,但应该逐步迁移到新的 PLATFORM_MODIFIER
23
+ /** @deprecated 请使用 @/const/hotkey 中的 PLATFORM_MODIFIER.MOD */
20
24
  export var CONTROL_OR_META = {
21
25
  ctrlKey: !IS_APPLE,
22
26
  metaKey: IS_APPLE
23
27
  };
28
+ /** @deprecated 请使用 @/const/hotkey 中的 PLATFORM_MODIFIER.MOD_SHIFT */
24
29
  export var CONTROL_OR_META_AND_SHIFT = {
25
30
  ctrlKey: !IS_APPLE,
26
31
  metaKey: IS_APPLE,
@@ -0,0 +1,3 @@
1
+ import { HotkeyItem } from "../types/hotkey";
2
+ export type HotkeyRegistration = HotkeyItem[];
3
+ export declare const HOTKEYS_REGISTRATION: HotkeyRegistration;
@@ -0,0 +1,58 @@
1
+ import { COMMAND_PRIORITY_EDITOR } from 'lexical';
2
+ import { HotkeyEnum, HotkeyScopeEnum, KeyEnum } from "../types/hotkey";
3
+ var combineKeys = function combineKeys(keys) {
4
+ return keys.join('+');
5
+ };
6
+ export var HOTKEYS_REGISTRATION = [{
7
+ id: HotkeyEnum.Undo,
8
+ keys: combineKeys([KeyEnum.Mod, 'z']),
9
+ priority: COMMAND_PRIORITY_EDITOR,
10
+ scopes: [HotkeyScopeEnum.Format]
11
+ }, {
12
+ id: HotkeyEnum.Redo,
13
+ keys: combineKeys([KeyEnum.Mod, 'y']),
14
+ priority: COMMAND_PRIORITY_EDITOR,
15
+ scopes: [HotkeyScopeEnum.Format]
16
+ }, {
17
+ id: HotkeyEnum.Bold,
18
+ keys: combineKeys([KeyEnum.Mod, 'b']),
19
+ priority: COMMAND_PRIORITY_EDITOR,
20
+ scopes: [HotkeyScopeEnum.Format]
21
+ }, {
22
+ id: HotkeyEnum.Italic,
23
+ keys: combineKeys([KeyEnum.Mod, 'i']),
24
+ priority: COMMAND_PRIORITY_EDITOR,
25
+ scopes: [HotkeyScopeEnum.Format]
26
+ }, {
27
+ id: HotkeyEnum.Underline,
28
+ keys: combineKeys([KeyEnum.Mod, 'u']),
29
+ priority: COMMAND_PRIORITY_EDITOR,
30
+ scopes: [HotkeyScopeEnum.Format]
31
+ }, {
32
+ id: HotkeyEnum.Strikethrough,
33
+ keys: combineKeys([KeyEnum.Mod, KeyEnum.Shift, 'x']),
34
+ priority: COMMAND_PRIORITY_EDITOR,
35
+ scopes: [HotkeyScopeEnum.Format]
36
+ }, {
37
+ id: HotkeyEnum.CodeInline,
38
+ keys: combineKeys([KeyEnum.Mod, 'e']),
39
+ priority: COMMAND_PRIORITY_EDITOR,
40
+ scopes: [HotkeyScopeEnum.Format, HotkeyScopeEnum.Plugin]
41
+ }, {
42
+ id: HotkeyEnum.Link,
43
+ keys: combineKeys([KeyEnum.Mod, 'k']),
44
+ priority: COMMAND_PRIORITY_EDITOR,
45
+ scopes: [HotkeyScopeEnum.Format, HotkeyScopeEnum.Plugin]
46
+ },
47
+ // List hotkeys
48
+ {
49
+ id: HotkeyEnum.NumberList,
50
+ keys: combineKeys([KeyEnum.Mod, KeyEnum.Shift, '7']),
51
+ priority: COMMAND_PRIORITY_EDITOR,
52
+ scopes: [HotkeyScopeEnum.Insert, HotkeyScopeEnum.Plugin]
53
+ }, {
54
+ id: HotkeyEnum.BulletList,
55
+ keys: combineKeys([KeyEnum.Mod, KeyEnum.Shift, '8']),
56
+ priority: COMMAND_PRIORITY_EDITOR,
57
+ scopes: [HotkeyScopeEnum.Insert, HotkeyScopeEnum.Plugin]
58
+ }];
@@ -1,7 +1,9 @@
1
1
  import EventEmitter from 'eventemitter3';
2
2
  import { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
3
+ import { HotkeyId } from "../types/hotkey";
3
4
  import { IEditor, IEditorKernel, IEditorPluginConstructor, IPlugin, IServiceID } from "../types/kernel";
4
5
  import { ILocaleKeys } from "../types/locale";
6
+ import { HotkeyOptions, HotkeysEvent } from "../utils/hotkey/registerHotkey";
5
7
  import DataSource from './data-source';
6
8
  export declare class Kernel extends EventEmitter implements IEditorKernel {
7
9
  private static globalHotReloadMode;
@@ -87,5 +89,6 @@ export declare class Kernel extends EventEmitter implements IEditorKernel {
87
89
  cleanDocument(): void;
88
90
  private _commands;
89
91
  private _commandsClean;
92
+ registerHotkey(hotkeyId: HotkeyId, callback: (event: KeyboardEvent, handler: HotkeysEvent) => void, options?: HotkeyOptions): () => void;
90
93
  registerHighCommand<P>(command: LexicalCommand<P>, listener: CommandListener<P>, priority: CommandListenerPriority): () => void;
91
94
  }
@@ -20,11 +20,12 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
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
22
  import EventEmitter from 'eventemitter3';
23
- import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, createEditor } from 'lexical';
23
+ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, KEY_DOWN_COMMAND, createEditor } from 'lexical';
24
24
  import { get, merge, template, templateSettings } from 'lodash-es';
25
25
  import defaultLocale from "../locale";
26
26
  import { $isRootTextContentEmpty } from "../plugins/common/utils";
27
27
  import { createDebugLogger } from "../utils/debug";
28
+ import { getHotkeyById, registerHotkey as _registerHotkey } from "../utils/hotkey/registerHotkey";
28
29
  import { registerEvent } from "./event";
29
30
  import { KernelPlugin } from "./plugin";
30
31
  import { createEmptyEditorState } from "./utils";
@@ -558,6 +559,24 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
558
559
  value: function cleanDocument() {
559
560
  this.setDocument('text', '');
560
561
  }
562
+ }, {
563
+ key: "registerHotkey",
564
+ value: function registerHotkey(hotkeyId, callback) {
565
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
566
+ var lexicalEditor = this.editor;
567
+ if (!lexicalEditor) {
568
+ throw new Error('Editor is not initialized.');
569
+ }
570
+ var hotkey = getHotkeyById(hotkeyId);
571
+ if (!hotkey) return function () {
572
+ return false;
573
+ };
574
+ if (options.enabled === false) return function () {
575
+ return false;
576
+ };
577
+ this.logger.debug("\u2328\uFE0F Hotkey: ".concat(hotkey.id));
578
+ return lexicalEditor.registerCommand(KEY_DOWN_COMMAND, _registerHotkey(hotkey, callback, options), hotkey.priority);
579
+ }
561
580
  }, {
562
581
  key: "registerHighCommand",
563
582
  value: function registerHighCommand(command, listener, priority) {
package/es/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export * from './plugins/slash';
14
14
  export * from './plugins/table';
15
15
  export * from './plugins/upload';
16
16
  export type { IEditor } from './types';
17
+ export * from './types/hotkey';
18
+ export { getHotkeyById } from './utils/hotkey/registerHotkey';
17
19
  export { browserDebug, createDebugLogger, debugLogger, debugLoggers, devConsole, prodSafeLogger, } from './utils/debug';
18
20
  export { Kernel } from './editor-kernel/kernel';
19
21
  /**
package/es/index.js CHANGED
@@ -13,6 +13,10 @@ export * from "./plugins/mention";
13
13
  export * from "./plugins/slash";
14
14
  export * from "./plugins/table";
15
15
  export * from "./plugins/upload";
16
+ // Hotkey utilities
17
+ export * from "./types/hotkey";
18
+ export { getHotkeyById } from "./utils/hotkey/registerHotkey";
19
+
16
20
  // Debug utilities
17
21
  export { browserDebug, createDebugLogger, debugLogger, debugLoggers, devConsole, prodSafeLogger } from "./utils/debug";
18
22
 
@@ -1,5 +1,6 @@
1
1
  import { IEditorPluginConstructor } from "../../../types";
2
2
  export interface CodePluginOptions {
3
+ enableHotkey?: boolean;
3
4
  theme?: string;
4
5
  }
5
6
  export declare const CodePlugin: IEditorPluginConstructor<CodePluginOptions>;
@@ -18,28 +18,29 @@ import { IMarkdownShortCutService } from "../../markdown/service/shortcut";
18
18
  import { registerCodeInlineCommand } from "../command";
19
19
  import { CodeNode } from "../node/code";
20
20
  import { registerCodeInline } from "./registry";
21
-
22
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
23
-
24
21
  export var CodePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
25
22
  _inherits(CodePlugin, _KernelPlugin);
26
23
  var _super = _createSuper(CodePlugin);
27
- function CodePlugin(kernel, options) {
24
+ function CodePlugin(kernel, config) {
28
25
  var _this;
29
26
  _classCallCheck(this, CodePlugin);
30
27
  _this = _super.call(this);
31
28
  _this.kernel = kernel;
29
+ _this.config = config;
32
30
  kernel.registerNodes([CodeNode]);
33
31
  kernel.registerThemes({
34
- codeInline: (options === null || options === void 0 ? void 0 : options.theme) || 'editor-code'
32
+ codeInline: (config === null || config === void 0 ? void 0 : config.theme) || 'editor-code'
35
33
  });
36
34
  return _this;
37
35
  }
38
36
  _createClass(CodePlugin, [{
39
37
  key: "onInit",
40
38
  value: function onInit(editor) {
39
+ var _this$config;
41
40
  this.register(registerCodeInlineCommand(editor));
42
- this.register(registerCodeInline(editor, this.kernel));
41
+ this.register(registerCodeInline(editor, this.kernel, {
42
+ enableHotkey: (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enableHotkey
43
+ }));
43
44
  var markdownService = this.kernel.requireService(IMarkdownShortCutService);
44
45
  if (!markdownService) {
45
46
  return;
@@ -1,3 +1,6 @@
1
1
  import { LexicalEditor } from 'lexical';
2
2
  import { IEditorKernel } from "../../../types";
3
- export declare function registerCodeInline(editor: LexicalEditor, kernel: IEditorKernel): () => void;
3
+ export interface CodeRegistryOptions {
4
+ enableHotkey?: boolean;
5
+ }
6
+ export declare function registerCodeInline(editor: LexicalEditor, kernel: IEditorKernel, options?: CodeRegistryOptions): () => void;
@@ -2,13 +2,16 @@ 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, COMMAND_PRIORITY_EDITOR, KEY_DOWN_COMMAND, isModifierMatch } from 'lexical';
6
- import { CONTROL_OR_META } from "../../../common/sys";
5
+ import { $getNodeByKey } from 'lexical';
6
+ import { HotkeyEnum } from "../../../types/hotkey";
7
7
  import { INSERT_CODEINLINE_COMMAND } from "../command";
8
8
  import { CodeNode } from "../node/code";
9
- export function registerCodeInline(editor, kernel) {
10
- return mergeRegister(editor.registerUpdateListener(function (_ref) {
11
- var mutatedNodes = _ref.mutatedNodes;
9
+ export function registerCodeInline(editor, kernel, options) {
10
+ var _ref = options || {},
11
+ _ref$enableHotkey = _ref.enableHotkey,
12
+ enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
13
+ return mergeRegister(editor.registerUpdateListener(function (_ref2) {
14
+ var mutatedNodes = _ref2.mutatedNodes;
12
15
  var codeChanged = mutatedNodes === null || mutatedNodes === void 0 ? void 0 : mutatedNodes.get(CodeNode);
13
16
  var keys = (codeChanged === null || codeChanged === void 0 ? void 0 : codeChanged.keys()) || [];
14
17
  editor.read(function () {
@@ -37,12 +40,11 @@ export function registerCodeInline(editor, kernel) {
37
40
  _iterator.f();
38
41
  }
39
42
  });
40
- }), kernel.registerHighCommand(KEY_DOWN_COMMAND, function (payload) {
41
- // ctrl + e
42
- if (isModifierMatch(payload, CONTROL_OR_META) && payload.code === 'KeyE') {
43
- payload.preventDefault();
44
- return editor.dispatchCommand(INSERT_CODEINLINE_COMMAND, undefined);
45
- }
46
- return false;
47
- }, COMMAND_PRIORITY_EDITOR));
43
+ }), kernel.registerHotkey(HotkeyEnum.CodeInline, function () {
44
+ return editor.dispatchCommand(INSERT_CODEINLINE_COMMAND, undefined);
45
+ }, {
46
+ enabled: enableHotkey,
47
+ preventDefault: true,
48
+ stopImmediatePropagation: true
49
+ }));
48
50
  }
@@ -12,7 +12,9 @@ import { MarkdownPlugin } from "../../markdown";
12
12
  import { CodePlugin } from "../plugin";
13
13
  import { useStyles } from "./style";
14
14
  var ReactCodePlugin = function ReactCodePlugin(_ref) {
15
- var className = _ref.className;
15
+ var className = _ref.className,
16
+ _ref$enableHotkey = _ref.enableHotkey,
17
+ enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
16
18
  var _useLexicalComposerCo = useLexicalComposerContext(),
17
19
  _useLexicalComposerCo2 = _slicedToArray(_useLexicalComposerCo, 1),
18
20
  editor = _useLexicalComposerCo2[0];
@@ -22,9 +24,10 @@ var ReactCodePlugin = function ReactCodePlugin(_ref) {
22
24
  useLayoutEffect(function () {
23
25
  editor.registerPlugin(MarkdownPlugin);
24
26
  editor.registerPlugin(CodePlugin, {
27
+ enableHotkey: enableHotkey,
25
28
  theme: cx(styles.codeInline, className)
26
29
  });
27
- }, []);
30
+ }, [className, cx, enableHotkey, styles.codeInline]);
28
31
  return null;
29
32
  };
30
33
  ReactCodePlugin.displayName = 'ReactCodePlugin';
@@ -1,3 +1,4 @@
1
1
  export interface ReactCodePluginProps {
2
2
  className?: string;
3
+ enableHotkey?: boolean;
3
4
  }
@@ -1,5 +1,6 @@
1
1
  import { IEditorPluginConstructor } from "../../../types";
2
2
  export interface CommonPluginOptions {
3
+ enableHotkey?: boolean;
3
4
  theme?: {
4
5
  quote?: string;
5
6
  textBold?: string;
@@ -241,7 +241,10 @@ export var CommonPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
241
241
  }, {
242
242
  key: "onInit",
243
243
  value: function onInit(editor) {
244
- this.registerClears(registerRichText(editor), registerDragonSupport(editor), registerHistory(editor, createEmptyHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor));
244
+ var _this$config;
245
+ this.registerClears(registerRichText(editor), registerDragonSupport(editor), registerHistory(editor, createEmptyHistoryState(), 300), registerHeaderBackspace(editor), registerRichKeydown(editor, this.kernel, {
246
+ enableHotkey: (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enableHotkey
247
+ }), registerCommands(editor), registerBreakLineClick(editor), registerCursorNode(editor));
245
248
  }
246
249
  }, {
247
250
  key: "destroy",
@@ -3,4 +3,7 @@ import { IEditor } from "../../../types";
3
3
  export declare function $getAdjacentNode(focus: PointType, isBackward: boolean): null | LexicalNode;
4
4
  export declare function $getDownUpNode(focus: PointType, isUp: boolean): null | LexicalNode;
5
5
  export declare function registerHeaderBackspace(editor: LexicalEditor): () => void;
6
- export declare function registerRichKeydown(editor: LexicalEditor, kernel: IEditor): () => void;
6
+ export interface RichKeydownOptions {
7
+ enableHotkey?: boolean;
8
+ }
9
+ export declare function registerRichKeydown(editor: LexicalEditor, kernel: IEditor, options?: RichKeydownOptions): () => void;
@@ -1,8 +1,8 @@
1
1
  import { $isCodeHighlightNode, $isCodeNode } from '@lexical/code';
2
2
  import { $isHeadingNode } from '@lexical/rich-text';
3
3
  import { mergeRegister } from '@lexical/utils';
4
- import { $createNodeSelection, $createParagraphNode, $getRoot, $getSelection, $isDecoratorNode, $isElementNode, $isLineBreakNode, $isNodeSelection, $isRangeSelection, $isRootOrShadowRoot, $isTextNode, $setSelection, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_NORMAL, FORMAT_TEXT_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, isModifierMatch } from 'lexical';
5
- import { CONTROL_OR_META_AND_SHIFT } from "../../../common/sys";
4
+ import { $createNodeSelection, $createParagraphNode, $getRoot, $getSelection, $isDecoratorNode, $isElementNode, $isLineBreakNode, $isNodeSelection, $isRangeSelection, $isRootOrShadowRoot, $isTextNode, $setSelection, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_NORMAL, FORMAT_TEXT_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, REDO_COMMAND, UNDO_COMMAND } from 'lexical';
5
+ import { HotkeyEnum } from "../../../types/hotkey";
6
6
  function resolveElement(element, isBackward, focusOffset) {
7
7
  var parent = element.getParent();
8
8
  var offset = focusOffset;
@@ -132,18 +132,47 @@ export function registerHeaderBackspace(editor) {
132
132
  return false;
133
133
  }, COMMAND_PRIORITY_NORMAL);
134
134
  }
135
- export function registerRichKeydown(editor, kernel) {
136
- return mergeRegister(kernel.registerHighCommand(KEY_DOWN_COMMAND, function (payload) {
137
- // ctrl + shift + x
138
- if (isModifierMatch(payload, CONTROL_OR_META_AND_SHIFT) && payload.code === 'KeyX') {
139
- // Handle the custom key combination
140
- payload.stopImmediatePropagation();
141
- payload.preventDefault();
142
- editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough');
143
- return true;
144
- }
145
- return false;
146
- }, COMMAND_PRIORITY_EDITOR), kernel.registerHighCommand(KEY_ARROW_UP_COMMAND, function (event) {
135
+ export function registerRichKeydown(editor, kernel, options) {
136
+ var _ref = options || {},
137
+ _ref$enableHotkey = _ref.enableHotkey,
138
+ enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
139
+ return mergeRegister(kernel.registerHotkey(HotkeyEnum.Bold, function () {
140
+ return editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
141
+ }, {
142
+ enabled: enableHotkey,
143
+ preventDefault: true,
144
+ stopImmediatePropagation: true
145
+ }), kernel.registerHotkey(HotkeyEnum.Italic, function () {
146
+ return editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
147
+ }, {
148
+ enabled: enableHotkey,
149
+ preventDefault: true,
150
+ stopImmediatePropagation: true
151
+ }), kernel.registerHotkey(HotkeyEnum.Underline, function () {
152
+ return editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline');
153
+ }, {
154
+ enabled: enableHotkey,
155
+ preventDefault: true,
156
+ stopImmediatePropagation: true
157
+ }), kernel.registerHotkey(HotkeyEnum.Strikethrough, function () {
158
+ return editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough');
159
+ }, {
160
+ enabled: enableHotkey,
161
+ preventDefault: true,
162
+ stopImmediatePropagation: true
163
+ }), kernel.registerHotkey(HotkeyEnum.Undo, function () {
164
+ return editor.dispatchCommand(UNDO_COMMAND, undefined);
165
+ }, {
166
+ enabled: enableHotkey,
167
+ preventDefault: true,
168
+ stopImmediatePropagation: true
169
+ }), kernel.registerHotkey(HotkeyEnum.Redo, function () {
170
+ return editor.dispatchCommand(REDO_COMMAND, undefined);
171
+ }, {
172
+ enabled: enableHotkey,
173
+ preventDefault: true,
174
+ stopImmediatePropagation: true
175
+ }), kernel.registerHighCommand(KEY_ARROW_UP_COMMAND, function (event) {
147
176
  var selection = $getSelection();
148
177
  if ($isNodeSelection(selection)) {
149
178
  // If selection is on a node, let's try and move selection
@@ -34,6 +34,8 @@ var ReactPlainText = /*#__PURE__*/memo(function (_ref) {
34
34
  onChange = _ref.onChange,
35
35
  className = _ref.className,
36
36
  variant = _ref.variant,
37
+ _ref$enableHotkey = _ref.enableHotkey,
38
+ enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey,
37
39
  onKeyDown = _ref.onKeyDown,
38
40
  onFocus = _ref.onFocus,
39
41
  onBlur = _ref.onBlur,
@@ -79,9 +81,10 @@ var ReactPlainText = /*#__PURE__*/memo(function (_ref) {
79
81
  useLayoutEffect(function () {
80
82
  editor.registerPlugin(MarkdownPlugin);
81
83
  editor.registerPlugin(CommonPlugin, {
84
+ enableHotkey: enableHotkey,
82
85
  theme: restTheme ? _objectSpread(_objectSpread({}, themeStyles), restTheme) : themeStyles
83
86
  });
84
- }, [editor, restTheme, themeStyles]);
87
+ }, [editor, enableHotkey, restTheme, themeStyles]);
85
88
  useEffect(function () {
86
89
  var _editor$getLexicalEdi;
87
90
  var container = editorContainerRef.current;
@@ -10,6 +10,7 @@ export interface ReactPlainTextProps {
10
10
  autoFocus?: boolean;
11
11
  children: ReactElement<ReactEditorContentProps>;
12
12
  className?: string;
13
+ enableHotkey?: boolean;
13
14
  onBlur?: (props: {
14
15
  editor: IEditor;
15
16
  event: FocusEvent<HTMLDivElement>;
@@ -715,7 +715,5 @@ export function formatUrl(url) {
715
715
  else if (PHONE_NUMBER_REGEX.test(url)) {
716
716
  return "tel:".concat(url);
717
717
  }
718
-
719
- // For everything else, return with https:// prefix
720
- return "https://".concat(url);
718
+ return url;
721
719
  }
@@ -1,8 +1,12 @@
1
1
  import { IEditorPluginConstructor } from "../../../types";
2
+ import { LinkAttributes } from '../node/LinkNode';
2
3
  export interface LinkPluginOptions {
4
+ attributes?: LinkAttributes;
5
+ enableHotkey?: boolean;
3
6
  linkRegex?: RegExp;
4
7
  theme?: {
5
8
  link?: string;
6
9
  };
10
+ validateUrl?: (url: string) => boolean;
7
11
  }
8
12
  export declare const LinkPlugin: IEditorPluginConstructor<LinkPluginOptions>;
@@ -24,6 +24,7 @@ import { KernelPlugin } from "../../../editor-kernel/plugin";
24
24
  import { IMarkdownShortCutService } from "../../markdown";
25
25
  import { INSERT_LINK_COMMAND, registerLinkCommand } from "../command";
26
26
  import { $createLinkNode, $isLinkNode, AutoLinkNode, LinkNode } from "../node/LinkNode";
27
+ import { registerLinkCommands } from "./registry";
27
28
  export var LinkPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
28
29
  _inherits(LinkPlugin, _KernelPlugin);
29
30
  var _super = _createSuper(LinkPlugin);
@@ -35,6 +36,7 @@ export var LinkPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
35
36
  // Register the link nodes
36
37
  _defineProperty(_assertThisInitialized(_this), "linkRegex", /^https?:\/\/\S+$/);
37
38
  _this.kernel = kernel;
39
+ _this.config = config;
38
40
  kernel.registerNodes([LinkNode, AutoLinkNode]);
39
41
  if (config !== null && config !== void 0 && config.theme) {
40
42
  kernel.registerThemes(config.theme);
@@ -71,8 +73,16 @@ export var LinkPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
71
73
  _createClass(LinkPlugin, [{
72
74
  key: "onInit",
73
75
  value: function onInit(editor) {
74
- var _this2 = this;
76
+ var _this$config,
77
+ _this$config2,
78
+ _this$config3,
79
+ _this2 = this;
75
80
  this.register(registerLinkCommand(editor));
81
+ this.register(registerLinkCommands(editor, this.kernel, {
82
+ attributes: (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.attributes,
83
+ enableHotkey: (_this$config2 = this.config) === null || _this$config2 === void 0 ? void 0 : _this$config2.enableHotkey,
84
+ validateUrl: (_this$config3 = this.config) === null || _this$config3 === void 0 ? void 0 : _this$config3.validateUrl
85
+ }));
76
86
  this.register(editor.registerCommand(PASTE_COMMAND, function (payload) {
77
87
  var clipboardData = payload.clipboardData;
78
88
  if (clipboardData && clipboardData.types && clipboardData.types.length === 1 && clipboardData.types[0] === 'text/plain') {
@@ -0,0 +1,9 @@
1
+ import { LexicalEditor } from 'lexical';
2
+ import { IEditorKernel } from "../../../types";
3
+ import { LinkAttributes } from '../node/LinkNode';
4
+ export interface LinkRegistryOptions {
5
+ attributes?: LinkAttributes;
6
+ enableHotkey?: boolean;
7
+ validateUrl?: (url: string) => boolean;
8
+ }
9
+ export declare function registerLinkCommands(editor: LexicalEditor, kernel: IEditorKernel, options?: LinkRegistryOptions): () => void;
@@ -0,0 +1,108 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ 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; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
+ 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); }
7
+ import { mergeRegister } from '@lexical/utils';
8
+ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_LOW } from 'lexical';
9
+ import { HotkeyEnum } from "../../../types/hotkey";
10
+ import { $isLinkNode, $toggleLink, TOGGLE_LINK_COMMAND, formatUrl } from "../node/LinkNode";
11
+ import { extractUrlFromText, getSelectedNode, sanitizeUrl } from "../utils";
12
+ export function registerLinkCommands(editor, kernel, options) {
13
+ var _ref = options || {},
14
+ validateUrl = _ref.validateUrl,
15
+ attributes = _ref.attributes,
16
+ _ref$enableHotkey = _ref.enableHotkey,
17
+ enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
18
+ var state = {
19
+ isLink: false
20
+ };
21
+ var registrations = [editor.registerUpdateListener(function () {
22
+ var selection = editor.read(function () {
23
+ return $getSelection();
24
+ });
25
+ if (!selection) return;
26
+ if ($isRangeSelection(selection)) {
27
+ editor.read(function () {
28
+ var node = getSelectedNode(selection);
29
+ var parent = node.getParent();
30
+ var isLink = $isLinkNode(parent) || $isLinkNode(node);
31
+ state.isLink = isLink;
32
+ });
33
+ } else {
34
+ state.isLink = false;
35
+ }
36
+ }), editor.registerCommand(TOGGLE_LINK_COMMAND, function (payload) {
37
+ if (payload === null) {
38
+ $toggleLink(payload);
39
+ return true;
40
+ } else if (typeof payload === 'string') {
41
+ if (validateUrl === undefined || validateUrl(payload)) {
42
+ $toggleLink(payload, attributes);
43
+ return true;
44
+ }
45
+ return false;
46
+ } else {
47
+ var _url = payload.url,
48
+ target = payload.target,
49
+ rel = payload.rel,
50
+ title = payload.title;
51
+ $toggleLink(_url, _objectSpread(_objectSpread({}, attributes), {}, {
52
+ rel: rel,
53
+ target: target,
54
+ title: title
55
+ }));
56
+ return true;
57
+ }
58
+ }, COMMAND_PRIORITY_LOW)];
59
+
60
+ // 注册热键,通过 enabled 选项控制
61
+ registrations.push(kernel.registerHotkey(HotkeyEnum.Link, function () {
62
+ var isLink = state.isLink;
63
+ if (isLink) {
64
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
65
+ return;
66
+ }
67
+ var nextUrl = sanitizeUrl('https://');
68
+ var expandTo = null;
69
+ editor.getEditorState().read(function () {
70
+ var selection = $getSelection();
71
+ if ($isRangeSelection(selection)) {
72
+ if (!selection.isCollapsed()) {
73
+ var text = selection.getTextContent().trim();
74
+ var maybeUrl = formatUrl(text);
75
+ if (validateUrl !== null && validateUrl !== void 0 && validateUrl(maybeUrl)) {
76
+ nextUrl = maybeUrl;
77
+ }
78
+ } else {
79
+ var lineText = selection.anchor.getNode().getTextContent();
80
+ var found = extractUrlFromText(lineText);
81
+ if (found && validateUrl !== null && validateUrl !== void 0 && validateUrl(formatUrl(found.url))) {
82
+ nextUrl = formatUrl(found.url);
83
+ expandTo = {
84
+ index: found.index,
85
+ length: found.length
86
+ };
87
+ }
88
+ }
89
+ }
90
+ });
91
+ editor.update(function () {
92
+ if (expandTo) {
93
+ var selection = $getSelection();
94
+ if ($isRangeSelection(selection)) {
95
+ var anchorNode = selection.anchor.getNode();
96
+ selection.anchor.set(anchorNode.getKey(), expandTo.index, 'text');
97
+ selection.focus.set(anchorNode.getKey(), expandTo.index + expandTo.length, 'text');
98
+ }
99
+ }
100
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, nextUrl);
101
+ });
102
+ }, {
103
+ enabled: enableHotkey,
104
+ preventDefault: true,
105
+ stopPropagation: true
106
+ }));
107
+ return mergeRegister.apply(void 0, registrations);
108
+ }