@platejs/ai 49.1.11 → 49.2.1
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/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +265 -206
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +249 -179
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +4 -2
- package/dist/react/index.d.ts +4 -2
- package/dist/react/index.js +71 -68
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +42 -38
- package/dist/react/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
bindFirst,
|
|
4
4
|
createTSlatePlugin,
|
|
5
|
-
KEYS
|
|
5
|
+
KEYS as KEYS2
|
|
6
6
|
} from "platejs";
|
|
7
7
|
|
|
8
8
|
// src/lib/transforms/insertAINodes.ts
|
|
@@ -24,10 +24,12 @@ var insertAINodes = (editor, nodes, {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
// src/lib/transforms/removeAIMarks.ts
|
|
27
|
+
import { getPluginType, KEYS } from "platejs";
|
|
27
28
|
var removeAIMarks = (editor, { at = [] } = {}) => {
|
|
28
|
-
editor.
|
|
29
|
+
const nodeType = getPluginType(editor, KEYS.ai);
|
|
30
|
+
editor.tf.unsetNodes(nodeType, {
|
|
29
31
|
at,
|
|
30
|
-
match: (n) => n
|
|
32
|
+
match: (n) => n[nodeType]
|
|
31
33
|
});
|
|
32
34
|
};
|
|
33
35
|
|
|
@@ -68,7 +70,7 @@ var withAIBatch = (editor, fn, {
|
|
|
68
70
|
|
|
69
71
|
// src/lib/BaseAIPlugin.ts
|
|
70
72
|
var BaseAIPlugin = createTSlatePlugin({
|
|
71
|
-
key:
|
|
73
|
+
key: KEYS2.ai,
|
|
72
74
|
node: { isDecoration: false, isLeaf: true }
|
|
73
75
|
}).extendTransforms(({ editor }) => ({
|
|
74
76
|
insertNodes: bindFirst(insertAINodes, editor),
|
|
@@ -85,143 +87,7 @@ var streamDeserializeInlineMd = (editor, text, options) => {
|
|
|
85
87
|
|
|
86
88
|
// src/lib/streaming/streamDeserializeMd.ts
|
|
87
89
|
import { MarkdownPlugin as MarkdownPlugin2 } from "@platejs/markdown";
|
|
88
|
-
import { KEYS as
|
|
89
|
-
|
|
90
|
-
// src/lib/streaming/utils/escapeInput.ts
|
|
91
|
-
var escapeInput = (data) => {
|
|
92
|
-
let res = data;
|
|
93
|
-
if (data.startsWith("$$") && !data.startsWith("$$\n") && !isCompleteMath(data)) {
|
|
94
|
-
res = data.replace("$$", String.raw`\$\$`);
|
|
95
|
-
}
|
|
96
|
-
return res;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
// src/lib/streaming/utils/getListNode.ts
|
|
100
|
-
var getListNode = (editor, node) => {
|
|
101
|
-
if (node.listStyleType && node.listStart) {
|
|
102
|
-
const previousNode = editor.api.previous({
|
|
103
|
-
at: editor.selection?.focus
|
|
104
|
-
})?.[0];
|
|
105
|
-
if (previousNode?.listStyleType && previousNode?.listStart) {
|
|
106
|
-
return node;
|
|
107
|
-
} else {
|
|
108
|
-
if (node.listStart === 1) return node;
|
|
109
|
-
return {
|
|
110
|
-
...node,
|
|
111
|
-
listRestartPolite: node.listStart
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return node;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// src/lib/streaming/utils/isSameNode.ts
|
|
119
|
-
import { isDefined, KEYS as KEYS2 } from "platejs";
|
|
120
|
-
var LIST_STYLE_TYPE = "listStyleType";
|
|
121
|
-
var isSameNode = (editor, node1, node2) => {
|
|
122
|
-
if (node1.type !== editor.getType(KEYS2.p) || node2.type !== editor.getType(KEYS2.p))
|
|
123
|
-
return node1.type === node2.type;
|
|
124
|
-
if (isDefined(node1[LIST_STYLE_TYPE]) || isDefined(node2[LIST_STYLE_TYPE])) {
|
|
125
|
-
return node1[LIST_STYLE_TYPE] === node2[LIST_STYLE_TYPE];
|
|
126
|
-
}
|
|
127
|
-
return node1.type === node2.type;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// src/lib/streaming/utils/nodesWithProps.ts
|
|
131
|
-
import { ElementApi } from "platejs";
|
|
132
|
-
var nodesWithProps = (editor, nodes, options) => {
|
|
133
|
-
return nodes.map((node) => {
|
|
134
|
-
if (ElementApi.isElement(node)) {
|
|
135
|
-
return {
|
|
136
|
-
...getListNode(editor, node),
|
|
137
|
-
...options.elementProps,
|
|
138
|
-
children: nodesWithProps(editor, node.children, options)
|
|
139
|
-
};
|
|
140
|
-
} else {
|
|
141
|
-
return {
|
|
142
|
-
...options.textProps,
|
|
143
|
-
...node,
|
|
144
|
-
text: node.text
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// src/lib/streaming/utils/utils.ts
|
|
151
|
-
var getChunkTrimmed = (chunk, {
|
|
152
|
-
direction = "right"
|
|
153
|
-
} = {}) => {
|
|
154
|
-
const str = direction === "right" ? chunk.trimEnd() : chunk.trimStart();
|
|
155
|
-
if (direction === "right") {
|
|
156
|
-
return chunk.slice(str.length);
|
|
157
|
-
} else {
|
|
158
|
-
return chunk.slice(0, chunk.length - str.length);
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
function isCompleteCodeBlock(str) {
|
|
162
|
-
const trimmed = str.trim();
|
|
163
|
-
const startsWithCodeBlock = trimmed.startsWith("```");
|
|
164
|
-
const endsWithCodeBlock = trimmed.endsWith("```");
|
|
165
|
-
return startsWithCodeBlock && endsWithCodeBlock;
|
|
166
|
-
}
|
|
167
|
-
function isCompleteMath(str) {
|
|
168
|
-
const trimmed = str.trim();
|
|
169
|
-
const startsWithMath = trimmed.startsWith("$$");
|
|
170
|
-
const endsWithMath = trimmed.endsWith("$$");
|
|
171
|
-
return startsWithMath && endsWithMath;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/lib/streaming/streamDeserializeMd.ts
|
|
175
|
-
var streamDeserializeMd = (editor, data, options) => {
|
|
176
|
-
const input = escapeInput(data);
|
|
177
|
-
let blocks = [];
|
|
178
|
-
blocks = editor.getApi(MarkdownPlugin2).markdown.deserialize(input, {
|
|
179
|
-
...options,
|
|
180
|
-
preserveEmptyParagraphs: false
|
|
181
|
-
});
|
|
182
|
-
const trimmedData = getChunkTrimmed(data);
|
|
183
|
-
const lastBlock = blocks.at(-1);
|
|
184
|
-
const addNewLine = trimmedData === "\n\n";
|
|
185
|
-
const unshiftNewLine = getChunkTrimmed(data, { direction: "left" }) === "\n\n";
|
|
186
|
-
const isCodeBlockOrTable = lastBlock?.type === "code_block" || lastBlock?.type === "table";
|
|
187
|
-
let result = blocks;
|
|
188
|
-
if (lastBlock && !isCodeBlockOrTable && trimmedData.length > 0 && !addNewLine) {
|
|
189
|
-
const textNode = [
|
|
190
|
-
{
|
|
191
|
-
text: trimmedData
|
|
192
|
-
}
|
|
193
|
-
];
|
|
194
|
-
const lastChild = lastBlock.children.at(-1);
|
|
195
|
-
if (lastChild && TextApi2.isText(lastChild) && Object.keys(lastChild).length === 1) {
|
|
196
|
-
lastBlock.children.pop();
|
|
197
|
-
const textNode2 = [
|
|
198
|
-
{
|
|
199
|
-
text: lastChild.text + trimmedData
|
|
200
|
-
}
|
|
201
|
-
];
|
|
202
|
-
lastBlock.children.push(...textNode2);
|
|
203
|
-
} else {
|
|
204
|
-
lastBlock.children.push(...textNode);
|
|
205
|
-
}
|
|
206
|
-
result = [...blocks.slice(0, -1), lastBlock];
|
|
207
|
-
}
|
|
208
|
-
if (addNewLine && !isCodeBlockOrTable) {
|
|
209
|
-
result.push({
|
|
210
|
-
children: [{ text: "" }],
|
|
211
|
-
type: KEYS3.p
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
if (unshiftNewLine && !isCodeBlockOrTable) {
|
|
215
|
-
result.unshift({
|
|
216
|
-
children: [{ text: "" }],
|
|
217
|
-
type: KEYS3.p
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
return result;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
// src/lib/streaming/streamInsertChunk.ts
|
|
224
|
-
import { NodeApi as NodeApi2, PathApi as PathApi2 } from "platejs";
|
|
90
|
+
import { getPluginType as getPluginType4, KEYS as KEYS13, TextApi as TextApi3 } from "platejs";
|
|
225
91
|
|
|
226
92
|
// src/react/ai/AIPlugin.ts
|
|
227
93
|
import { toPlatePlugin } from "platejs/react";
|
|
@@ -231,17 +97,18 @@ var AIPlugin = toPlatePlugin(BaseAIPlugin);
|
|
|
231
97
|
import { BlockSelectionPlugin as BlockSelectionPlugin5 } from "@platejs/selection/react";
|
|
232
98
|
import {
|
|
233
99
|
bindFirst as bindFirst2,
|
|
234
|
-
ElementApi as
|
|
235
|
-
|
|
100
|
+
ElementApi as ElementApi3,
|
|
101
|
+
getPluginType as getPluginType3,
|
|
102
|
+
KEYS as KEYS11
|
|
236
103
|
} from "platejs";
|
|
237
104
|
import { createTPlatePlugin } from "platejs/react";
|
|
238
105
|
|
|
239
106
|
// src/react/ai-chat/transforms/acceptAIChat.ts
|
|
240
|
-
import { KEYS as
|
|
107
|
+
import { KEYS as KEYS3 } from "platejs";
|
|
241
108
|
import { getEditorPlugin } from "platejs/react";
|
|
242
109
|
var acceptAIChat = (editor) => {
|
|
243
110
|
const { tf } = getEditorPlugin(editor, AIPlugin);
|
|
244
|
-
const api = editor.getApi({ key:
|
|
111
|
+
const api = editor.getApi({ key: KEYS3.ai });
|
|
245
112
|
const lastAINodePath = api.aiChat.node({ at: [], reverse: true })[1];
|
|
246
113
|
withAIBatch(editor, () => {
|
|
247
114
|
tf.ai.removeMarks();
|
|
@@ -259,7 +126,7 @@ var acceptAIChat = (editor) => {
|
|
|
259
126
|
// src/react/ai-chat/transforms/insertBelowAIChat.ts
|
|
260
127
|
import { BlockSelectionPlugin as BlockSelectionPlugin2 } from "@platejs/selection/react";
|
|
261
128
|
import cloneDeep2 from "lodash/cloneDeep.js";
|
|
262
|
-
import { KEYS as
|
|
129
|
+
import { KEYS as KEYS5, PathApi, RangeApi } from "platejs";
|
|
263
130
|
|
|
264
131
|
// src/react/ai-chat/transforms/replaceSelectionAIChat.ts
|
|
265
132
|
import {
|
|
@@ -268,9 +135,9 @@ import {
|
|
|
268
135
|
} from "@platejs/selection/react";
|
|
269
136
|
import cloneDeep from "lodash/cloneDeep.js";
|
|
270
137
|
import {
|
|
271
|
-
KEYS as
|
|
138
|
+
KEYS as KEYS4,
|
|
272
139
|
NodeApi,
|
|
273
|
-
TextApi as
|
|
140
|
+
TextApi as TextApi2
|
|
274
141
|
} from "platejs";
|
|
275
142
|
var createFormattedBlocks = ({
|
|
276
143
|
blocks,
|
|
@@ -284,7 +151,7 @@ var createFormattedBlocks = ({
|
|
|
284
151
|
const blockProps = NodeApi.extractProps(sourceNode);
|
|
285
152
|
const textProps = NodeApi.extractProps(firstTextEntry[0]);
|
|
286
153
|
const applyTextFormatting = (node) => {
|
|
287
|
-
if (
|
|
154
|
+
if (TextApi2.isText(node)) {
|
|
288
155
|
return { ...textProps, ...node };
|
|
289
156
|
}
|
|
290
157
|
if (node.children) {
|
|
@@ -311,7 +178,7 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
|
|
|
311
178
|
BlockSelectionPlugin,
|
|
312
179
|
"isSelectingSome"
|
|
313
180
|
);
|
|
314
|
-
editor.getApi({ key:
|
|
181
|
+
editor.getApi({ key: KEYS4.ai }).aiChat.hide();
|
|
315
182
|
if (!isBlockSelecting) {
|
|
316
183
|
const firstBlock = editor.api.node({
|
|
317
184
|
block: true,
|
|
@@ -375,7 +242,7 @@ var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
|
375
242
|
BlockSelectionPlugin2,
|
|
376
243
|
"isSelectingSome"
|
|
377
244
|
);
|
|
378
|
-
editor.getApi({ key:
|
|
245
|
+
editor.getApi({ key: KEYS5.ai }).aiChat.hide();
|
|
379
246
|
const insertBlocksAndSelect = editor.getTransforms(BlockSelectionPlugin2).blockSelection.insertBlocksAndSelect;
|
|
380
247
|
if (isBlockSelecting) {
|
|
381
248
|
const selectedBlocks = editor.getApi(BlockSelectionPlugin2).blockSelection.getNodes();
|
|
@@ -427,12 +294,12 @@ var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
|
427
294
|
};
|
|
428
295
|
|
|
429
296
|
// src/react/ai-chat/transforms/removeAnchorAIChat.ts
|
|
430
|
-
import { ElementApi as
|
|
297
|
+
import { ElementApi, getPluginType as getPluginType2, KEYS as KEYS6 } from "platejs";
|
|
431
298
|
var removeAnchorAIChat = (editor, options) => {
|
|
432
299
|
editor.tf.withoutSaving(() => {
|
|
433
300
|
editor.tf.removeNodes({
|
|
434
301
|
at: [],
|
|
435
|
-
match: (n) =>
|
|
302
|
+
match: (n) => ElementApi.isElement(n) && n.type === getPluginType2(editor, KEYS6.aiChat),
|
|
436
303
|
...options
|
|
437
304
|
});
|
|
438
305
|
});
|
|
@@ -445,7 +312,7 @@ import { BlockSelectionPlugin as BlockSelectionPlugin4 } from "@platejs/selectio
|
|
|
445
312
|
// src/react/ai-chat/utils/getMarkdown.ts
|
|
446
313
|
import { serializeMd } from "@platejs/markdown";
|
|
447
314
|
import { BlockSelectionPlugin as BlockSelectionPlugin3 } from "@platejs/selection/react";
|
|
448
|
-
import { KEYS as
|
|
315
|
+
import { KEYS as KEYS7 } from "platejs";
|
|
449
316
|
var getMarkdown = (editor, type) => {
|
|
450
317
|
if (type === "editor") {
|
|
451
318
|
return serializeMd(editor);
|
|
@@ -464,7 +331,7 @@ var getMarkdown = (editor, type) => {
|
|
|
464
331
|
const modifiedFragment = [
|
|
465
332
|
{
|
|
466
333
|
children: fragment[0].children,
|
|
467
|
-
type:
|
|
334
|
+
type: KEYS7.p
|
|
468
335
|
}
|
|
469
336
|
];
|
|
470
337
|
return serializeMd(editor, { value: modifiedFragment });
|
|
@@ -526,11 +393,11 @@ var getEditorPrompt = (editor, {
|
|
|
526
393
|
};
|
|
527
394
|
|
|
528
395
|
// src/react/ai-chat/utils/resetAIChat.ts
|
|
529
|
-
import { KEYS as
|
|
396
|
+
import { KEYS as KEYS8 } from "platejs";
|
|
530
397
|
import { getEditorPlugin as getEditorPlugin2 } from "platejs/react";
|
|
531
398
|
var resetAIChat = (editor) => {
|
|
532
399
|
const { api, getOptions } = getEditorPlugin2(editor, {
|
|
533
|
-
key:
|
|
400
|
+
key: KEYS8.aiChat
|
|
534
401
|
});
|
|
535
402
|
api.aiChat.stop();
|
|
536
403
|
const chat = getOptions().chat;
|
|
@@ -542,7 +409,7 @@ var resetAIChat = (editor) => {
|
|
|
542
409
|
|
|
543
410
|
// src/react/ai-chat/utils/submitAIChat.ts
|
|
544
411
|
import { isSelecting as isSelecting2 } from "@platejs/selection";
|
|
545
|
-
import { KEYS as
|
|
412
|
+
import { KEYS as KEYS9 } from "platejs";
|
|
546
413
|
import { getEditorPlugin as getEditorPlugin3 } from "platejs/react";
|
|
547
414
|
var submitAIChat = (editor, {
|
|
548
415
|
mode,
|
|
@@ -553,7 +420,7 @@ var submitAIChat = (editor, {
|
|
|
553
420
|
const { getOptions, setOption } = getEditorPlugin3(
|
|
554
421
|
editor,
|
|
555
422
|
{
|
|
556
|
-
key:
|
|
423
|
+
key: KEYS9.aiChat
|
|
557
424
|
}
|
|
558
425
|
);
|
|
559
426
|
const { chat, promptTemplate, systemTemplate } = getOptions();
|
|
@@ -592,7 +459,7 @@ var submitAIChat = (editor, {
|
|
|
592
459
|
};
|
|
593
460
|
|
|
594
461
|
// src/react/ai-chat/withAIChat.ts
|
|
595
|
-
import { ElementApi as
|
|
462
|
+
import { ElementApi as ElementApi2, KEYS as KEYS10 } from "platejs";
|
|
596
463
|
var withAIChat = ({
|
|
597
464
|
api,
|
|
598
465
|
editor,
|
|
@@ -634,11 +501,11 @@ var withAIChat = ({
|
|
|
634
501
|
},
|
|
635
502
|
normalizeNode(entry) {
|
|
636
503
|
const [node, path] = entry;
|
|
637
|
-
if (node[
|
|
504
|
+
if (node[KEYS10.ai] && !getOptions().open) {
|
|
638
505
|
tf.ai.removeMarks({ at: path });
|
|
639
506
|
return;
|
|
640
507
|
}
|
|
641
|
-
if (
|
|
508
|
+
if (ElementApi2.isElement(node) && node.type === type && !getOptions().open) {
|
|
642
509
|
editor.getTransforms(AIChatPlugin).aiChat.removeAnchor({ at: path });
|
|
643
510
|
return;
|
|
644
511
|
}
|
|
@@ -650,7 +517,7 @@ var withAIChat = ({
|
|
|
650
517
|
|
|
651
518
|
// src/react/ai-chat/AIChatPlugin.ts
|
|
652
519
|
var AIChatPlugin = createTPlatePlugin({
|
|
653
|
-
key:
|
|
520
|
+
key: KEYS11.aiChat,
|
|
654
521
|
dependencies: ["ai"],
|
|
655
522
|
node: {
|
|
656
523
|
isElement: true
|
|
@@ -658,6 +525,7 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
658
525
|
options: {
|
|
659
526
|
_blockChunks: "",
|
|
660
527
|
_blockPath: null,
|
|
528
|
+
_mdxName: null,
|
|
661
529
|
aiEditor: null,
|
|
662
530
|
chat: { messages: [] },
|
|
663
531
|
experimental_lastTextId: null,
|
|
@@ -679,7 +547,7 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
679
547
|
if (anchor) {
|
|
680
548
|
return editor.api.node({
|
|
681
549
|
at: [],
|
|
682
|
-
match: (n) =>
|
|
550
|
+
match: (n) => ElementApi3.isElement(n) && n.type === type,
|
|
683
551
|
...rest
|
|
684
552
|
});
|
|
685
553
|
}
|
|
@@ -691,12 +559,12 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
691
559
|
at: path,
|
|
692
560
|
mode: "lowest",
|
|
693
561
|
reverse: true,
|
|
694
|
-
match: (t) => !!t.ai,
|
|
562
|
+
match: (t) => !!t[getPluginType3(editor, KEYS11.ai)],
|
|
695
563
|
...rest
|
|
696
564
|
});
|
|
697
565
|
}
|
|
698
566
|
return editor.api.node({
|
|
699
|
-
match: (n) => n.ai,
|
|
567
|
+
match: (n) => n[getPluginType3(editor, KEYS11.ai)],
|
|
700
568
|
...rest
|
|
701
569
|
});
|
|
702
570
|
},
|
|
@@ -744,13 +612,197 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
744
612
|
replaceSelection: bindFirst2(replaceSelectionAIChat, editor)
|
|
745
613
|
}));
|
|
746
614
|
|
|
615
|
+
// src/lib/streaming/utils/escapeInput.ts
|
|
616
|
+
var escapeInput = (data) => {
|
|
617
|
+
let res = data;
|
|
618
|
+
if (data.startsWith("$$") && !data.startsWith("$$\n") && !isCompleteMath(data)) {
|
|
619
|
+
res = data.replace("$$", String.raw`\$\$`);
|
|
620
|
+
}
|
|
621
|
+
return res;
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// src/lib/streaming/utils/getListNode.ts
|
|
625
|
+
var getListNode = (editor, node) => {
|
|
626
|
+
if (node.listStyleType && node.listStart) {
|
|
627
|
+
const previousNode = editor.api.previous({
|
|
628
|
+
at: editor.selection?.focus
|
|
629
|
+
})?.[0];
|
|
630
|
+
if (previousNode?.listStyleType && previousNode?.listStart) {
|
|
631
|
+
return node;
|
|
632
|
+
} else {
|
|
633
|
+
if (node.listStart === 1) return node;
|
|
634
|
+
return {
|
|
635
|
+
...node,
|
|
636
|
+
listRestartPolite: node.listStart
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return node;
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// src/lib/streaming/utils/isSameNode.ts
|
|
644
|
+
import { isDefined, KEYS as KEYS12 } from "platejs";
|
|
645
|
+
var LIST_STYLE_TYPE = "listStyleType";
|
|
646
|
+
var isSameNode = (editor, node1, node2) => {
|
|
647
|
+
if (node1.type !== editor.getType(KEYS12.p) || node2.type !== editor.getType(KEYS12.p))
|
|
648
|
+
return node1.type === node2.type;
|
|
649
|
+
if (isDefined(node1[LIST_STYLE_TYPE]) || isDefined(node2[LIST_STYLE_TYPE])) {
|
|
650
|
+
return node1[LIST_STYLE_TYPE] === node2[LIST_STYLE_TYPE];
|
|
651
|
+
}
|
|
652
|
+
return node1.type === node2.type;
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// src/lib/streaming/utils/nodesWithProps.ts
|
|
656
|
+
import { ElementApi as ElementApi4 } from "platejs";
|
|
657
|
+
var nodesWithProps = (editor, nodes, options) => {
|
|
658
|
+
return nodes.map((node) => {
|
|
659
|
+
if (ElementApi4.isElement(node)) {
|
|
660
|
+
return {
|
|
661
|
+
...getListNode(editor, node),
|
|
662
|
+
...options.elementProps,
|
|
663
|
+
children: nodesWithProps(editor, node.children, options)
|
|
664
|
+
};
|
|
665
|
+
} else {
|
|
666
|
+
return {
|
|
667
|
+
...options.textProps,
|
|
668
|
+
...node,
|
|
669
|
+
text: node.text
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// src/lib/streaming/utils/utils.ts
|
|
676
|
+
var getChunkTrimmed = (chunk, {
|
|
677
|
+
direction = "right"
|
|
678
|
+
} = {}) => {
|
|
679
|
+
const str = direction === "right" ? chunk.trimEnd() : chunk.trimStart();
|
|
680
|
+
if (direction === "right") {
|
|
681
|
+
return chunk.slice(str.length);
|
|
682
|
+
} else {
|
|
683
|
+
return chunk.slice(0, chunk.length - str.length);
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
function isCompleteCodeBlock(str) {
|
|
687
|
+
const trimmed = str.trim();
|
|
688
|
+
const startsWithCodeBlock = trimmed.startsWith("```");
|
|
689
|
+
const endsWithCodeBlock = trimmed.endsWith("```");
|
|
690
|
+
return startsWithCodeBlock && endsWithCodeBlock;
|
|
691
|
+
}
|
|
692
|
+
function isCompleteMath(str) {
|
|
693
|
+
const trimmed = str.trim();
|
|
694
|
+
const startsWithMath = trimmed.startsWith("$$");
|
|
695
|
+
const endsWithMath = trimmed.endsWith("$$");
|
|
696
|
+
return startsWithMath && endsWithMath;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/lib/streaming/streamDeserializeMd.ts
|
|
700
|
+
var statMdxTagRegex = /<([A-Za-z][A-Za-z0-9\-_]*)>/;
|
|
701
|
+
var streamDeserializeMd = (editor, data, options) => {
|
|
702
|
+
const input = escapeInput(data);
|
|
703
|
+
const value = withoutDeserializeInMdx(editor, input);
|
|
704
|
+
if (Array.isArray(value)) return value;
|
|
705
|
+
let blocks = [];
|
|
706
|
+
blocks = editor.getApi(MarkdownPlugin2).markdown.deserialize(input, {
|
|
707
|
+
...options,
|
|
708
|
+
preserveEmptyParagraphs: false
|
|
709
|
+
});
|
|
710
|
+
const trimmedData = getChunkTrimmed(data);
|
|
711
|
+
const lastBlock = blocks.at(-1);
|
|
712
|
+
const addNewLine = trimmedData === "\n\n";
|
|
713
|
+
const unshiftNewLine = getChunkTrimmed(data, { direction: "left" }) === "\n\n";
|
|
714
|
+
const isCodeBlockOrTable = lastBlock?.type === "code_block" || lastBlock?.type === "table";
|
|
715
|
+
let result = blocks;
|
|
716
|
+
if (lastBlock && !isCodeBlockOrTable && trimmedData.length > 0 && !addNewLine) {
|
|
717
|
+
const textNode = [
|
|
718
|
+
{
|
|
719
|
+
text: trimmedData
|
|
720
|
+
}
|
|
721
|
+
];
|
|
722
|
+
const lastChild = lastBlock.children.at(-1);
|
|
723
|
+
if (lastChild && TextApi3.isText(lastChild) && Object.keys(lastChild).length === 1) {
|
|
724
|
+
lastBlock.children.pop();
|
|
725
|
+
const textNode2 = [
|
|
726
|
+
{
|
|
727
|
+
text: lastChild.text + trimmedData
|
|
728
|
+
}
|
|
729
|
+
];
|
|
730
|
+
lastBlock.children.push(...textNode2);
|
|
731
|
+
} else {
|
|
732
|
+
lastBlock.children.push(...textNode);
|
|
733
|
+
}
|
|
734
|
+
result = [...blocks.slice(0, -1), lastBlock];
|
|
735
|
+
}
|
|
736
|
+
if (addNewLine && !isCodeBlockOrTable) {
|
|
737
|
+
result.push({
|
|
738
|
+
children: [{ text: "" }],
|
|
739
|
+
type: KEYS13.p
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
if (unshiftNewLine && !isCodeBlockOrTable) {
|
|
743
|
+
result.unshift({
|
|
744
|
+
children: [{ text: "" }],
|
|
745
|
+
type: KEYS13.p
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
return result;
|
|
749
|
+
};
|
|
750
|
+
var withoutDeserializeInMdx = (editor, input) => {
|
|
751
|
+
const mdxName = editor.getOption(AIChatPlugin, "_mdxName");
|
|
752
|
+
if (mdxName) {
|
|
753
|
+
const isMdxEnd = input.includes(`</${mdxName}>`);
|
|
754
|
+
if (isMdxEnd) {
|
|
755
|
+
editor.setOption(AIChatPlugin, "_mdxName", null);
|
|
756
|
+
return false;
|
|
757
|
+
} else {
|
|
758
|
+
return [
|
|
759
|
+
{
|
|
760
|
+
children: [
|
|
761
|
+
{
|
|
762
|
+
text: input
|
|
763
|
+
}
|
|
764
|
+
],
|
|
765
|
+
type: getPluginType4(editor, KEYS13.p)
|
|
766
|
+
}
|
|
767
|
+
];
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
const newMdxName = statMdxTagRegex.exec(input)?.[1];
|
|
771
|
+
if (input.startsWith(`<${newMdxName}`)) {
|
|
772
|
+
editor.setOption(AIChatPlugin, "_mdxName", newMdxName ?? null);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// src/lib/streaming/streamInsertChunk.ts
|
|
778
|
+
import {
|
|
779
|
+
getPluginType as getPluginType5,
|
|
780
|
+
KEYS as KEYS15,
|
|
781
|
+
NodeApi as NodeApi2,
|
|
782
|
+
PathApi as PathApi2
|
|
783
|
+
} from "platejs";
|
|
784
|
+
|
|
747
785
|
// src/lib/streaming/streamSerializeMd.ts
|
|
748
786
|
import { MarkdownPlugin as MarkdownPlugin3 } from "@platejs/markdown";
|
|
749
|
-
import {
|
|
750
|
-
|
|
751
|
-
|
|
787
|
+
import {
|
|
788
|
+
ElementApi as ElementApi5,
|
|
789
|
+
getPluginKey,
|
|
790
|
+
KEYS as KEYS14,
|
|
791
|
+
TextApi as TextApi4
|
|
792
|
+
} from "platejs";
|
|
793
|
+
var trimEndHeading = (editor, value) => {
|
|
794
|
+
const headingKeys = /* @__PURE__ */ new Set([
|
|
795
|
+
KEYS14.h1,
|
|
796
|
+
KEYS14.h2,
|
|
797
|
+
KEYS14.h3,
|
|
798
|
+
KEYS14.h4,
|
|
799
|
+
KEYS14.h5,
|
|
800
|
+
KEYS14.h6
|
|
801
|
+
]);
|
|
752
802
|
const lastBlock = value.at(-1);
|
|
753
|
-
if (lastBlock && headingKeys.has(
|
|
803
|
+
if (lastBlock && headingKeys.has(
|
|
804
|
+
getPluginKey(editor, lastBlock.type) ?? lastBlock.type
|
|
805
|
+
) && ElementApi5.isElement(lastBlock)) {
|
|
754
806
|
const lastTextNode = lastBlock.children.at(-1);
|
|
755
807
|
if (TextApi4.isText(lastTextNode)) {
|
|
756
808
|
const trimmedText = getChunkTrimmed(lastTextNode?.text);
|
|
@@ -772,7 +824,7 @@ var trimEndHeading = (value) => {
|
|
|
772
824
|
};
|
|
773
825
|
var streamSerializeMd = (editor, options, chunk) => {
|
|
774
826
|
const { value: optionsValue, ...restOptions } = options;
|
|
775
|
-
const { value } = trimEndHeading(optionsValue ?? editor.children);
|
|
827
|
+
const { value } = trimEndHeading(editor, optionsValue ?? editor.children);
|
|
776
828
|
let result = "";
|
|
777
829
|
result = editor.getApi(MarkdownPlugin3).markdown.serialize({
|
|
778
830
|
preserveEmptyParagraphs: false,
|
|
@@ -804,12 +856,20 @@ var streamSerializeMd = (editor, options, chunk) => {
|
|
|
804
856
|
};
|
|
805
857
|
|
|
806
858
|
// src/lib/streaming/streamInsertChunk.ts
|
|
859
|
+
var getNextPath = (path, length) => {
|
|
860
|
+
let result = path;
|
|
861
|
+
for (let i = 0; i < length; i++) {
|
|
862
|
+
result = PathApi2.next(result);
|
|
863
|
+
}
|
|
864
|
+
return result;
|
|
865
|
+
};
|
|
807
866
|
function streamInsertChunk(editor, chunk, options = {}) {
|
|
808
867
|
const { _blockChunks, _blockPath } = editor.getOptions(AIChatPlugin);
|
|
809
868
|
if (_blockPath === null) {
|
|
810
869
|
const blocks = streamDeserializeMd(editor, chunk);
|
|
811
870
|
const path = getCurrentBlockPath(editor);
|
|
812
|
-
const
|
|
871
|
+
const startBlock = editor.api.node(path)[0];
|
|
872
|
+
const startInEmptyParagraph = NodeApi2.string(startBlock).length === 0 && startBlock.type === getPluginType5(editor, KEYS15.p);
|
|
813
873
|
if (startInEmptyParagraph) {
|
|
814
874
|
editor.tf.removeNodes({ at: path });
|
|
815
875
|
}
|
|
@@ -829,7 +889,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
829
889
|
nextBlock: true,
|
|
830
890
|
select: true
|
|
831
891
|
});
|
|
832
|
-
const lastBlock = editor.api.node(
|
|
892
|
+
const lastBlock = editor.api.node(getNextPath(nextPath, nextBlocks.length));
|
|
833
893
|
editor.setOption(AIChatPlugin, "_blockPath", lastBlock[1]);
|
|
834
894
|
const lastBlockChunks = streamSerializeMd(
|
|
835
895
|
editor,
|
|
@@ -887,7 +947,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
887
947
|
AIChatPlugin,
|
|
888
948
|
"_blockChunks",
|
|
889
949
|
// one block includes multiple children
|
|
890
|
-
tempBlocks[0].type ===
|
|
950
|
+
tempBlocks[0].type === getPluginType5(editor, KEYS15.codeBlock) || tempBlocks[0].type === getPluginType5(editor, KEYS15.table) || tempBlocks[0].type === getPluginType5(editor, KEYS15.equation) ? tempBlockChunks : serializedBlock2
|
|
891
951
|
);
|
|
892
952
|
}
|
|
893
953
|
} else {
|
|
@@ -913,7 +973,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
913
973
|
select: true
|
|
914
974
|
});
|
|
915
975
|
if (tempBlocks.length > 1) {
|
|
916
|
-
const newEndBlockPath =
|
|
976
|
+
const newEndBlockPath = getNextPath(_blockPath, tempBlocks.length - 1);
|
|
917
977
|
editor.tf.insertNodes(
|
|
918
978
|
nodesWithProps(editor, tempBlocks.slice(1), options),
|
|
919
979
|
{
|
|
@@ -936,11 +996,21 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
936
996
|
}
|
|
937
997
|
}
|
|
938
998
|
var getCurrentBlockPath = (editor) => {
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
999
|
+
const getAnchorPreviousPath = (editor2) => {
|
|
1000
|
+
const anchorNode = editor2.getApi(AIChatPlugin).aiChat.node({ anchor: true });
|
|
1001
|
+
if (anchorNode) {
|
|
1002
|
+
return PathApi2.previous(anchorNode[1]);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
const getFocusPath = (editor2) => {
|
|
1006
|
+
return editor2.selection?.focus.path.slice(0, 1);
|
|
1007
|
+
};
|
|
1008
|
+
const path = getAnchorPreviousPath(editor) ?? getFocusPath(editor) ?? [0];
|
|
1009
|
+
const entry = editor.api.node(path);
|
|
1010
|
+
if (entry && (entry[0].type === getPluginType5(editor, KEYS15.columnGroup) || entry[0].type === getPluginType5(editor, KEYS15.table))) {
|
|
1011
|
+
return editor.api.above()?.[1] ?? path;
|
|
942
1012
|
}
|
|
943
|
-
return
|
|
1013
|
+
return path;
|
|
944
1014
|
};
|
|
945
1015
|
export {
|
|
946
1016
|
BaseAIPlugin,
|