@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.
- package/es/common/sys.d.ts +2 -0
- package/es/common/sys.js +5 -0
- package/es/const/hotkey.d.ts +3 -0
- package/es/const/hotkey.js +58 -0
- package/es/editor-kernel/kernel.d.ts +3 -0
- package/es/editor-kernel/kernel.js +20 -1
- package/es/index.d.ts +2 -0
- package/es/index.js +4 -0
- package/es/plugins/code/plugin/index.d.ts +1 -0
- package/es/plugins/code/plugin/index.js +7 -6
- package/es/plugins/code/plugin/registry.d.ts +4 -1
- package/es/plugins/code/plugin/registry.js +15 -13
- package/es/plugins/code/react/CodeReactPlugin.js +5 -2
- package/es/plugins/code/react/type.d.ts +1 -0
- package/es/plugins/common/plugin/index.d.ts +1 -0
- package/es/plugins/common/plugin/index.js +4 -1
- package/es/plugins/common/plugin/register.d.ts +4 -1
- package/es/plugins/common/plugin/register.js +43 -14
- package/es/plugins/common/react/ReactPlainText.js +4 -1
- package/es/plugins/common/react/type.d.ts +1 -0
- package/es/plugins/link/node/LinkNode.js +1 -3
- package/es/plugins/link/plugin/index.d.ts +4 -0
- package/es/plugins/link/plugin/index.js +11 -1
- package/es/plugins/link/plugin/registry.d.ts +9 -0
- package/es/plugins/link/plugin/registry.js +108 -0
- package/es/plugins/link/react/ReactLinkPlugin.js +23 -50
- package/es/plugins/link/react/components/LinkEdit.js +41 -21
- package/es/plugins/link/react/components/LinkToolbar.js +58 -24
- package/es/plugins/link/react/type.d.ts +1 -0
- package/es/plugins/link/utils/index.d.ts +5 -0
- package/es/plugins/link/utils/index.js +14 -0
- package/es/plugins/list/plugin/index.d.ts +1 -0
- package/es/plugins/list/plugin/index.js +9 -76
- package/es/plugins/list/plugin/registry.d.ts +6 -0
- package/es/plugins/list/plugin/registry.js +98 -0
- package/es/plugins/list/react/ReactListPlugin.js +5 -2
- package/es/plugins/list/react/type.d.ts +1 -0
- package/es/plugins/math/react/component/MathEditor.js +41 -5
- package/es/plugins/math/react/component/MathEditorContainer.js +1 -0
- package/es/plugins/math/react/component/MathEditorContent.d.ts +2 -0
- package/es/plugins/math/react/component/MathEditorContent.js +7 -3
- package/es/react/ChatInputActions/components/ActionItem.js +8 -2
- package/es/react/ChatInputActions/components/ActionRender.js +10 -3
- package/es/react/ChatInputActions/type.d.ts +2 -1
- package/es/react/hooks/useEditorState/index.js +44 -8
- package/es/types/hotkey.d.ts +71 -0
- package/es/types/hotkey.js +71 -0
- package/es/types/kernel.d.ts +9 -0
- package/es/utils/hotkey/isHotkeyMatch.d.ts +1 -0
- package/es/utils/hotkey/isHotkeyMatch.js +9 -0
- package/es/utils/hotkey/parseHotkeys.d.ts +6 -0
- package/es/utils/hotkey/parseHotkeys.js +42 -0
- package/es/utils/hotkey/registerHotkey.d.ts +15 -0
- package/es/utils/hotkey/registerHotkey.js +32 -0
- package/package.json +2 -1
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
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); }
|
|
4
|
-
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; }
|
|
5
|
-
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; }
|
|
6
|
-
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; }
|
|
7
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
8
|
-
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); }
|
|
9
3
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
10
4
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
11
5
|
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); }
|
|
@@ -14,15 +8,14 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
|
|
|
14
8
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
15
9
|
import { computePosition, flip, offset, shift } from '@floating-ui/dom';
|
|
16
10
|
import { mergeRegister } from '@lexical/utils';
|
|
17
|
-
import { $getSelection, $isRangeSelection,
|
|
11
|
+
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_NORMAL } from 'lexical';
|
|
18
12
|
import { useLayoutEffect, useRef, useState } from 'react';
|
|
19
|
-
import { CONTROL_OR_META } from "../../../common/sys";
|
|
20
13
|
import { useLexicalEditor } from "../../../editor-kernel/react";
|
|
21
14
|
import { useLexicalComposerContext } from "../../../editor-kernel/react/react-context";
|
|
22
15
|
import { MarkdownPlugin } from "../../markdown";
|
|
23
|
-
import { $isLinkNode,
|
|
16
|
+
import { $isLinkNode, HOVER_LINK_COMMAND, HOVER_OUT_LINK_COMMAND } from "../node/LinkNode";
|
|
24
17
|
import { LinkPlugin } from "../plugin";
|
|
25
|
-
import { getSelectedNode
|
|
18
|
+
import { getSelectedNode } from "../utils";
|
|
26
19
|
import LinkEdit, { EDIT_LINK_COMMAND } from "./components/LinkEdit";
|
|
27
20
|
import LinkToolbar from "./components/LinkToolbar";
|
|
28
21
|
import { useStyles } from "./style";
|
|
@@ -31,6 +24,8 @@ import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
|
31
24
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
32
25
|
export var ReactLinkPlugin = function ReactLinkPlugin(_ref) {
|
|
33
26
|
var theme = _ref.theme,
|
|
27
|
+
_ref$enableHotkey = _ref.enableHotkey,
|
|
28
|
+
enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey,
|
|
34
29
|
validateUrl = _ref.validateUrl,
|
|
35
30
|
attributes = _ref.attributes;
|
|
36
31
|
var _useLexicalComposerCo = useLexicalComposerContext(),
|
|
@@ -51,9 +46,12 @@ export var ReactLinkPlugin = function ReactLinkPlugin(_ref) {
|
|
|
51
46
|
useLayoutEffect(function () {
|
|
52
47
|
editor.registerPlugin(MarkdownPlugin);
|
|
53
48
|
editor.registerPlugin(LinkPlugin, {
|
|
54
|
-
|
|
49
|
+
attributes: attributes,
|
|
50
|
+
enableHotkey: enableHotkey,
|
|
51
|
+
theme: theme || styles,
|
|
52
|
+
validateUrl: validateUrl
|
|
55
53
|
});
|
|
56
|
-
}, []);
|
|
54
|
+
}, [attributes, enableHotkey, styles, theme, validateUrl]);
|
|
57
55
|
useLexicalEditor(function (editor) {
|
|
58
56
|
return mergeRegister(editor.registerUpdateListener(function () {
|
|
59
57
|
var selection = editor.read(function () {
|
|
@@ -61,7 +59,7 @@ export var ReactLinkPlugin = function ReactLinkPlugin(_ref) {
|
|
|
61
59
|
});
|
|
62
60
|
if (!selection) return;
|
|
63
61
|
if ($isRangeSelection(selection)) {
|
|
64
|
-
// Update links
|
|
62
|
+
// Update links for UI components
|
|
65
63
|
editor.read(function () {
|
|
66
64
|
var node = getSelectedNode(selection);
|
|
67
65
|
var parent = node.getParent();
|
|
@@ -83,46 +81,12 @@ export var ReactLinkPlugin = function ReactLinkPlugin(_ref) {
|
|
|
83
81
|
} else {
|
|
84
82
|
state.current.isLink = false;
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
divRef.current.style.left = '-9999px';
|
|
88
|
-
divRef.current.style.top = '-9999px';
|
|
89
|
-
}
|
|
90
|
-
}), editor.registerCommand(TOGGLE_LINK_COMMAND, function (payload) {
|
|
91
|
-
if (payload === null) {
|
|
92
|
-
$toggleLink(payload);
|
|
93
|
-
return true;
|
|
94
|
-
} else if (typeof payload === 'string') {
|
|
95
|
-
if (validateUrl === undefined || validateUrl(payload)) {
|
|
96
|
-
$toggleLink(payload, attributes);
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
return false;
|
|
100
|
-
} else {
|
|
101
|
-
var url = payload.url,
|
|
102
|
-
target = payload.target,
|
|
103
|
-
rel = payload.rel,
|
|
104
|
-
title = payload.title;
|
|
105
|
-
$toggleLink(url, _objectSpread(_objectSpread({}, attributes), {}, {
|
|
106
|
-
rel: rel,
|
|
107
|
-
target: target,
|
|
108
|
-
title: title
|
|
109
|
-
}));
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
}, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DOWN_COMMAND, function (e) {
|
|
113
|
-
// ctrl + k / cmd + k
|
|
114
|
-
if (isModifierMatch(e, CONTROL_OR_META) && 'KeyK' === e.code) {
|
|
115
|
-
var isLink = state.current.isLink;
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
e.stopPropagation();
|
|
118
|
-
editor.dispatchCommand(TOGGLE_LINK_COMMAND, isLink ? null : sanitizeUrl('https://'));
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
return false;
|
|
122
|
-
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(HOVER_LINK_COMMAND, function (payload) {
|
|
84
|
+
}), editor.registerCommand(HOVER_LINK_COMMAND, function (payload) {
|
|
123
85
|
if (!payload.event.target || divRef.current === null) {
|
|
124
86
|
return false;
|
|
125
87
|
}
|
|
88
|
+
// Cancel any pending hide timers when hovering a link again
|
|
89
|
+
clearTimeout(clearTimerRef.current);
|
|
126
90
|
setLinkNode(payload.linkNode);
|
|
127
91
|
computePosition(payload.event.target, divRef.current, {
|
|
128
92
|
middleware: [offset(5), flip(), shift()],
|
|
@@ -157,6 +121,15 @@ export var ReactLinkPlugin = function ReactLinkPlugin(_ref) {
|
|
|
157
121
|
onMouseEnter: function onMouseEnter() {
|
|
158
122
|
clearTimeout(clearTimerRef.current);
|
|
159
123
|
},
|
|
124
|
+
onMouseLeave: function onMouseLeave() {
|
|
125
|
+
clearTimeout(clearTimerRef.current);
|
|
126
|
+
clearTimerRef.current = setTimeout(function () {
|
|
127
|
+
if (divRef.current) {
|
|
128
|
+
divRef.current.style.left = '-9999px';
|
|
129
|
+
divRef.current.style.top = '-9999px';
|
|
130
|
+
}
|
|
131
|
+
}, 300);
|
|
132
|
+
},
|
|
160
133
|
ref: divRef
|
|
161
134
|
}), /*#__PURE__*/_jsx(LinkEdit, {})]
|
|
162
135
|
});
|
|
@@ -42,6 +42,25 @@ var LinkEdit = function LinkEdit() {
|
|
|
42
42
|
var _useStyles = useStyles(),
|
|
43
43
|
styles = _useStyles.styles,
|
|
44
44
|
theme = _useStyles.theme;
|
|
45
|
+
|
|
46
|
+
// 取消编辑,不保存更改
|
|
47
|
+
var handleCancel = useCallback(function () {
|
|
48
|
+
var lexicalEditor = editor.getLexicalEditor();
|
|
49
|
+
if (!lexicalEditor) return;
|
|
50
|
+
|
|
51
|
+
// 将焦点返回到编辑器
|
|
52
|
+
lexicalEditor.focus();
|
|
53
|
+
|
|
54
|
+
// 隐藏编辑面板
|
|
55
|
+
if (divRef.current) {
|
|
56
|
+
divRef.current.style.left = '-9999px';
|
|
57
|
+
divRef.current.style.top = '-9999px';
|
|
58
|
+
}
|
|
59
|
+
linkNodeRef.current = null;
|
|
60
|
+
setLinkUrl('');
|
|
61
|
+
setLinkText('');
|
|
62
|
+
setLinkDom(null);
|
|
63
|
+
}, [editor]);
|
|
45
64
|
useEffect(function () {
|
|
46
65
|
if (!linkDom || !divRef.current) {
|
|
47
66
|
return;
|
|
@@ -59,6 +78,27 @@ var LinkEdit = function LinkEdit() {
|
|
|
59
78
|
});
|
|
60
79
|
}, [linkDom]);
|
|
61
80
|
|
|
81
|
+
// 点击编辑器外部时关闭面板
|
|
82
|
+
useEffect(function () {
|
|
83
|
+
var handlePointerDown = function handlePointerDown(event) {
|
|
84
|
+
if (!divRef.current) return;
|
|
85
|
+
var target = event.target;
|
|
86
|
+
if (!target) return;
|
|
87
|
+
// 点击面板内部忽略
|
|
88
|
+
if (divRef.current.contains(target)) return;
|
|
89
|
+
// 面板打开时(存在 linkDom)才触发关闭
|
|
90
|
+
if (linkDom) {
|
|
91
|
+
handleCancel();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
document.addEventListener('mousedown', handlePointerDown);
|
|
95
|
+
document.addEventListener('touchstart', handlePointerDown);
|
|
96
|
+
return function () {
|
|
97
|
+
document.removeEventListener('mousedown', handlePointerDown);
|
|
98
|
+
document.removeEventListener('touchstart', handlePointerDown);
|
|
99
|
+
};
|
|
100
|
+
}, [handleCancel, linkDom]);
|
|
101
|
+
|
|
62
102
|
// 提取提交逻辑到独立函数
|
|
63
103
|
var handleSubmit = useCallback(function () {
|
|
64
104
|
var lexicalEditor = editor.getLexicalEditor();
|
|
@@ -105,25 +145,6 @@ var LinkEdit = function LinkEdit() {
|
|
|
105
145
|
setLinkText('');
|
|
106
146
|
setLinkDom(null);
|
|
107
147
|
}, [editor, linkNodeRef, linkInputRef, linkTextInputRef]);
|
|
108
|
-
|
|
109
|
-
// 取消编辑,不保存更改
|
|
110
|
-
var handleCancel = useCallback(function () {
|
|
111
|
-
var lexicalEditor = editor.getLexicalEditor();
|
|
112
|
-
if (!lexicalEditor) return;
|
|
113
|
-
|
|
114
|
-
// 将焦点返回到编辑器
|
|
115
|
-
lexicalEditor.focus();
|
|
116
|
-
|
|
117
|
-
// 隐藏编辑面板
|
|
118
|
-
if (divRef.current) {
|
|
119
|
-
divRef.current.style.left = '-9999px';
|
|
120
|
-
divRef.current.style.top = '-9999px';
|
|
121
|
-
}
|
|
122
|
-
linkNodeRef.current = null;
|
|
123
|
-
setLinkUrl('');
|
|
124
|
-
setLinkText('');
|
|
125
|
-
setLinkDom(null);
|
|
126
|
-
}, [editor]);
|
|
127
148
|
var handleKeyDown = useCallback(function (event) {
|
|
128
149
|
var lexicalEditor = editor.getLexicalEditor();
|
|
129
150
|
if (!linkNodeRef.current || !linkInputRef.current || !linkTextInputRef.current || !lexicalEditor) {
|
|
@@ -253,8 +274,7 @@ var LinkEdit = function LinkEdit() {
|
|
|
253
274
|
icon: LinkIcon
|
|
254
275
|
}),
|
|
255
276
|
ref: linkInputRef,
|
|
256
|
-
value: linkUrl
|
|
257
|
-
variant: 'outlined'
|
|
277
|
+
value: linkUrl
|
|
258
278
|
})]
|
|
259
279
|
}), /*#__PURE__*/_jsx(Flexbox, {
|
|
260
280
|
className: styles.linkEditFooter,
|
|
@@ -5,13 +5,17 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
5
5
|
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; }
|
|
6
6
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
7
7
|
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); }
|
|
8
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
9
|
+
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); }
|
|
10
|
+
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; }
|
|
8
11
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
9
12
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
10
13
|
import { ActionIconGroup } from '@lobehub/ui';
|
|
14
|
+
import { $createRangeSelection, $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, $setSelection } from 'lexical';
|
|
11
15
|
import { EditIcon, ExternalLinkIcon, UnlinkIcon } from 'lucide-react';
|
|
12
|
-
import { memo } from 'react';
|
|
16
|
+
import { memo, useCallback } from 'react';
|
|
13
17
|
import { useTranslation } from "../../../../editor-kernel/react/useTranslation";
|
|
14
|
-
import { TOGGLE_LINK_COMMAND } from "../../node/LinkNode";
|
|
18
|
+
import { $isLinkNode, TOGGLE_LINK_COMMAND } from "../../node/LinkNode";
|
|
15
19
|
import { useStyles } from "../style";
|
|
16
20
|
import { EDIT_LINK_COMMAND } from "./LinkEdit";
|
|
17
21
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -22,28 +26,58 @@ var LinkToolbar = /*#__PURE__*/memo(function (_ref) {
|
|
|
22
26
|
var _useStyles = useStyles(),
|
|
23
27
|
styles = _useStyles.styles;
|
|
24
28
|
var t = useTranslation();
|
|
25
|
-
var handleEdit = function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
var handleEdit = useCallback(function () {
|
|
30
|
+
if (!linkNode) return;
|
|
31
|
+
editor.dispatchCommand(EDIT_LINK_COMMAND, {
|
|
32
|
+
linkNode: linkNode,
|
|
33
|
+
linkNodeDOM: editor.getElementByKey(linkNode.getKey())
|
|
34
|
+
});
|
|
35
|
+
}, [editor, linkNode]);
|
|
36
|
+
var handleRemove = useCallback(function () {
|
|
37
|
+
if (!linkNode) return;
|
|
38
|
+
editor.update(function () {
|
|
39
|
+
var node = $getNodeByKey(linkNode.getKey());
|
|
40
|
+
if (!$isLinkNode(node)) return;
|
|
41
|
+
|
|
42
|
+
// Try to create a range selection that covers the link's text
|
|
43
|
+
var selection = $getSelection();
|
|
44
|
+
if (!selection || !$isRangeSelection(selection)) {
|
|
45
|
+
$setSelection($createRangeSelection());
|
|
46
|
+
selection = $getSelection();
|
|
47
|
+
}
|
|
48
|
+
var first = node.getFirstDescendant();
|
|
49
|
+
var last = node.getLastDescendant();
|
|
50
|
+
if (selection && $isRangeSelection(selection) && $isTextNode(first) && $isTextNode(last)) {
|
|
51
|
+
selection.anchor.set(first.getKey(), 0, 'text');
|
|
52
|
+
selection.focus.set(last.getKey(), last.getTextContentSize(), 'text');
|
|
53
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Fallback: directly unwrap the link node preserving its children
|
|
58
|
+
var children = node.getChildren();
|
|
59
|
+
var _iterator = _createForOfIteratorHelper(children),
|
|
60
|
+
_step;
|
|
61
|
+
try {
|
|
62
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
63
|
+
var child = _step.value;
|
|
64
|
+
node.insertBefore(child);
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
_iterator.e(err);
|
|
68
|
+
} finally {
|
|
69
|
+
_iterator.f();
|
|
70
|
+
}
|
|
71
|
+
node.remove();
|
|
72
|
+
});
|
|
73
|
+
}, [editor, linkNode]);
|
|
74
|
+
var handleOpenLink = useCallback(function () {
|
|
75
|
+
if (!linkNode) return;
|
|
76
|
+
var url = editor.read(function () {
|
|
77
|
+
return linkNode.getURL();
|
|
78
|
+
});
|
|
79
|
+
window.open(url, '_blank');
|
|
80
|
+
}, [editor, linkNode]);
|
|
47
81
|
return /*#__PURE__*/_jsx(ActionIconGroup, _objectSpread({
|
|
48
82
|
className: styles.linkToolbar,
|
|
49
83
|
items: [{
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { ElementNode, RangeSelection, TextNode } from 'lexical';
|
|
2
2
|
export declare function sanitizeUrl(url: string): string;
|
|
3
3
|
export declare function validateUrl(url: string): boolean;
|
|
4
|
+
export declare function extractUrlFromText(text: string): {
|
|
5
|
+
index: number;
|
|
6
|
+
length: number;
|
|
7
|
+
url: string;
|
|
8
|
+
} | null;
|
|
4
9
|
export declare function getSelectedNode(selection: RangeSelection): TextNode | ElementNode;
|
|
@@ -20,6 +20,20 @@ export function validateUrl(url) {
|
|
|
20
20
|
// Maybe show a dialog where they user can type the URL before inserting it.
|
|
21
21
|
return url === 'https://' || urlRegExp.test(url);
|
|
22
22
|
}
|
|
23
|
+
export function extractUrlFromText(text) {
|
|
24
|
+
var _index;
|
|
25
|
+
var match = urlRegExp.exec(text);
|
|
26
|
+
if (!match) return null;
|
|
27
|
+
var raw = match[0];
|
|
28
|
+
var start = (_index = match.index) !== null && _index !== void 0 ? _index : text.indexOf(raw);
|
|
29
|
+
// Trim trailing punctuation that often follows inline links
|
|
30
|
+
var trimmed = raw.replace(/[\),\.:;\]]+$/, '');
|
|
31
|
+
return {
|
|
32
|
+
index: start,
|
|
33
|
+
length: trimmed.length,
|
|
34
|
+
url: trimmed
|
|
35
|
+
};
|
|
36
|
+
}
|
|
23
37
|
export function getSelectedNode(selection) {
|
|
24
38
|
var anchor = selection.anchor;
|
|
25
39
|
var focus = selection.focus;
|
|
@@ -13,20 +13,18 @@ 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 { $
|
|
16
|
+
import { $isListItemNode, $isListNode, ListItemNode, ListNode, registerList, registerListStrictIndentTransform } from '@lexical/list';
|
|
17
17
|
import { $getNearestNodeOfType } from '@lexical/utils';
|
|
18
18
|
import { cx } from 'antd-style';
|
|
19
|
-
import { $
|
|
19
|
+
import { $isRootNode } from 'lexical';
|
|
20
20
|
import { KernelPlugin } from "../../../editor-kernel/plugin";
|
|
21
21
|
import { IMarkdownShortCutService } from "../../markdown";
|
|
22
|
-
import {
|
|
22
|
+
import { listReplace } from "../utils";
|
|
23
23
|
import { registerCheckList } from "./checkList";
|
|
24
|
+
import { registerListCommands } from "./registry";
|
|
24
25
|
var ORDERED_LIST_REGEX = /^(\s*)(\d+)\.\s/;
|
|
25
26
|
var UNORDERED_LIST_REGEX = /^(\s*)[*+-]\s/;
|
|
26
27
|
var CHECK_LIST_REGEX = /^(\s*)(?:-\s)?\s?(\[(\s|x)?])\s/i;
|
|
27
|
-
|
|
28
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
29
|
-
|
|
30
28
|
export var ListPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
31
29
|
_inherits(ListPlugin, _KernelPlugin);
|
|
32
30
|
var _super = _createSuper(ListPlugin);
|
|
@@ -37,6 +35,7 @@ export var ListPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
37
35
|
_this = _super.call(this);
|
|
38
36
|
// Register the list nodes
|
|
39
37
|
_this.kernel = kernel;
|
|
38
|
+
_this.config = config;
|
|
40
39
|
kernel.registerNodes([ListNode, ListItemNode]);
|
|
41
40
|
// Register themes for list nodes
|
|
42
41
|
kernel.registerThemes({
|
|
@@ -121,79 +120,13 @@ export var ListPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
|
|
|
121
120
|
_createClass(ListPlugin, [{
|
|
122
121
|
key: "onInit",
|
|
123
122
|
value: function onInit(editor) {
|
|
123
|
+
var _this$config;
|
|
124
124
|
this.register(registerList(editor));
|
|
125
125
|
this.register(registerCheckList(editor));
|
|
126
126
|
this.register(registerListStrictIndentTransform(editor));
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
event.preventDefault();
|
|
133
|
-
var command = $indentOverTab(selection) ? event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND : INSERT_TAB_COMMAND;
|
|
134
|
-
return editor.dispatchCommand(command, undefined);
|
|
135
|
-
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(KEY_BACKSPACE_COMMAND, function (event) {
|
|
136
|
-
var _listItemNode$getPare;
|
|
137
|
-
var selection = $getSelection();
|
|
138
|
-
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
var anchor = selection.anchor;
|
|
142
|
-
if (anchor.offset !== 0) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
var anchorNode = anchor.getNode();
|
|
146
|
-
var listItemNode;
|
|
147
|
-
if ($isListItemNode(anchorNode)) {
|
|
148
|
-
listItemNode = anchorNode;
|
|
149
|
-
} else if ($isTextNode(anchorNode)) {
|
|
150
|
-
// Do not handle non-leading text nodes
|
|
151
|
-
if (anchorNode.getPreviousSibling()) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
var parent = anchorNode.getParentOrThrow();
|
|
155
|
-
if (!$isListItemNode(parent)) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
listItemNode = parent;
|
|
159
|
-
}
|
|
160
|
-
if (!listItemNode || !$isRootNode((_listItemNode$getPare = listItemNode.getParent()) === null || _listItemNode$getPare === void 0 ? void 0 : _listItemNode$getPare.getParent())) {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
var listNode = listItemNode.getParentOrThrow();
|
|
164
|
-
queueMicrotask(function () {
|
|
165
|
-
editor.update(function () {
|
|
166
|
-
// Add null check since listItemNode might be undefined in this closure
|
|
167
|
-
if (!listItemNode) return;
|
|
168
|
-
var newlistNode;
|
|
169
|
-
var isFirst = listItemNode.getPreviousSibling() === null;
|
|
170
|
-
if (isFirst) {
|
|
171
|
-
var _p = listItemNode.replace($createParagraphNode(), true);
|
|
172
|
-
_p.select(0, 0);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
var next = listItemNode.getNextSibling();
|
|
176
|
-
if (next) {
|
|
177
|
-
newlistNode = $createListNode(listNode.getListType(), listItemNode.getValue());
|
|
178
|
-
}
|
|
179
|
-
while (next && newlistNode) {
|
|
180
|
-
next.remove();
|
|
181
|
-
newlistNode.append(next);
|
|
182
|
-
next = next.getNextSibling();
|
|
183
|
-
}
|
|
184
|
-
var p = listItemNode.replace($createParagraphNode(), true);
|
|
185
|
-
p.remove();
|
|
186
|
-
listNode.insertAfter(p);
|
|
187
|
-
if (newlistNode) {
|
|
188
|
-
p.insertAfter(newlistNode);
|
|
189
|
-
}
|
|
190
|
-
p.select(0, 0);
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
event.stopImmediatePropagation();
|
|
194
|
-
event.preventDefault();
|
|
195
|
-
return true;
|
|
196
|
-
}, COMMAND_PRIORITY_LOW));
|
|
127
|
+
this.register(registerListCommands(editor, this.kernel, {
|
|
128
|
+
enableHotkey: (_this$config = this.config) === null || _this$config === void 0 ? void 0 : _this$config.enableHotkey
|
|
129
|
+
}));
|
|
197
130
|
}
|
|
198
131
|
}]);
|
|
199
132
|
return ListPlugin;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LexicalEditor } from 'lexical';
|
|
2
|
+
import { IEditorKernel } from "../../../types";
|
|
3
|
+
export interface ListRegistryOptions {
|
|
4
|
+
enableHotkey?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function registerListCommands(editor: LexicalEditor, kernel: IEditorKernel, options?: ListRegistryOptions): () => void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { $createListNode, $isListItemNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';
|
|
2
|
+
import { mergeRegister } from '@lexical/utils';
|
|
3
|
+
import { $createParagraphNode, $getSelection, $isRangeSelection, $isRootNode, $isTextNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, INDENT_CONTENT_COMMAND, INSERT_TAB_COMMAND, KEY_BACKSPACE_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND } from 'lexical';
|
|
4
|
+
import { HotkeyEnum } from "../../../types/hotkey";
|
|
5
|
+
import { $indentOverTab } from "../utils";
|
|
6
|
+
export function registerListCommands(editor, kernel, options) {
|
|
7
|
+
var _ref = options || {},
|
|
8
|
+
_ref$enableHotkey = _ref.enableHotkey,
|
|
9
|
+
enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
|
|
10
|
+
return mergeRegister(
|
|
11
|
+
// Hotkey registrations
|
|
12
|
+
kernel.registerHotkey(HotkeyEnum.BulletList, function () {
|
|
13
|
+
return editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
|
|
14
|
+
}, {
|
|
15
|
+
enabled: enableHotkey,
|
|
16
|
+
preventDefault: true,
|
|
17
|
+
stopImmediatePropagation: true
|
|
18
|
+
}), kernel.registerHotkey(HotkeyEnum.NumberList, function () {
|
|
19
|
+
return editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
|
|
20
|
+
}, {
|
|
21
|
+
enabled: enableHotkey,
|
|
22
|
+
preventDefault: true,
|
|
23
|
+
stopImmediatePropagation: true
|
|
24
|
+
}),
|
|
25
|
+
// Tab key command for indentation
|
|
26
|
+
editor.registerCommand(KEY_TAB_COMMAND, function (event) {
|
|
27
|
+
var selection = $getSelection();
|
|
28
|
+
if (!$isRangeSelection(selection)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
var command = $indentOverTab(selection) ? event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND : INSERT_TAB_COMMAND;
|
|
33
|
+
return editor.dispatchCommand(command, undefined);
|
|
34
|
+
}, COMMAND_PRIORITY_EDITOR),
|
|
35
|
+
// Backspace key command for list item handling
|
|
36
|
+
editor.registerCommand(KEY_BACKSPACE_COMMAND, function (event) {
|
|
37
|
+
var _listItemNode$getPare;
|
|
38
|
+
var selection = $getSelection();
|
|
39
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
var anchor = selection.anchor;
|
|
43
|
+
if (anchor.offset !== 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
var anchorNode = anchor.getNode();
|
|
47
|
+
var listItemNode;
|
|
48
|
+
if ($isListItemNode(anchorNode)) {
|
|
49
|
+
listItemNode = anchorNode;
|
|
50
|
+
} else if ($isTextNode(anchorNode)) {
|
|
51
|
+
// Do not handle non-leading text nodes
|
|
52
|
+
if (anchorNode.getPreviousSibling()) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
var parent = anchorNode.getParentOrThrow();
|
|
56
|
+
if (!$isListItemNode(parent)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
listItemNode = parent;
|
|
60
|
+
}
|
|
61
|
+
if (!listItemNode || !$isRootNode((_listItemNode$getPare = listItemNode.getParent()) === null || _listItemNode$getPare === void 0 ? void 0 : _listItemNode$getPare.getParent())) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
var listNode = listItemNode.getParentOrThrow();
|
|
65
|
+
queueMicrotask(function () {
|
|
66
|
+
editor.update(function () {
|
|
67
|
+
// Add null check since listItemNode might be undefined in this closure
|
|
68
|
+
if (!listItemNode) return;
|
|
69
|
+
var newlistNode;
|
|
70
|
+
var isFirst = listItemNode.getPreviousSibling() === null;
|
|
71
|
+
if (isFirst) {
|
|
72
|
+
var _p = listItemNode.replace($createParagraphNode(), true);
|
|
73
|
+
_p.select(0, 0);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
var next = listItemNode.getNextSibling();
|
|
77
|
+
if (next) {
|
|
78
|
+
newlistNode = $createListNode(listNode.getListType(), listItemNode.getValue());
|
|
79
|
+
}
|
|
80
|
+
while (next && newlistNode) {
|
|
81
|
+
next.remove();
|
|
82
|
+
newlistNode.append(next);
|
|
83
|
+
next = next.getNextSibling();
|
|
84
|
+
}
|
|
85
|
+
var p = listItemNode.replace($createParagraphNode(), true);
|
|
86
|
+
p.remove();
|
|
87
|
+
listNode.insertAfter(p);
|
|
88
|
+
if (newlistNode) {
|
|
89
|
+
p.insertAfter(newlistNode);
|
|
90
|
+
}
|
|
91
|
+
p.select(0, 0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
event.stopImmediatePropagation();
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
return true;
|
|
97
|
+
}, COMMAND_PRIORITY_LOW));
|
|
98
|
+
}
|
|
@@ -11,7 +11,9 @@ import { useLexicalComposerContext } from "../../../editor-kernel/react/react-co
|
|
|
11
11
|
import { MarkdownPlugin } from "../../markdown";
|
|
12
12
|
import { ListPlugin } from "../plugin";
|
|
13
13
|
import { useStyles } from "./style";
|
|
14
|
-
var ReactListPlugin = function ReactListPlugin() {
|
|
14
|
+
var ReactListPlugin = function ReactListPlugin(_ref) {
|
|
15
|
+
var _ref$enableHotkey = _ref.enableHotkey,
|
|
16
|
+
enableHotkey = _ref$enableHotkey === void 0 ? true : _ref$enableHotkey;
|
|
15
17
|
var _useLexicalComposerCo = useLexicalComposerContext(),
|
|
16
18
|
_useLexicalComposerCo2 = _slicedToArray(_useLexicalComposerCo, 1),
|
|
17
19
|
editor = _useLexicalComposerCo2[0];
|
|
@@ -20,9 +22,10 @@ var ReactListPlugin = function ReactListPlugin() {
|
|
|
20
22
|
useLayoutEffect(function () {
|
|
21
23
|
editor.registerPlugin(MarkdownPlugin);
|
|
22
24
|
editor.registerPlugin(ListPlugin, {
|
|
25
|
+
enableHotkey: enableHotkey,
|
|
23
26
|
theme: styles
|
|
24
27
|
});
|
|
25
|
-
}, []);
|
|
28
|
+
}, [enableHotkey, styles]);
|
|
26
29
|
return null;
|
|
27
30
|
};
|
|
28
31
|
ReactListPlugin.displayName = 'ReactListPlugin';
|