@ctzhian/tiptap 1.6.0 → 1.6.2
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/dist/Editor/demo.js
CHANGED
|
@@ -4,7 +4,7 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try
|
|
|
4
4
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
5
5
|
import { Editor, EditorThemeProvider, EditorToolbar, useTiptap } from "./..";
|
|
6
6
|
import { Box } from '@mui/material';
|
|
7
|
-
import React
|
|
7
|
+
import React from 'react';
|
|
8
8
|
import { AiGenerate2Icon } from "../component/Icons";
|
|
9
9
|
import "../index.css";
|
|
10
10
|
var Reader = function Reader() {
|
|
@@ -15,17 +15,22 @@ var Reader = function Reader() {
|
|
|
15
15
|
console.log(editor.getHTML());
|
|
16
16
|
editor.commands.setContent(editor.getHTML());
|
|
17
17
|
},
|
|
18
|
+
onCreate: function onCreate(_ref) {
|
|
19
|
+
var currentEditor = _ref.editor;
|
|
20
|
+
currentEditor.commands.setAiWriting(true);
|
|
21
|
+
},
|
|
18
22
|
onAiWritingGetSuggestion: function () {
|
|
19
|
-
var _onAiWritingGetSuggestion = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(
|
|
20
|
-
var
|
|
23
|
+
var _onAiWritingGetSuggestion = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2) {
|
|
24
|
+
var prefix, suffix;
|
|
21
25
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
22
26
|
while (1) switch (_context.prev = _context.next) {
|
|
23
27
|
case 0:
|
|
24
|
-
|
|
28
|
+
prefix = _ref2.prefix, suffix = _ref2.suffix;
|
|
29
|
+
console.log('onAiWritingGetSuggestion', prefix, suffix);
|
|
25
30
|
return _context.abrupt("return", new Promise(function (resolve) {
|
|
26
31
|
resolve(['this is a default suggestion.', 'we are good.', 'what is your name?', 'how are you?', 'what is your favorite color?', 'what is your favorite food?', 'what is your favorite animal?', 'what is your favorite book?', 'what is your favorite movie?', 'what is your favorite song?', 'what is your favorite artist?', 'what is your favorite band?', 'what is your favorite city?', 'what is your favorite country?', 'what is your favorite sport?'][Math.floor(Math.random() * 10)]);
|
|
27
32
|
}));
|
|
28
|
-
case
|
|
33
|
+
case 3:
|
|
29
34
|
case "end":
|
|
30
35
|
return _context.stop();
|
|
31
36
|
}
|
|
@@ -38,12 +43,12 @@ var Reader = function Reader() {
|
|
|
38
43
|
}(),
|
|
39
44
|
// onTocUpdate: handleTocUpdate,
|
|
40
45
|
onMentionFilter: function () {
|
|
41
|
-
var _onMentionFilter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(
|
|
46
|
+
var _onMentionFilter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(_ref3) {
|
|
42
47
|
var query;
|
|
43
48
|
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
|
44
49
|
while (1) switch (_context2.prev = _context2.next) {
|
|
45
50
|
case 0:
|
|
46
|
-
query =
|
|
51
|
+
query = _ref3.query;
|
|
47
52
|
return _context2.abrupt("return", new Promise(function (resolve) {
|
|
48
53
|
resolve(['Winona Ryder', 'Molly Ringwald', 'Ally Sheedy', 'Debbie Harry', 'Olivia Newton-John', 'Elton John', 'Michael J. Fox', 'Axl Rose', 'Emilio Estevez', 'Ralph Macchio', 'Rob Lowe', 'Jennifer Grey'].filter(function (item) {
|
|
49
54
|
return item.toLowerCase().startsWith(query.toLowerCase());
|
|
@@ -105,11 +110,6 @@ var Reader = function Reader() {
|
|
|
105
110
|
content: ""
|
|
106
111
|
}),
|
|
107
112
|
editor = _useTiptap.editor;
|
|
108
|
-
useEffect(function () {
|
|
109
|
-
if (editor) {
|
|
110
|
-
editor.commands.setAiWriting(true);
|
|
111
|
-
}
|
|
112
|
-
}, [editor]);
|
|
113
113
|
return /*#__PURE__*/React.createElement(EditorThemeProvider, {
|
|
114
114
|
mode: "light"
|
|
115
115
|
}, /*#__PURE__*/React.createElement(Box, {
|
|
@@ -10,6 +10,11 @@ declare module '@tiptap/core' {
|
|
|
10
10
|
setAiWriting: (enabled: boolean) => ReturnType;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
+
interface Storage {
|
|
14
|
+
aiWriting: {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
type SuggestionState = {
|
|
15
20
|
enabled: boolean;
|
|
@@ -17,10 +22,12 @@ type SuggestionState = {
|
|
|
17
22
|
text: string;
|
|
18
23
|
decorations: DecorationSet;
|
|
19
24
|
lastDocText: string;
|
|
25
|
+
lastTriggerPos: number | null;
|
|
20
26
|
};
|
|
21
27
|
export declare const AiWritingExtension: (props: {
|
|
22
|
-
onAiWritingGetSuggestion?: (({
|
|
23
|
-
|
|
28
|
+
onAiWritingGetSuggestion?: (({ prefix, suffix }: {
|
|
29
|
+
prefix: string;
|
|
30
|
+
suffix: string;
|
|
24
31
|
}) => Promise<string>) | undefined;
|
|
25
32
|
}) => Extension<AiWritingOptions, any>;
|
|
26
33
|
export type { SuggestionState };
|
|
@@ -34,16 +34,11 @@ function isAtEndWithNoContentAfter(view) {
|
|
|
34
34
|
var selection = state.selection,
|
|
35
35
|
doc = state.doc;
|
|
36
36
|
if (!selection.empty) return false;
|
|
37
|
-
//
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (afterText && afterText.trim().length > 0) return false;
|
|
43
|
-
// 同时在当前文本块末尾(不在块中间)
|
|
44
|
-
var $from = selection.$from;
|
|
45
|
-
var atEndOfBlock = $from.parentOffset === $from.parent.content.size;
|
|
46
|
-
return !!atEndOfBlock;
|
|
37
|
+
// 基于当前行:从光标到下一处换行(或文末)之间是否仅为空白
|
|
38
|
+
var suffixFromCursor = doc.textBetween(selection.from, doc.content.size, '\n', '\n');
|
|
39
|
+
var nextNewlineIndex = suffixFromCursor.indexOf('\n');
|
|
40
|
+
var currentLineAfterCursor = nextNewlineIndex >= 0 ? suffixFromCursor.slice(0, nextNewlineIndex) : suffixFromCursor;
|
|
41
|
+
return currentLineAfterCursor.trim().length === 0;
|
|
47
42
|
}
|
|
48
43
|
function createSuggestionWidget(text) {
|
|
49
44
|
var dom = document.createElement('span');
|
|
@@ -56,7 +51,7 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
56
51
|
name: 'aiWriting',
|
|
57
52
|
addOptions: function addOptions() {
|
|
58
53
|
return {
|
|
59
|
-
minChars:
|
|
54
|
+
minChars: 0,
|
|
60
55
|
debounceMs: 1000
|
|
61
56
|
};
|
|
62
57
|
},
|
|
@@ -71,16 +66,13 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
71
66
|
setAiWriting: function setAiWriting(enabled) {
|
|
72
67
|
return function (_ref) {
|
|
73
68
|
var tr = _ref.tr,
|
|
74
|
-
state = _ref.state,
|
|
75
69
|
dispatch = _ref.dispatch;
|
|
76
70
|
if (dispatch) {
|
|
77
71
|
var meta = {
|
|
78
72
|
type: 'setEnabled',
|
|
79
73
|
enabled: enabled
|
|
80
74
|
};
|
|
81
|
-
dispatch(tr.setMeta(aiWritingPluginKey, meta))
|
|
82
|
-
// 同步到 storage,便于外部判断
|
|
83
|
-
;
|
|
75
|
+
dispatch(tr.setMeta(aiWritingPluginKey, meta));
|
|
84
76
|
_this.storage.enabled = !!enabled;
|
|
85
77
|
}
|
|
86
78
|
return true;
|
|
@@ -103,7 +95,21 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
103
95
|
dispatch = _ref2.dispatch;
|
|
104
96
|
if (!dispatch) return true;
|
|
105
97
|
var insertPos = state.selection.from;
|
|
106
|
-
|
|
98
|
+
var schema = state.schema;
|
|
99
|
+
var segments = text.split('\n');
|
|
100
|
+
var posCursor = insertPos;
|
|
101
|
+
for (var i = 0; i < segments.length; i++) {
|
|
102
|
+
var segment = segments[i];
|
|
103
|
+
if (segment.length > 0) {
|
|
104
|
+
tr.insertText(segment, posCursor);
|
|
105
|
+
posCursor += segment.length;
|
|
106
|
+
}
|
|
107
|
+
if (i < segments.length - 1) {
|
|
108
|
+
var br = schema.nodes.hardBreak.create();
|
|
109
|
+
tr.insert(posCursor, br);
|
|
110
|
+
posCursor += 1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
107
113
|
// 接受后清空建议
|
|
108
114
|
dispatch(tr.setMeta(aiWritingPluginKey, {
|
|
109
115
|
type: 'clearSuggestion'
|
|
@@ -120,7 +126,7 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
120
126
|
var debouncedRequest = null;
|
|
121
127
|
var request = /*#__PURE__*/function () {
|
|
122
128
|
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(view) {
|
|
123
|
-
var state, text, suggestion, _yield$props$onAiWrit, _props$onAiWritingGet, tr;
|
|
129
|
+
var state, text, from, suggestion, _yield$props$onAiWrit, _props$onAiWritingGet, _ref4, doc, prefix, suffix, tr;
|
|
124
130
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
125
131
|
while (1) switch (_context.prev = _context.next) {
|
|
126
132
|
case 0:
|
|
@@ -144,57 +150,70 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
144
150
|
}
|
|
145
151
|
return _context.abrupt("return");
|
|
146
152
|
case 8:
|
|
147
|
-
if (!(
|
|
153
|
+
if (!(!text || text.trim().length === 0)) {
|
|
148
154
|
_context.next = 10;
|
|
149
155
|
break;
|
|
150
156
|
}
|
|
151
157
|
return _context.abrupt("return");
|
|
152
158
|
case 10:
|
|
159
|
+
// 避免重复请求同一内容与同一光标位置
|
|
160
|
+
from = view.state.selection.from;
|
|
161
|
+
if (!(state.lastDocText === text && state.lastTriggerPos === from)) {
|
|
162
|
+
_context.next = 13;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
return _context.abrupt("return");
|
|
166
|
+
case 13:
|
|
153
167
|
suggestion = '';
|
|
154
|
-
_context.prev =
|
|
155
|
-
|
|
168
|
+
_context.prev = 14;
|
|
169
|
+
_ref4 = view.state, doc = _ref4.doc;
|
|
170
|
+
prefix = doc.textBetween(0, from, '\n', '\n');
|
|
171
|
+
suffix = doc.textBetween(from, doc.content.size, '\n', '\n');
|
|
172
|
+
_context.next = 20;
|
|
156
173
|
return (_props$onAiWritingGet = props.onAiWritingGetSuggestion) === null || _props$onAiWritingGet === void 0 ? void 0 : _props$onAiWritingGet.call(props, {
|
|
157
|
-
|
|
174
|
+
prefix: prefix,
|
|
175
|
+
suffix: suffix
|
|
158
176
|
});
|
|
159
|
-
case
|
|
177
|
+
case 20:
|
|
160
178
|
_context.t1 = _yield$props$onAiWrit = _context.sent;
|
|
161
179
|
_context.t0 = _context.t1 !== null;
|
|
162
180
|
if (!_context.t0) {
|
|
163
|
-
_context.next =
|
|
181
|
+
_context.next = 24;
|
|
164
182
|
break;
|
|
165
183
|
}
|
|
166
184
|
_context.t0 = _yield$props$onAiWrit !== void 0;
|
|
167
|
-
case
|
|
185
|
+
case 24:
|
|
168
186
|
if (!_context.t0) {
|
|
169
|
-
_context.next =
|
|
187
|
+
_context.next = 28;
|
|
170
188
|
break;
|
|
171
189
|
}
|
|
172
190
|
_context.t2 = _yield$props$onAiWrit;
|
|
173
|
-
_context.next =
|
|
191
|
+
_context.next = 29;
|
|
174
192
|
break;
|
|
175
|
-
case
|
|
193
|
+
case 28:
|
|
176
194
|
_context.t2 = '';
|
|
177
|
-
case
|
|
195
|
+
case 29:
|
|
178
196
|
suggestion = _context.t2;
|
|
179
|
-
_context.next =
|
|
197
|
+
_context.next = 35;
|
|
180
198
|
break;
|
|
181
|
-
case
|
|
182
|
-
_context.prev =
|
|
183
|
-
_context.t3 = _context["catch"](
|
|
199
|
+
case 32:
|
|
200
|
+
_context.prev = 32;
|
|
201
|
+
_context.t3 = _context["catch"](14);
|
|
184
202
|
console.error('getSuggestion error', _context.t3);
|
|
185
|
-
case
|
|
203
|
+
case 35:
|
|
186
204
|
tr = view.state.tr.setMeta(aiWritingPluginKey, {
|
|
187
205
|
type: 'setSuggestion',
|
|
188
206
|
text: suggestion,
|
|
189
207
|
pos: view.state.selection.from,
|
|
190
|
-
lastDocText: text
|
|
208
|
+
lastDocText: text,
|
|
209
|
+
lastTriggerPos: from
|
|
191
210
|
});
|
|
192
211
|
view.dispatch(tr);
|
|
193
|
-
case
|
|
212
|
+
case 37:
|
|
194
213
|
case "end":
|
|
195
214
|
return _context.stop();
|
|
196
215
|
}
|
|
197
|
-
}, _callee, null, [[
|
|
216
|
+
}, _callee, null, [[14, 32]]);
|
|
198
217
|
}));
|
|
199
218
|
return function request(_x) {
|
|
200
219
|
return _ref3.apply(this, arguments);
|
|
@@ -217,7 +236,8 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
217
236
|
pos: null,
|
|
218
237
|
text: '',
|
|
219
238
|
decorations: DecorationSet.create(state.doc, []),
|
|
220
|
-
lastDocText: ''
|
|
239
|
+
lastDocText: '',
|
|
240
|
+
lastTriggerPos: null
|
|
221
241
|
};
|
|
222
242
|
},
|
|
223
243
|
apply: function apply(tr, pluginState, _old, newState) {
|
|
@@ -234,7 +254,8 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
234
254
|
next = _objectSpread(_objectSpread({}, next), {}, {
|
|
235
255
|
text: '',
|
|
236
256
|
pos: null,
|
|
237
|
-
decorations: DecorationSet.create(newState.doc, [])
|
|
257
|
+
decorations: DecorationSet.create(newState.doc, []),
|
|
258
|
+
lastTriggerPos: null
|
|
238
259
|
});
|
|
239
260
|
}
|
|
240
261
|
}
|
|
@@ -250,7 +271,8 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
250
271
|
enabled: _enabled,
|
|
251
272
|
text: _enabled ? next.text : '',
|
|
252
273
|
pos: _enabled ? next.pos : null,
|
|
253
|
-
decorations: cleared
|
|
274
|
+
decorations: cleared,
|
|
275
|
+
lastTriggerPos: _enabled ? next.lastTriggerPos : null
|
|
254
276
|
});
|
|
255
277
|
}
|
|
256
278
|
case 'setSuggestion':
|
|
@@ -259,12 +281,14 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
259
281
|
var text = meta.text || '';
|
|
260
282
|
var pos = typeof meta.pos === 'number' ? meta.pos : null;
|
|
261
283
|
var lastDocText = (_meta$lastDocText = meta.lastDocText) !== null && _meta$lastDocText !== void 0 ? _meta$lastDocText : next.lastDocText;
|
|
284
|
+
var lastTriggerPos = typeof meta.lastTriggerPos === 'number' ? meta.lastTriggerPos : next.lastTriggerPos;
|
|
262
285
|
if (!text || pos == null) {
|
|
263
286
|
return _objectSpread(_objectSpread({}, next), {}, {
|
|
264
287
|
text: '',
|
|
265
288
|
pos: null,
|
|
266
289
|
decorations: DecorationSet.create(newState.doc, []),
|
|
267
|
-
lastDocText: lastDocText
|
|
290
|
+
lastDocText: lastDocText,
|
|
291
|
+
lastTriggerPos: lastTriggerPos
|
|
268
292
|
});
|
|
269
293
|
}
|
|
270
294
|
var deco = Decoration.widget(pos, function () {
|
|
@@ -278,7 +302,8 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
278
302
|
text: text,
|
|
279
303
|
pos: pos,
|
|
280
304
|
decorations: decoSet,
|
|
281
|
-
lastDocText: lastDocText
|
|
305
|
+
lastDocText: lastDocText,
|
|
306
|
+
lastTriggerPos: lastTriggerPos
|
|
282
307
|
});
|
|
283
308
|
}
|
|
284
309
|
case 'clearSuggestion':
|
|
@@ -286,7 +311,8 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
286
311
|
return _objectSpread(_objectSpread({}, next), {}, {
|
|
287
312
|
text: '',
|
|
288
313
|
pos: null,
|
|
289
|
-
decorations: DecorationSet.create(newState.doc, [])
|
|
314
|
+
decorations: DecorationSet.create(newState.doc, []),
|
|
315
|
+
lastTriggerPos: null
|
|
290
316
|
});
|
|
291
317
|
}
|
|
292
318
|
}
|
|
@@ -307,6 +333,13 @@ export var AiWritingExtension = function AiWritingExtension(props) {
|
|
|
307
333
|
var handler = function handler() {
|
|
308
334
|
var state = aiWritingPluginKey.getState(view.state);
|
|
309
335
|
if (!state || !state.enabled) return;
|
|
336
|
+
var currentPos = view.state.selection.from;
|
|
337
|
+
// 若光标位置与建议位置不同且有建议,先清空(视为拒绝)
|
|
338
|
+
if (state.text && state.pos != null && state.pos !== currentPos) {
|
|
339
|
+
view.dispatch(view.state.tr.setMeta(aiWritingPluginKey, {
|
|
340
|
+
type: 'clearSuggestion'
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
310
343
|
if (!isAtEndWithNoContentAfter(view)) return;
|
|
311
344
|
ensureDebounced()(view);
|
|
312
345
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { UploadFunction } from "../../type";
|
|
2
2
|
export declare const FileHandlerExtension: (props: {
|
|
3
3
|
onUpload?: UploadFunction;
|
|
4
|
-
}) => import("@tiptap/core").Extension<Omit<import("@tiptap/extension-file-handler").FileHandlePluginOptions, "
|
|
4
|
+
}) => import("@tiptap/core").Extension<Omit<import("@tiptap/extension-file-handler").FileHandlePluginOptions, "key" | "editor">, any>;
|
package/dist/type/index.d.ts
CHANGED
|
@@ -70,8 +70,9 @@ export type EditorFnProps = {
|
|
|
70
70
|
onError?: (error: Error) => void;
|
|
71
71
|
onUpload?: UploadFunction;
|
|
72
72
|
onTocUpdate?: (toc: TocList) => void;
|
|
73
|
-
onAiWritingGetSuggestion?: ({
|
|
74
|
-
|
|
73
|
+
onAiWritingGetSuggestion?: ({ prefix, suffix }: {
|
|
74
|
+
prefix: string;
|
|
75
|
+
suffix: string;
|
|
75
76
|
}) => Promise<string>;
|
|
76
77
|
};
|
|
77
78
|
export type MentionItems = string[];
|