@cgboiler/biz-basic 1.0.47 → 1.0.49
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/index.d.ts +1 -1
- package/es/index.js +1 -1
- package/es/rich-text-editor/RichTextEditor.d.ts +5 -1
- package/es/rich-text-editor/RichTextEditor.js +37 -2
- package/es/rich-text-editor/index.css +1 -1
- package/es/rich-text-editor/index.less +12 -1
- package/es/rich-text-editor/types.d.ts +15 -0
- package/es/rich-text-editor/useExtensions.d.ts +2 -7
- package/es/rich-text-editor/useExtensions.js +177 -150
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/rich-text-editor/RichTextEditor.d.ts +5 -1
- package/lib/rich-text-editor/RichTextEditor.js +37 -2
- package/lib/rich-text-editor/index.css +1 -1
- package/lib/rich-text-editor/index.less +12 -1
- package/lib/rich-text-editor/types.d.ts +15 -0
- package/lib/rich-text-editor/useExtensions.d.ts +2 -7
- package/lib/rich-text-editor/useExtensions.js +176 -149
- package/package.json +1 -1
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core';
|
|
1
|
+
import { Extension, Mark } from '@tiptap/core';
|
|
2
2
|
/**
|
|
3
3
|
* useExtensions
|
|
4
4
|
* - 功能:构建并返回 TipTap 编辑器使用的扩展集合。
|
|
5
|
-
* - 参数说明:
|
|
6
|
-
* - props: 组件属性对象,至少应包含占位符 `placeholder` 等。
|
|
7
|
-
* - emit: 事件发送函数,用于向父组件触发富文本相关事件(如 hashTag-triggered / hashTag-input / hashTag-exit)。
|
|
8
|
-
* - 返回值:Extension[] 扩展数组,用于初始化 TipTap 编辑器。
|
|
9
|
-
* - 异常:无显式抛出;若内部命令执行失败(例如插入内容时)可能由 TipTap 抛出异常,应在上层统一处理。
|
|
10
5
|
*/
|
|
11
|
-
export declare function useExtensions({ props, emit }: any): (import("@tiptap/core").Node<any, any> | import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any> | Extension<
|
|
6
|
+
export declare function useExtensions({ props, emit }: any): (import("@tiptap/core").Node<any, any> | Mark<any, any> | import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any> | Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | Extension<any, any> | Mark<import("@tiptap/extension-text-style").TextStyleOptions, any> | Extension<import("@tiptap/extension-text-style").ColorOptions, any> | Extension<import("tiptap-markdown").MarkdownOptions, import("tiptap-markdown").MarkdownStorage> | import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any> | Extension<import("@tiptap/extension-table").TableKitOptions, any> | Extension<import("@tiptap/extensions").PlaceholderOptions, any> | Extension<import("@tiptap/extension-list").ListKitOptions, any>)[];
|
|
@@ -42,29 +42,70 @@ var import_core = require("@tiptap/core");
|
|
|
42
42
|
var import_HtmlBlock = __toESM(require("./extensions/HtmlBlock"));
|
|
43
43
|
var import_extensions = require("@tiptap/extensions");
|
|
44
44
|
function useExtensions({ props, emit }) {
|
|
45
|
-
let spentHashTagPositions = [];
|
|
46
|
-
let spentMentionPositions = [];
|
|
47
45
|
let activeEditor = null;
|
|
46
|
+
const ConsumedTrigger = import_core.Mark.create({
|
|
47
|
+
name: "consumedTrigger",
|
|
48
|
+
keepOnSplit: false,
|
|
49
|
+
// 保证在标记后继续输入时不延续标记
|
|
50
|
+
parseHTML() {
|
|
51
|
+
return [{ tag: "span[data-consumed-trigger]" }];
|
|
52
|
+
},
|
|
53
|
+
renderHTML({ HTMLAttributes }) {
|
|
54
|
+
return [
|
|
55
|
+
"span",
|
|
56
|
+
(0, import_core.mergeAttributes)(HTMLAttributes, {
|
|
57
|
+
"data-consumed-trigger": "true",
|
|
58
|
+
style: "color: inherit;"
|
|
59
|
+
}),
|
|
60
|
+
0
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const checkConsumed = (state, range) => {
|
|
65
|
+
const { doc, schema } = state;
|
|
66
|
+
const markType = schema.marks.consumedTrigger;
|
|
67
|
+
if (!markType)
|
|
68
|
+
return false;
|
|
69
|
+
let isConsumed = false;
|
|
70
|
+
doc.nodesBetween(range.from, range.to, (node) => {
|
|
71
|
+
if (node.marks.some((m) => m.type === markType)) {
|
|
72
|
+
isConsumed = true;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return isConsumed;
|
|
76
|
+
};
|
|
77
|
+
const markAsConsumed = (editor, range, char) => {
|
|
78
|
+
if (!editor || !range || range.from === void 0)
|
|
79
|
+
return;
|
|
80
|
+
try {
|
|
81
|
+
const { doc } = editor.state;
|
|
82
|
+
const actualChar = doc.textBetween(range.from, range.from + 1);
|
|
83
|
+
if (actualChar === char) {
|
|
84
|
+
editor.chain().setMeta("addToHistory", false).setTextSelection({ from: range.from, to: range.from + 1 }).setMark("consumedTrigger").setTextSelection(editor.state.selection.to).unsetMark("consumedTrigger").run();
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
}
|
|
88
|
+
};
|
|
48
89
|
const HashTag = import_extension_mention.default.extend({
|
|
49
90
|
name: "hashTag",
|
|
50
|
-
renderHTML({ node
|
|
91
|
+
renderHTML({ node }) {
|
|
51
92
|
var _a, _b, _c, _d;
|
|
52
93
|
const id = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.id) != null ? _b : "";
|
|
53
94
|
const label = (_d = (_c = node == null ? void 0 : node.attrs) == null ? void 0 : _c.label) != null ? _d : "";
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
95
|
+
return [
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
class: "hash-tag",
|
|
99
|
+
"data-type": "hashTag",
|
|
100
|
+
"data-id": id,
|
|
101
|
+
"data-label": label,
|
|
102
|
+
"data-hash-tag": "#",
|
|
103
|
+
contenteditable: "false"
|
|
104
|
+
},
|
|
105
|
+
`#${label}`
|
|
106
|
+
];
|
|
63
107
|
}
|
|
64
108
|
}).configure({
|
|
65
|
-
HTMLAttributes: {
|
|
66
|
-
class: "hash-tag"
|
|
67
|
-
},
|
|
68
109
|
deleteTriggerWithBackspace: true,
|
|
69
110
|
suggestion: {
|
|
70
111
|
char: "#",
|
|
@@ -73,13 +114,10 @@ function useExtensions({ props, emit }) {
|
|
|
73
114
|
/**
|
|
74
115
|
* allow
|
|
75
116
|
* - 功能:判断是否允许触发建议态。
|
|
76
|
-
* -
|
|
117
|
+
* - 若该字符带有 consumedTrigger 标记,说明此前已触发过或用户选择忽略,则不再触发建议。
|
|
77
118
|
*/
|
|
78
119
|
allow: ({ state, range }) => {
|
|
79
|
-
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
return true;
|
|
120
|
+
return !checkConsumed(state, range);
|
|
83
121
|
},
|
|
84
122
|
render() {
|
|
85
123
|
let activeRange = null;
|
|
@@ -107,111 +145,139 @@ function useExtensions({ props, emit }) {
|
|
|
107
145
|
activeEditor = editor || activeEditor;
|
|
108
146
|
emit("hashTag-input", query != null ? query : "");
|
|
109
147
|
},
|
|
110
|
-
/**
|
|
111
|
-
* onKeyDown
|
|
112
|
-
* - 功能:在建议态期间侦测用户键盘行为并记录“非连续输入”的退出原因。
|
|
113
|
-
* - 参数说明:
|
|
114
|
-
* - event: KeyboardEvent 当前键盘事件对象。
|
|
115
|
-
* - 返回值:boolean 始终返回 false,交由默认逻辑处理(从而触发 onExit)。
|
|
116
|
-
* - 异常:无。
|
|
117
|
-
*/
|
|
118
148
|
onKeyDown({ event }) {
|
|
119
|
-
const isSpaceKey =
|
|
120
|
-
event.keyCode === 32 ||
|
|
121
|
-
event.code === "Space";
|
|
149
|
+
const isSpaceKey = [" ", "Space", "Spacebar"].includes(event.key) || // @ts-ignore
|
|
150
|
+
event.keyCode === 32 || event.code === "Space";
|
|
122
151
|
if (isSpaceKey) {
|
|
123
152
|
exitCause = "space";
|
|
124
|
-
return false;
|
|
125
153
|
}
|
|
126
154
|
return false;
|
|
127
155
|
},
|
|
128
|
-
|
|
129
|
-
* onExit
|
|
130
|
-
* - 功能:建议态结束时向外部发送退出事件,并尽可能准确地判断退出原因。
|
|
131
|
-
* - 设计考量:
|
|
132
|
-
* - 安卓设备上软键盘可能不触发标准 keydown 空格;此时通过检查当前选择位置前一个字符是否为空格来回溯判断。
|
|
133
|
-
* - 参数:无。
|
|
134
|
-
* - 返回值:无(通过 emit 派发事件)。
|
|
135
|
-
* - 异常:内部读取选择/文档时若发生异常,捕获后保持原有退出原因,不影响外部流程。
|
|
136
|
-
*/
|
|
137
|
-
onExit({ range }) {
|
|
156
|
+
onExit({ editor, range }) {
|
|
138
157
|
var _a, _b, _c, _d, _e;
|
|
139
158
|
try {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (prevChar === " ") {
|
|
146
|
-
exitCause = "space";
|
|
147
|
-
}
|
|
159
|
+
const sel = (_a = editor.state) == null ? void 0 : _a.selection;
|
|
160
|
+
const from = (_b = sel == null ? void 0 : sel.from) != null ? _b : 0;
|
|
161
|
+
const prevChar = (_e = (_d = (_c = editor.state) == null ? void 0 : _c.doc) == null ? void 0 : _d.textBetween(Math.max(from - 1, 0), from, "\0", "\0")) != null ? _e : "";
|
|
162
|
+
if (prevChar === " ") {
|
|
163
|
+
exitCause = "space";
|
|
148
164
|
}
|
|
149
165
|
} catch (e) {
|
|
150
166
|
}
|
|
151
|
-
|
|
152
|
-
spentHashTagPositions.push(range.from);
|
|
153
|
-
}
|
|
167
|
+
markAsConsumed(editor, range, "#");
|
|
154
168
|
activeRange = null;
|
|
155
169
|
activeEditor = null;
|
|
156
|
-
|
|
170
|
+
emit("hashTag-exit", {
|
|
157
171
|
reason: exitCause,
|
|
158
172
|
nonContiguous: exitCause === "space"
|
|
159
|
-
};
|
|
160
|
-
emit("hashTag-exit", payload);
|
|
173
|
+
});
|
|
161
174
|
}
|
|
162
175
|
};
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
178
|
});
|
|
166
|
-
const
|
|
167
|
-
name: "
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
179
|
+
const CustomContent = import_extension_mention.default.extend({
|
|
180
|
+
name: "customContent",
|
|
181
|
+
addAttributes() {
|
|
182
|
+
return {
|
|
183
|
+
id: {
|
|
184
|
+
default: null,
|
|
185
|
+
parseHTML: (element) => element.getAttribute("data-id"),
|
|
186
|
+
renderHTML: (attributes) => {
|
|
187
|
+
if (!attributes.id) {
|
|
188
|
+
return {};
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
"data-id": attributes.id
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
label: {
|
|
196
|
+
default: null,
|
|
197
|
+
parseHTML: (element) => element.getAttribute("file-label"),
|
|
198
|
+
renderHTML: (attributes) => {
|
|
199
|
+
if (!attributes.label) {
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
"file-label": attributes.label
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
obj: {
|
|
208
|
+
default: null,
|
|
209
|
+
parseHTML: (element) => {
|
|
210
|
+
const objStr = element.getAttribute("obj");
|
|
211
|
+
return objStr ? JSON.parse(objStr) : null;
|
|
212
|
+
},
|
|
213
|
+
renderHTML: (attributes) => {
|
|
214
|
+
if (!attributes.obj) {
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
obj: JSON.stringify(attributes.obj)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
color: {
|
|
223
|
+
default: null,
|
|
224
|
+
parseHTML: (element) => element.getAttribute("data-color"),
|
|
225
|
+
renderHTML: (attributes) => {
|
|
226
|
+
if (!attributes.color)
|
|
227
|
+
return {};
|
|
228
|
+
return { "data-color": attributes.color };
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
hoverColor: {
|
|
232
|
+
default: null,
|
|
233
|
+
parseHTML: (element) => element.getAttribute("data-hover-color"),
|
|
234
|
+
renderHTML: (attributes) => {
|
|
235
|
+
if (!attributes.hoverColor)
|
|
236
|
+
return {};
|
|
237
|
+
return { "data-hover-color": attributes.hoverColor };
|
|
238
|
+
}
|
|
199
239
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
renderHTML({ node }) {
|
|
243
|
+
var _a, _b, _c, _d, _e, _f;
|
|
244
|
+
const obj = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.obj) != null ? _b : {};
|
|
245
|
+
const label = (_d = (_c = node == null ? void 0 : node.attrs) == null ? void 0 : _c.label) != null ? _d : "";
|
|
246
|
+
const color = (_e = node == null ? void 0 : node.attrs) == null ? void 0 : _e.color;
|
|
247
|
+
const hoverColor = (_f = node == null ? void 0 : node.attrs) == null ? void 0 : _f.hoverColor;
|
|
248
|
+
const styleParts = [];
|
|
249
|
+
if (color)
|
|
250
|
+
styleParts.push(`--custom-content-color: ${color}`);
|
|
251
|
+
if (hoverColor)
|
|
252
|
+
styleParts.push(`--custom-content-hover-color: ${hoverColor}`);
|
|
253
|
+
return [
|
|
254
|
+
"span",
|
|
255
|
+
{
|
|
256
|
+
class: "custom-content",
|
|
257
|
+
"data-type": "custom-content",
|
|
258
|
+
obj: JSON.stringify(obj),
|
|
259
|
+
"file-label": label,
|
|
260
|
+
"data-color": color,
|
|
261
|
+
"data-hover-color": hoverColor,
|
|
262
|
+
style: styleParts.length ? styleParts.join(";") : void 0,
|
|
263
|
+
contenteditable: "false"
|
|
264
|
+
},
|
|
265
|
+
label
|
|
266
|
+
];
|
|
202
267
|
}
|
|
203
268
|
});
|
|
204
269
|
const extensions = [
|
|
205
270
|
import_starter_kit.default,
|
|
206
271
|
import_HtmlBlock.default,
|
|
207
|
-
|
|
272
|
+
ConsumedTrigger,
|
|
273
|
+
// Video input rule extension
|
|
208
274
|
import_core.Extension.create({
|
|
209
275
|
name: "videoInputRule",
|
|
210
276
|
addInputRules() {
|
|
211
277
|
return [
|
|
212
278
|
new import_core.InputRule({
|
|
213
279
|
find: /!video\(([^)]+)\)\s/,
|
|
214
|
-
handler: ({
|
|
280
|
+
handler: ({ range, match, commands }) => {
|
|
215
281
|
const [, url] = match;
|
|
216
282
|
if (url) {
|
|
217
283
|
const html = `<video src="${url}" autoplay="" loop="" muted="" controls="" playsinline=""></video>`;
|
|
@@ -232,7 +298,7 @@ function useExtensions({ props, emit }) {
|
|
|
232
298
|
return [
|
|
233
299
|
new import_core.InputRule({
|
|
234
300
|
find: /!audio\(([^)]+)\)\s/,
|
|
235
|
-
handler: ({
|
|
301
|
+
handler: ({ range, match, commands }) => {
|
|
236
302
|
const [, url] = match;
|
|
237
303
|
if (url) {
|
|
238
304
|
const html = `<audio src="${url}" controls="" playsinline=""></audio>`;
|
|
@@ -247,14 +313,8 @@ function useExtensions({ props, emit }) {
|
|
|
247
313
|
];
|
|
248
314
|
}
|
|
249
315
|
}),
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// 如果你还想支持其他 style 属性,可以在这里配置
|
|
253
|
-
// HTMLAttributes: { class: 'my-custom-class' }
|
|
254
|
-
}),
|
|
255
|
-
import_extension_color.Color.configure({
|
|
256
|
-
// types: ['textStyle'] 默认就是这个,一般不需要改
|
|
257
|
-
}),
|
|
316
|
+
import_extension_text_style.TextStyle,
|
|
317
|
+
import_extension_color.Color,
|
|
258
318
|
import_tiptap_markdown.Markdown.configure({
|
|
259
319
|
html: true,
|
|
260
320
|
tightLists: true,
|
|
@@ -265,27 +325,19 @@ function useExtensions({ props, emit }) {
|
|
|
265
325
|
transformPastedText: true,
|
|
266
326
|
transformCopiedText: true
|
|
267
327
|
}),
|
|
268
|
-
// 自定义扩展来支持 Markdown 链接语法
|
|
269
328
|
import_core.Extension.create({
|
|
270
329
|
name: "markdownLinkInputRule",
|
|
271
330
|
addInputRules() {
|
|
272
331
|
return [
|
|
273
332
|
new import_core.InputRule({
|
|
274
333
|
find: /\[([^\]]+)\]\(([^\)]+)\)\s/,
|
|
275
|
-
handler: ({
|
|
334
|
+
handler: ({ range, match, commands }) => {
|
|
276
335
|
const [, text, href] = match;
|
|
277
|
-
|
|
278
|
-
const end = range.to;
|
|
279
|
-
commands.deleteRange({ from: start, to: end });
|
|
336
|
+
commands.deleteRange({ from: range.from, to: range.to });
|
|
280
337
|
commands.insertContent({
|
|
281
338
|
type: "text",
|
|
282
339
|
text,
|
|
283
|
-
marks: [
|
|
284
|
-
{
|
|
285
|
-
type: "link",
|
|
286
|
-
attrs: { href }
|
|
287
|
-
}
|
|
288
|
-
]
|
|
340
|
+
marks: [{ type: "link", attrs: { href } }]
|
|
289
341
|
});
|
|
290
342
|
}
|
|
291
343
|
})
|
|
@@ -297,9 +349,7 @@ function useExtensions({ props, emit }) {
|
|
|
297
349
|
table: { resizable: true }
|
|
298
350
|
}),
|
|
299
351
|
import_extensions.Placeholder.configure({
|
|
300
|
-
placeholder: () =>
|
|
301
|
-
return props.placeholder;
|
|
302
|
-
}
|
|
352
|
+
placeholder: () => props.placeholder
|
|
303
353
|
}),
|
|
304
354
|
import_extension_list.ListKit.extend({
|
|
305
355
|
addKeyboardShortcuts() {
|
|
@@ -307,18 +357,11 @@ function useExtensions({ props, emit }) {
|
|
|
307
357
|
Tab: ({ editor }) => {
|
|
308
358
|
const { $from } = editor.state.selection;
|
|
309
359
|
const currentItem = $from.node(-1);
|
|
310
|
-
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
return false;
|
|
360
|
+
return currentItem.type.name === "listItem";
|
|
314
361
|
},
|
|
315
362
|
"Shift-Tab": ({ editor }) => {
|
|
316
363
|
const { $from } = editor.state.selection;
|
|
317
|
-
|
|
318
|
-
if (currentItem.type.name === "doc") {
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
return false;
|
|
364
|
+
return $from.node(-1).type.name === "doc";
|
|
322
365
|
}
|
|
323
366
|
};
|
|
324
367
|
}
|
|
@@ -332,32 +375,23 @@ function useExtensions({ props, emit }) {
|
|
|
332
375
|
char: "@",
|
|
333
376
|
allowedPrefixes: null,
|
|
334
377
|
allowSpaces: false,
|
|
335
|
-
/**
|
|
336
|
-
* allow
|
|
337
|
-
* - 功能:判断是否允许触发建议态。
|
|
338
|
-
* - 1. 当@ 前面一个字符是数字/英文时,不触发,防止用户是想要输入邮箱。
|
|
339
|
-
* - 2. 触发以后如果包含数字,则收起(通过返回 false 销毁建议态)。
|
|
340
|
-
*/
|
|
341
378
|
allow: ({ state, range }) => {
|
|
342
|
-
if (
|
|
379
|
+
if (checkConsumed(state, range))
|
|
343
380
|
return false;
|
|
344
|
-
}
|
|
345
381
|
const doc = state.doc;
|
|
346
382
|
const $from = doc.resolve(range.from);
|
|
347
383
|
const isAtStart = range.from === $from.start();
|
|
348
384
|
const prevChar = isAtStart ? "" : doc.textBetween(range.from - 1, range.from);
|
|
349
|
-
if (/[a-zA-Z0-9]/.test(prevChar))
|
|
385
|
+
if (/[a-zA-Z0-9]/.test(prevChar))
|
|
350
386
|
return false;
|
|
351
|
-
}
|
|
352
387
|
const query = doc.textBetween(range.from + 1, range.to);
|
|
353
|
-
if (/[0-9]/.test(query))
|
|
388
|
+
if (/[0-9]/.test(query))
|
|
354
389
|
return false;
|
|
355
|
-
}
|
|
356
390
|
return true;
|
|
357
391
|
},
|
|
358
392
|
render() {
|
|
359
393
|
return {
|
|
360
|
-
onStart({ editor,
|
|
394
|
+
onStart({ editor, command, query }) {
|
|
361
395
|
activeEditor = editor;
|
|
362
396
|
emit("mention-triggered", (data) => {
|
|
363
397
|
command({
|
|
@@ -371,23 +405,16 @@ function useExtensions({ props, emit }) {
|
|
|
371
405
|
activeEditor = editor;
|
|
372
406
|
emit("mention-input", query != null ? query : "");
|
|
373
407
|
},
|
|
374
|
-
onExit({ range }) {
|
|
375
|
-
|
|
376
|
-
spentMentionPositions.push(range.from);
|
|
377
|
-
}
|
|
408
|
+
onExit({ editor, range }) {
|
|
409
|
+
markAsConsumed(editor, range, "@");
|
|
378
410
|
emit("mention-exit");
|
|
379
411
|
}
|
|
380
412
|
};
|
|
381
413
|
}
|
|
382
414
|
}
|
|
383
415
|
}),
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
*/
|
|
387
|
-
MentionTracker,
|
|
388
|
-
HashTagTracker,
|
|
389
|
-
// HashTag 扩展:支持 # 触发、实时输入同步、完成后插入为 “#+文字”
|
|
390
|
-
HashTag
|
|
416
|
+
HashTag,
|
|
417
|
+
CustomContent
|
|
391
418
|
];
|
|
392
419
|
return extensions;
|
|
393
420
|
}
|