@platejs/ai 51.0.0 → 51.0.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/react/index.d.mts +5 -2
- package/dist/react/index.d.ts +5 -2
- package/dist/react/index.js +466 -436
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +363 -338
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -271,24 +271,46 @@ var aiCommentToRange = (editor, aiComment) => {
|
|
|
271
271
|
};
|
|
272
272
|
|
|
273
273
|
// src/react/ai-chat/AIChatPlugin.ts
|
|
274
|
-
import { BlockSelectionPlugin as
|
|
274
|
+
import { BlockSelectionPlugin as BlockSelectionPlugin5 } from "@platejs/selection/react";
|
|
275
275
|
import {
|
|
276
276
|
bindFirst as bindFirst2,
|
|
277
|
-
ElementApi as
|
|
277
|
+
ElementApi as ElementApi4,
|
|
278
278
|
getPluginType as getPluginType3,
|
|
279
|
-
KEYS as
|
|
279
|
+
KEYS as KEYS12
|
|
280
280
|
} from "platejs";
|
|
281
281
|
import { createTPlatePlugin } from "platejs/react";
|
|
282
282
|
|
|
283
283
|
// src/react/ai-chat/transforms/acceptAIChat.ts
|
|
284
|
-
import {
|
|
285
|
-
acceptSuggestion,
|
|
286
|
-
getSuggestionKey,
|
|
287
|
-
getTransientSuggestionKey as getTransientSuggestionKey2
|
|
288
|
-
} from "@platejs/suggestion";
|
|
289
|
-
import { SuggestionPlugin } from "@platejs/suggestion/react";
|
|
290
284
|
import { KEYS as KEYS4 } from "platejs";
|
|
291
285
|
import { getEditorPlugin } from "platejs/react";
|
|
286
|
+
|
|
287
|
+
// src/react/ai-chat/utils/acceptAISuggestions.ts
|
|
288
|
+
import { acceptSuggestion, getSuggestionKey, getTransientSuggestionKey as getTransientSuggestionKey2 } from "@platejs/suggestion";
|
|
289
|
+
import { SuggestionPlugin } from "@platejs/suggestion/react";
|
|
290
|
+
var acceptAISuggestions = (editor) => {
|
|
291
|
+
const suggestions = editor.getApi(SuggestionPlugin).suggestion.nodes({
|
|
292
|
+
transient: true
|
|
293
|
+
});
|
|
294
|
+
suggestions.forEach(([suggestionNode]) => {
|
|
295
|
+
const suggestionData = editor.getApi(SuggestionPlugin).suggestion.suggestionData(suggestionNode);
|
|
296
|
+
if (!suggestionData) return;
|
|
297
|
+
const description = {
|
|
298
|
+
createdAt: new Date(suggestionData.createdAt),
|
|
299
|
+
keyId: getSuggestionKey(suggestionData.id),
|
|
300
|
+
suggestionId: suggestionData.id,
|
|
301
|
+
type: suggestionData.type,
|
|
302
|
+
userId: suggestionData.userId
|
|
303
|
+
};
|
|
304
|
+
acceptSuggestion(editor, description);
|
|
305
|
+
});
|
|
306
|
+
editor.tf.unsetNodes([getTransientSuggestionKey2()], {
|
|
307
|
+
at: [],
|
|
308
|
+
mode: "all",
|
|
309
|
+
match: (n) => !!n[getTransientSuggestionKey2()]
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// src/react/ai-chat/transforms/acceptAIChat.ts
|
|
292
314
|
var acceptAIChat = (editor) => {
|
|
293
315
|
const mode = editor.getOption(AIChatPlugin, "mode");
|
|
294
316
|
if (mode === "insert") {
|
|
@@ -309,49 +331,302 @@ var acceptAIChat = (editor) => {
|
|
|
309
331
|
}
|
|
310
332
|
if (mode === "chat") {
|
|
311
333
|
withAIBatch(editor, () => {
|
|
312
|
-
|
|
334
|
+
acceptAISuggestions(editor);
|
|
313
335
|
});
|
|
314
336
|
editor.getApi(AIChatPlugin).aiChat.hide();
|
|
315
337
|
}
|
|
316
338
|
};
|
|
317
|
-
|
|
318
|
-
|
|
339
|
+
|
|
340
|
+
// src/react/ai-chat/transforms/insertBelowAIChat.ts
|
|
341
|
+
import { BlockSelectionPlugin as BlockSelectionPlugin4 } from "@platejs/selection/react";
|
|
342
|
+
import cloneDeep2 from "lodash/cloneDeep.js";
|
|
343
|
+
import { KEYS as KEYS9, PathApi, RangeApi } from "platejs";
|
|
344
|
+
|
|
345
|
+
// src/react/ai-chat/utils/applyAISuggestions.ts
|
|
346
|
+
import { deserializeMd as deserializeMd2 } from "@platejs/markdown";
|
|
347
|
+
import { BlockSelectionPlugin } from "@platejs/selection/react";
|
|
348
|
+
import {
|
|
349
|
+
diffToSuggestions,
|
|
350
|
+
getTransientSuggestionKey as getTransientSuggestionKey3,
|
|
351
|
+
SkipSuggestionDeletes
|
|
352
|
+
} from "@platejs/suggestion";
|
|
353
|
+
import {
|
|
354
|
+
ElementApi,
|
|
355
|
+
KEYS as KEYS5,
|
|
356
|
+
nanoid,
|
|
357
|
+
TextApi as TextApi2
|
|
358
|
+
} from "platejs";
|
|
359
|
+
var applyAISuggestions = (editor, content) => {
|
|
360
|
+
editor.getApi({ key: KEYS5.cursorOverlay })?.cursorOverlay?.removeCursor("selection");
|
|
361
|
+
const isBlockSelecting = editor.getOption(
|
|
362
|
+
BlockSelectionPlugin,
|
|
363
|
+
"isSelectingSome"
|
|
364
|
+
);
|
|
365
|
+
const { chatNodes } = editor.getOptions(AIChatPlugin);
|
|
366
|
+
if (isBlockSelecting || editor.api.blocks({ mode: "highest" }).length > 1) {
|
|
367
|
+
const setReplaceIds = (ids) => {
|
|
368
|
+
editor.setOption(AIChatPlugin, "_replaceIds", ids);
|
|
369
|
+
};
|
|
370
|
+
if (editor.getOption(AIChatPlugin, "_replaceIds").length === 0) {
|
|
371
|
+
setReplaceIds(chatNodes.map((node) => node.id));
|
|
372
|
+
}
|
|
373
|
+
const diffNodes = getDiffNodes(editor, content);
|
|
374
|
+
const replaceNodes = Array.from(
|
|
375
|
+
editor.api.nodes({
|
|
376
|
+
at: [],
|
|
377
|
+
match: (n) => ElementApi.isElement(n) && editor.getOption(AIChatPlugin, "_replaceIds").includes(n.id)
|
|
378
|
+
})
|
|
379
|
+
);
|
|
380
|
+
replaceNodes.forEach(([node, path], index) => {
|
|
381
|
+
const replaceNode = node;
|
|
382
|
+
const diffNode = diffNodes[index];
|
|
383
|
+
const isSameString = SkipSuggestionDeletes(editor, replaceNode) === SkipSuggestionDeletes(editor, diffNode);
|
|
384
|
+
const isSameSuggestion = replaceNode.suggestion?.type === diffNode.suggestion?.type;
|
|
385
|
+
if (index === replaceNodes.length - 1 && diffNodes.length > replaceNodes.length) {
|
|
386
|
+
editor.tf.replaceNodes(diffNodes.slice(index), {
|
|
387
|
+
at: path
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (isSameString && isSameSuggestion && node.id == diffNode.id) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
editor.tf.replaceNodes(diffNode, {
|
|
394
|
+
at: path
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
editor.getApi(BlockSelectionPlugin).blockSelection.set(diffNodes.map((node) => node.id));
|
|
398
|
+
setReplaceIds(diffNodes.map((node) => node.id));
|
|
399
|
+
} else {
|
|
400
|
+
const diffNodes = getDiffNodes(editor, content);
|
|
401
|
+
editor.tf.insertFragment(diffNodes);
|
|
402
|
+
const nodes = Array.from(
|
|
403
|
+
editor.api.nodes({
|
|
404
|
+
at: [],
|
|
405
|
+
mode: "lowest",
|
|
406
|
+
match: (n) => TextApi2.isText(n) && !!n[getTransientSuggestionKey3()]
|
|
407
|
+
})
|
|
408
|
+
);
|
|
409
|
+
const range = editor.api.nodesRange(nodes);
|
|
410
|
+
editor.tf.setSelection(range);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var withProps = (diffNodes, chatNodes) => {
|
|
415
|
+
return diffNodes.map((node, index) => {
|
|
416
|
+
if (!ElementApi.isElement(node)) return node;
|
|
417
|
+
const originalNode = chatNodes?.[index];
|
|
418
|
+
return {
|
|
419
|
+
...node,
|
|
420
|
+
...originalNode ?? { id: nanoid() },
|
|
421
|
+
children: node.children
|
|
422
|
+
};
|
|
423
|
+
});
|
|
424
|
+
};
|
|
425
|
+
var withTransient = (diffNodes) => {
|
|
426
|
+
return diffNodes.map((node) => {
|
|
427
|
+
if (TextApi2.isText(node)) {
|
|
428
|
+
return {
|
|
429
|
+
...node,
|
|
430
|
+
[getTransientSuggestionKey3()]: true
|
|
431
|
+
};
|
|
432
|
+
} else {
|
|
433
|
+
return {
|
|
434
|
+
...node,
|
|
435
|
+
children: withTransient(node.children),
|
|
436
|
+
[getTransientSuggestionKey3()]: true
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
};
|
|
441
|
+
var withoutSuggestionAndComments = (nodes) => {
|
|
442
|
+
return nodes.map((node) => {
|
|
443
|
+
if (TextApi2.isText(node)) {
|
|
444
|
+
if (node[KEYS5.suggestion] || node[KEYS5.comment]) {
|
|
445
|
+
return {
|
|
446
|
+
text: node.text
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return node;
|
|
450
|
+
}
|
|
451
|
+
if (ElementApi.isElement(node)) {
|
|
452
|
+
if (node[KEYS5.suggestion]) {
|
|
453
|
+
const nodeWithoutSuggestion = {};
|
|
454
|
+
Object.keys(node).forEach((key) => {
|
|
455
|
+
if (key !== KEYS5.suggestion && !key.startsWith(KEYS5.suggestion)) {
|
|
456
|
+
nodeWithoutSuggestion[key] = node[key];
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
return {
|
|
460
|
+
...nodeWithoutSuggestion,
|
|
461
|
+
children: withoutSuggestionAndComments(node.children)
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
...node,
|
|
466
|
+
children: withoutSuggestionAndComments(node.children)
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
return node;
|
|
470
|
+
});
|
|
471
|
+
};
|
|
472
|
+
var getDiffNodes = (editor, aiContent) => {
|
|
473
|
+
const chatNodes = withoutSuggestionAndComments(
|
|
474
|
+
editor.getOption(AIChatPlugin, "chatNodes")
|
|
475
|
+
);
|
|
476
|
+
const aiNodes = withProps(deserializeMd2(editor, aiContent), chatNodes);
|
|
477
|
+
const diffNodes = withTransient(
|
|
478
|
+
diffToSuggestions(editor, chatNodes, aiNodes, {
|
|
479
|
+
ignoreProps: ["id", "listStart"]
|
|
480
|
+
})
|
|
481
|
+
);
|
|
482
|
+
return diffNodes;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// src/react/ai-chat/utils/getLastAssistantMessage.ts
|
|
486
|
+
import { usePluginOption } from "platejs/react";
|
|
487
|
+
function getLastAssistantMessage(editor) {
|
|
488
|
+
const messages = editor.getOptions(AIChatPlugin).chat.messages;
|
|
489
|
+
return messages?.findLast((message) => message.role === "assistant");
|
|
490
|
+
}
|
|
491
|
+
function useLastAssistantMessage() {
|
|
492
|
+
const toolName = usePluginOption(AIChatPlugin, "toolName");
|
|
493
|
+
const chat = usePluginOption(AIChatPlugin, "chat");
|
|
494
|
+
if (toolName === "comment") return;
|
|
495
|
+
return chat.messages?.findLast((message) => message.role === "assistant");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/react/ai-chat/utils/rejectAISuggestions.ts
|
|
499
|
+
import { getSuggestionKey as getSuggestionKey2, getTransientSuggestionKey as getTransientSuggestionKey4, rejectSuggestion } from "@platejs/suggestion";
|
|
500
|
+
import { SuggestionPlugin as SuggestionPlugin2 } from "@platejs/suggestion/react";
|
|
501
|
+
var rejectAISuggestions = (editor) => {
|
|
502
|
+
const suggestions = editor.getApi(SuggestionPlugin2).suggestion.nodes({
|
|
319
503
|
transient: true
|
|
320
504
|
});
|
|
321
505
|
suggestions.forEach(([suggestionNode]) => {
|
|
322
|
-
const suggestionData = editor.getApi(
|
|
506
|
+
const suggestionData = editor.getApi(SuggestionPlugin2).suggestion.suggestionData(suggestionNode);
|
|
323
507
|
if (!suggestionData) return;
|
|
324
508
|
const description = {
|
|
325
509
|
createdAt: new Date(suggestionData.createdAt),
|
|
326
|
-
keyId:
|
|
510
|
+
keyId: getSuggestionKey2(suggestionData.id),
|
|
327
511
|
suggestionId: suggestionData.id,
|
|
328
512
|
type: suggestionData.type,
|
|
329
513
|
userId: suggestionData.userId
|
|
330
514
|
};
|
|
331
|
-
|
|
515
|
+
rejectSuggestion(editor, description);
|
|
332
516
|
});
|
|
333
|
-
editor.tf.unsetNodes([
|
|
517
|
+
editor.tf.unsetNodes([getTransientSuggestionKey4()], {
|
|
334
518
|
at: [],
|
|
335
519
|
mode: "all",
|
|
336
|
-
match: (n) => !!n[
|
|
520
|
+
match: (n) => !!n[getTransientSuggestionKey4()]
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// src/react/ai-chat/utils/resetAIChat.ts
|
|
525
|
+
import { KEYS as KEYS6 } from "platejs";
|
|
526
|
+
import { getEditorPlugin as getEditorPlugin2 } from "platejs/react";
|
|
527
|
+
var resetAIChat = (editor, { undo = true } = {}) => {
|
|
528
|
+
const { api, getOptions, setOptions } = getEditorPlugin2(
|
|
529
|
+
editor,
|
|
530
|
+
{
|
|
531
|
+
key: KEYS6.aiChat
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
api.aiChat.stop();
|
|
535
|
+
const chat = getOptions().chat;
|
|
536
|
+
if (chat.messages && chat.messages.length > 0) {
|
|
537
|
+
chat.setMessages?.([]);
|
|
538
|
+
}
|
|
539
|
+
setOptions({
|
|
540
|
+
_replaceIds: [],
|
|
541
|
+
chatNodes: [],
|
|
542
|
+
mode: "insert",
|
|
543
|
+
toolName: null
|
|
337
544
|
});
|
|
545
|
+
if (undo) {
|
|
546
|
+
editor.getTransforms(AIPlugin).ai.undo();
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// src/react/ai-chat/utils/submitAIChat.ts
|
|
551
|
+
import { isSelecting as isSelecting2 } from "@platejs/selection";
|
|
552
|
+
import { BlockSelectionPlugin as BlockSelectionPlugin2 } from "@platejs/selection/react";
|
|
553
|
+
import { KEYS as KEYS7 } from "platejs";
|
|
554
|
+
import { getEditorPlugin as getEditorPlugin3 } from "platejs/react";
|
|
555
|
+
var submitAIChat = (editor, input, {
|
|
556
|
+
mode,
|
|
557
|
+
options,
|
|
558
|
+
prompt,
|
|
559
|
+
toolName: toolNameProps
|
|
560
|
+
} = {}) => {
|
|
561
|
+
const { getOptions, setOption } = getEditorPlugin3(
|
|
562
|
+
editor,
|
|
563
|
+
{
|
|
564
|
+
key: KEYS7.aiChat
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
const { chat, toolName: toolNameOption } = getOptions();
|
|
568
|
+
const toolName = toolNameProps ?? toolNameOption ?? null;
|
|
569
|
+
if (!prompt && input?.length === 0) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (!prompt) {
|
|
573
|
+
prompt = input;
|
|
574
|
+
}
|
|
575
|
+
if (!mode) {
|
|
576
|
+
mode = isSelecting2(editor) ? "chat" : "insert";
|
|
577
|
+
}
|
|
578
|
+
if (mode === "insert") {
|
|
579
|
+
editor.getTransforms(AIPlugin).ai.undo();
|
|
580
|
+
}
|
|
581
|
+
setOption("mode", mode);
|
|
582
|
+
setOption("toolName", toolName);
|
|
583
|
+
const blocks = editor.getApi(BlockSelectionPlugin2).blockSelection.getNodes();
|
|
584
|
+
const blocksRange = editor.api.nodesRange(blocks);
|
|
585
|
+
const promptText = getEditorPrompt(editor, {
|
|
586
|
+
prompt
|
|
587
|
+
});
|
|
588
|
+
const selection = blocks.length > 0 ? blocksRange : editor.selection;
|
|
589
|
+
let chatNodes;
|
|
590
|
+
if (blocks.length > 0) {
|
|
591
|
+
chatNodes = blocks.map((block) => block[0]);
|
|
592
|
+
} else {
|
|
593
|
+
const selectionBlocks = editor.api.blocks({ mode: "highest" });
|
|
594
|
+
if (selectionBlocks.length > 1) {
|
|
595
|
+
chatNodes = selectionBlocks.map((block) => block[0]);
|
|
596
|
+
} else {
|
|
597
|
+
chatNodes = editor.api.fragment();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
setOption("chatNodes", chatNodes);
|
|
601
|
+
setOption("chatSelection", blocks.length > 0 ? null : editor.selection);
|
|
602
|
+
const ctx = {
|
|
603
|
+
children: editor.children,
|
|
604
|
+
selection: selection ?? null,
|
|
605
|
+
toolName
|
|
606
|
+
};
|
|
607
|
+
void chat.sendMessage?.(
|
|
608
|
+
{
|
|
609
|
+
text: promptText
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
body: {
|
|
613
|
+
ctx
|
|
614
|
+
},
|
|
615
|
+
...options
|
|
616
|
+
}
|
|
617
|
+
);
|
|
338
618
|
};
|
|
339
619
|
|
|
340
|
-
// src/react/ai-chat/transforms/insertBelowAIChat.ts
|
|
341
|
-
import { BlockSelectionPlugin as BlockSelectionPlugin2 } from "@platejs/selection/react";
|
|
342
|
-
import cloneDeep2 from "lodash/cloneDeep.js";
|
|
343
|
-
import { KEYS as KEYS6, PathApi, RangeApi } from "platejs";
|
|
344
|
-
|
|
345
620
|
// src/react/ai-chat/transforms/replaceSelectionAIChat.ts
|
|
346
621
|
import {
|
|
347
|
-
BlockSelectionPlugin,
|
|
622
|
+
BlockSelectionPlugin as BlockSelectionPlugin3,
|
|
348
623
|
removeBlockSelectionNodes
|
|
349
624
|
} from "@platejs/selection/react";
|
|
350
625
|
import cloneDeep from "lodash/cloneDeep.js";
|
|
351
626
|
import {
|
|
352
|
-
KEYS as
|
|
627
|
+
KEYS as KEYS8,
|
|
353
628
|
NodeApi as NodeApi3,
|
|
354
|
-
TextApi as
|
|
629
|
+
TextApi as TextApi3
|
|
355
630
|
} from "platejs";
|
|
356
631
|
var createFormattedBlocks = ({
|
|
357
632
|
blocks,
|
|
@@ -365,7 +640,7 @@ var createFormattedBlocks = ({
|
|
|
365
640
|
const blockProps = NodeApi3.extractProps(sourceNode);
|
|
366
641
|
const textProps = NodeApi3.extractProps(firstTextEntry[0]);
|
|
367
642
|
const applyTextFormatting = (node) => {
|
|
368
|
-
if (
|
|
643
|
+
if (TextApi3.isText(node)) {
|
|
369
644
|
return { ...textProps, ...node };
|
|
370
645
|
}
|
|
371
646
|
if (node.children) {
|
|
@@ -389,10 +664,10 @@ var createFormattedBlocks = ({
|
|
|
389
664
|
var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
390
665
|
if (!sourceEditor || sourceEditor.api.isEmpty()) return;
|
|
391
666
|
const isBlockSelecting = editor.getOption(
|
|
392
|
-
|
|
667
|
+
BlockSelectionPlugin3,
|
|
393
668
|
"isSelectingSome"
|
|
394
669
|
);
|
|
395
|
-
editor.getApi({ key:
|
|
670
|
+
editor.getApi({ key: KEYS8.ai }).aiChat.hide();
|
|
396
671
|
if (!isBlockSelecting) {
|
|
397
672
|
const firstBlock = editor.api.node({
|
|
398
673
|
block: true,
|
|
@@ -405,7 +680,7 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
|
|
|
405
680
|
sourceBlock: firstBlock
|
|
406
681
|
});
|
|
407
682
|
if (!formattedBlocks2) return;
|
|
408
|
-
if (firstBlock[0].type ===
|
|
683
|
+
if (firstBlock[0].type === KEYS8.codeLine && sourceEditor.children[0].type === KEYS8.codeBlock && sourceEditor.children.length === 1) {
|
|
409
684
|
editor.tf.insertFragment(formattedBlocks2[0].children);
|
|
410
685
|
} else {
|
|
411
686
|
editor.tf.insertFragment(formattedBlocks2);
|
|
@@ -417,14 +692,14 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
|
|
|
417
692
|
editor.tf.focus();
|
|
418
693
|
return;
|
|
419
694
|
}
|
|
420
|
-
const blockSelectionApi = editor.getApi(
|
|
695
|
+
const blockSelectionApi = editor.getApi(BlockSelectionPlugin3).blockSelection;
|
|
421
696
|
const selectedBlocks = blockSelectionApi.getNodes();
|
|
422
697
|
if (selectedBlocks.length === 0) return;
|
|
423
698
|
if (format === "none" || format === "single" && selectedBlocks.length > 1) {
|
|
424
699
|
editor.tf.withoutNormalizing(() => {
|
|
425
700
|
removeBlockSelectionNodes(editor);
|
|
426
701
|
editor.tf.withNewBatch(() => {
|
|
427
|
-
editor.getTransforms(
|
|
702
|
+
editor.getTransforms(BlockSelectionPlugin3).blockSelection.insertBlocksAndSelect(
|
|
428
703
|
cloneDeep(sourceEditor.children),
|
|
429
704
|
{
|
|
430
705
|
at: selectedBlocks[0][1]
|
|
@@ -432,7 +707,7 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
|
|
|
432
707
|
);
|
|
433
708
|
});
|
|
434
709
|
});
|
|
435
|
-
editor.getApi(
|
|
710
|
+
editor.getApi(BlockSelectionPlugin3).blockSelection.focus();
|
|
436
711
|
return;
|
|
437
712
|
}
|
|
438
713
|
const [, firstBlockPath] = selectedBlocks[0];
|
|
@@ -445,12 +720,12 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
|
|
|
445
720
|
editor.tf.withoutNormalizing(() => {
|
|
446
721
|
removeBlockSelectionNodes(editor);
|
|
447
722
|
editor.tf.withNewBatch(() => {
|
|
448
|
-
editor.getTransforms(
|
|
723
|
+
editor.getTransforms(BlockSelectionPlugin3).blockSelection.insertBlocksAndSelect(formattedBlocks, {
|
|
449
724
|
at: firstBlockPath
|
|
450
725
|
});
|
|
451
726
|
});
|
|
452
727
|
});
|
|
453
|
-
editor.getApi(
|
|
728
|
+
editor.getApi(BlockSelectionPlugin3).blockSelection.focus();
|
|
454
729
|
};
|
|
455
730
|
|
|
456
731
|
// src/react/ai-chat/transforms/insertBelowAIChat.ts
|
|
@@ -458,10 +733,10 @@ var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
|
458
733
|
const { toolName } = editor.getOptions(AIChatPlugin);
|
|
459
734
|
if (toolName === "generate")
|
|
460
735
|
return insertBelowGenerate(editor, sourceEditor, { format });
|
|
461
|
-
const selectedBlocks = editor.getApi(
|
|
462
|
-
const selectedIds = editor.getOptions(
|
|
736
|
+
const selectedBlocks = editor.getApi(BlockSelectionPlugin4).blockSelection.getNodes();
|
|
737
|
+
const selectedIds = editor.getOptions(BlockSelectionPlugin4).selectedIds;
|
|
463
738
|
editor.getTransforms(AIPlugin).ai.undo();
|
|
464
|
-
const insertBlocksAndSelect = editor.getTransforms(
|
|
739
|
+
const insertBlocksAndSelect = editor.getTransforms(BlockSelectionPlugin4).blockSelection.insertBlocksAndSelect;
|
|
465
740
|
if (!selectedIds || selectedIds.size === 0) return;
|
|
466
741
|
const lastBlock = selectedBlocks.at(-1);
|
|
467
742
|
if (!lastBlock) return;
|
|
@@ -471,7 +746,7 @@ var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
|
471
746
|
at: nextPath,
|
|
472
747
|
insertedCallback: () => {
|
|
473
748
|
withAIBatch(editor, () => {
|
|
474
|
-
|
|
749
|
+
acceptAISuggestions(editor);
|
|
475
750
|
});
|
|
476
751
|
}
|
|
477
752
|
});
|
|
@@ -480,14 +755,14 @@ var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
|
480
755
|
var insertBelowGenerate = (editor, sourceEditor, { format = "single" } = {}) => {
|
|
481
756
|
if (!sourceEditor || sourceEditor.api.isEmpty()) return;
|
|
482
757
|
const isBlockSelecting = editor.getOption(
|
|
483
|
-
|
|
758
|
+
BlockSelectionPlugin4,
|
|
484
759
|
"isSelectingSome"
|
|
485
760
|
);
|
|
486
|
-
editor.getApi({ key:
|
|
487
|
-
const insertBlocksAndSelect = editor.getTransforms(
|
|
761
|
+
editor.getApi({ key: KEYS9.ai }).aiChat.hide();
|
|
762
|
+
const insertBlocksAndSelect = editor.getTransforms(BlockSelectionPlugin4).blockSelection.insertBlocksAndSelect;
|
|
488
763
|
if (isBlockSelecting) {
|
|
489
|
-
const selectedBlocks = editor.getApi(
|
|
490
|
-
const selectedIds = editor.getOptions(
|
|
764
|
+
const selectedBlocks = editor.getApi(BlockSelectionPlugin4).blockSelection.getNodes();
|
|
765
|
+
const selectedIds = editor.getOptions(BlockSelectionPlugin4).selectedIds;
|
|
491
766
|
if (!selectedIds || selectedIds.size === 0) return;
|
|
492
767
|
const lastBlock = selectedBlocks.at(-1);
|
|
493
768
|
if (!lastBlock) return;
|
|
@@ -536,118 +811,22 @@ var insertBelowGenerate = (editor, sourceEditor, { format = "single" } = {}) =>
|
|
|
536
811
|
|
|
537
812
|
// src/react/ai-chat/transforms/removeAnchorAIChat.ts
|
|
538
813
|
import {
|
|
539
|
-
ElementApi,
|
|
814
|
+
ElementApi as ElementApi2,
|
|
540
815
|
getPluginType as getPluginType2,
|
|
541
|
-
KEYS as
|
|
816
|
+
KEYS as KEYS10
|
|
542
817
|
} from "platejs";
|
|
543
818
|
var removeAnchorAIChat = (editor, options) => {
|
|
544
819
|
editor.tf.withoutSaving(() => {
|
|
545
820
|
editor.tf.removeNodes({
|
|
546
821
|
at: [],
|
|
547
|
-
match: (n) =>
|
|
822
|
+
match: (n) => ElementApi2.isElement(n) && n.type === getPluginType2(editor, KEYS10.aiChat),
|
|
548
823
|
...options
|
|
549
824
|
});
|
|
550
825
|
});
|
|
551
826
|
};
|
|
552
827
|
|
|
553
|
-
// src/react/ai-chat/utils/resetAIChat.ts
|
|
554
|
-
import { KEYS as KEYS8 } from "platejs";
|
|
555
|
-
import { getEditorPlugin as getEditorPlugin2 } from "platejs/react";
|
|
556
|
-
var resetAIChat = (editor, { undo = true } = {}) => {
|
|
557
|
-
const { api, getOptions, setOptions } = getEditorPlugin2(
|
|
558
|
-
editor,
|
|
559
|
-
{
|
|
560
|
-
key: KEYS8.aiChat
|
|
561
|
-
}
|
|
562
|
-
);
|
|
563
|
-
api.aiChat.stop();
|
|
564
|
-
const chat = getOptions().chat;
|
|
565
|
-
if (chat.messages && chat.messages.length > 0) {
|
|
566
|
-
chat.setMessages?.([]);
|
|
567
|
-
}
|
|
568
|
-
setOptions({
|
|
569
|
-
_replaceIds: [],
|
|
570
|
-
chatNodes: [],
|
|
571
|
-
mode: "insert",
|
|
572
|
-
toolName: null
|
|
573
|
-
});
|
|
574
|
-
if (undo) {
|
|
575
|
-
editor.getTransforms(AIPlugin).ai.undo();
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
|
|
579
|
-
// src/react/ai-chat/utils/submitAIChat.ts
|
|
580
|
-
import { isSelecting as isSelecting2 } from "@platejs/selection";
|
|
581
|
-
import { BlockSelectionPlugin as BlockSelectionPlugin3 } from "@platejs/selection/react";
|
|
582
|
-
import { KEYS as KEYS9 } from "platejs";
|
|
583
|
-
import { getEditorPlugin as getEditorPlugin3 } from "platejs/react";
|
|
584
|
-
var submitAIChat = (editor, input, {
|
|
585
|
-
mode,
|
|
586
|
-
options,
|
|
587
|
-
prompt,
|
|
588
|
-
toolName: toolNameProps
|
|
589
|
-
} = {}) => {
|
|
590
|
-
const { getOptions, setOption } = getEditorPlugin3(
|
|
591
|
-
editor,
|
|
592
|
-
{
|
|
593
|
-
key: KEYS9.aiChat
|
|
594
|
-
}
|
|
595
|
-
);
|
|
596
|
-
const { chat, toolName: toolNameOption } = getOptions();
|
|
597
|
-
const toolName = toolNameProps ?? toolNameOption ?? null;
|
|
598
|
-
if (!prompt && input?.length === 0) {
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
if (!prompt) {
|
|
602
|
-
prompt = input;
|
|
603
|
-
}
|
|
604
|
-
if (!mode) {
|
|
605
|
-
mode = isSelecting2(editor) ? "chat" : "insert";
|
|
606
|
-
}
|
|
607
|
-
if (mode === "insert") {
|
|
608
|
-
editor.getTransforms(AIPlugin).ai.undo();
|
|
609
|
-
}
|
|
610
|
-
setOption("mode", mode);
|
|
611
|
-
setOption("toolName", toolName);
|
|
612
|
-
const blocks = editor.getApi(BlockSelectionPlugin3).blockSelection.getNodes();
|
|
613
|
-
const blocksRange = editor.api.nodesRange(blocks);
|
|
614
|
-
const promptText = getEditorPrompt(editor, {
|
|
615
|
-
prompt
|
|
616
|
-
});
|
|
617
|
-
const selection = blocks.length > 0 ? blocksRange : editor.selection;
|
|
618
|
-
let chatNodes;
|
|
619
|
-
if (blocks.length > 0) {
|
|
620
|
-
chatNodes = blocks.map((block) => block[0]);
|
|
621
|
-
} else {
|
|
622
|
-
const selectionBlocks = editor.api.blocks({ mode: "highest" });
|
|
623
|
-
if (selectionBlocks.length > 1) {
|
|
624
|
-
chatNodes = selectionBlocks.map((block) => block[0]);
|
|
625
|
-
} else {
|
|
626
|
-
chatNodes = editor.api.fragment();
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
setOption("chatNodes", chatNodes);
|
|
630
|
-
setOption("chatSelection", blocks.length > 0 ? null : editor.selection);
|
|
631
|
-
const ctx = {
|
|
632
|
-
children: editor.children,
|
|
633
|
-
selection: selection ?? null,
|
|
634
|
-
toolName
|
|
635
|
-
};
|
|
636
|
-
void chat.sendMessage?.(
|
|
637
|
-
{
|
|
638
|
-
text: promptText
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
body: {
|
|
642
|
-
ctx
|
|
643
|
-
},
|
|
644
|
-
...options
|
|
645
|
-
}
|
|
646
|
-
);
|
|
647
|
-
};
|
|
648
|
-
|
|
649
828
|
// src/react/ai-chat/withAIChat.ts
|
|
650
|
-
import { ElementApi as
|
|
829
|
+
import { ElementApi as ElementApi3, KEYS as KEYS11 } from "platejs";
|
|
651
830
|
var withAIChat = ({
|
|
652
831
|
api,
|
|
653
832
|
editor,
|
|
@@ -689,11 +868,11 @@ var withAIChat = ({
|
|
|
689
868
|
},
|
|
690
869
|
normalizeNode(entry) {
|
|
691
870
|
const [node, path] = entry;
|
|
692
|
-
if (node[
|
|
871
|
+
if (node[KEYS11.ai] && !getOptions().open) {
|
|
693
872
|
tf.ai.removeMarks({ at: path });
|
|
694
873
|
return;
|
|
695
874
|
}
|
|
696
|
-
if (
|
|
875
|
+
if (ElementApi3.isElement(node) && node.type === type && !getOptions().open) {
|
|
697
876
|
editor.getTransforms(AIChatPlugin).aiChat.removeAnchor({ at: path });
|
|
698
877
|
return;
|
|
699
878
|
}
|
|
@@ -705,7 +884,7 @@ var withAIChat = ({
|
|
|
705
884
|
|
|
706
885
|
// src/react/ai-chat/AIChatPlugin.ts
|
|
707
886
|
var AIChatPlugin = createTPlatePlugin({
|
|
708
|
-
key:
|
|
887
|
+
key: KEYS12.aiChat,
|
|
709
888
|
dependencies: ["ai"],
|
|
710
889
|
node: {
|
|
711
890
|
isElement: true
|
|
@@ -736,7 +915,7 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
736
915
|
if (anchor) {
|
|
737
916
|
return editor.api.node({
|
|
738
917
|
at: [],
|
|
739
|
-
match: (n) =>
|
|
918
|
+
match: (n) => ElementApi4.isElement(n) && n.type === type,
|
|
740
919
|
...rest
|
|
741
920
|
});
|
|
742
921
|
}
|
|
@@ -748,12 +927,12 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
748
927
|
at: path,
|
|
749
928
|
mode: "lowest",
|
|
750
929
|
reverse: true,
|
|
751
|
-
match: (t) => !!t[getPluginType3(editor,
|
|
930
|
+
match: (t) => !!t[getPluginType3(editor, KEYS12.ai)],
|
|
752
931
|
...rest
|
|
753
932
|
});
|
|
754
933
|
}
|
|
755
934
|
return editor.api.node({
|
|
756
|
-
match: (n) => n[getPluginType3(editor,
|
|
935
|
+
match: (n) => n[getPluginType3(editor, KEYS12.ai)],
|
|
757
936
|
...rest
|
|
758
937
|
});
|
|
759
938
|
},
|
|
@@ -763,9 +942,9 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
763
942
|
if (chatSelection) {
|
|
764
943
|
editor.tf.setSelection(chatSelection);
|
|
765
944
|
} else {
|
|
766
|
-
editor.getApi(
|
|
945
|
+
editor.getApi(BlockSelectionPlugin5).blockSelection.set(chatNodes.map((node) => node.id));
|
|
767
946
|
}
|
|
768
|
-
const blocks = editor.getApi(
|
|
947
|
+
const blocks = editor.getApi(BlockSelectionPlugin5).blockSelection.getNodes();
|
|
769
948
|
const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
|
|
770
949
|
const ctx = {
|
|
771
950
|
children: editor.children,
|
|
@@ -791,8 +970,8 @@ var AIChatPlugin = createTPlatePlugin({
|
|
|
791
970
|
api.aiChat.reset({ undo });
|
|
792
971
|
setOption("open", false);
|
|
793
972
|
if (focus) {
|
|
794
|
-
if (editor.getOption(
|
|
795
|
-
editor.getApi(
|
|
973
|
+
if (editor.getOption(BlockSelectionPlugin5, "isSelectingSome")) {
|
|
974
|
+
editor.getApi(BlockSelectionPlugin5).blockSelection.focus();
|
|
796
975
|
} else {
|
|
797
976
|
editor.tf.focus();
|
|
798
977
|
}
|
|
@@ -839,29 +1018,14 @@ var useAIChatEditor = (editor, content, { parser } = {}) => {
|
|
|
839
1018
|
|
|
840
1019
|
// src/react/ai-chat/hooks/useChatChunk.ts
|
|
841
1020
|
import { useEffect as useEffect2, useRef } from "react";
|
|
842
|
-
import { KEYS as
|
|
1021
|
+
import { KEYS as KEYS13 } from "platejs";
|
|
843
1022
|
import { usePluginOption as usePluginOption2 } from "platejs/react";
|
|
844
|
-
|
|
845
|
-
// src/react/ai-chat/utils/getLastAssistantMessage.ts
|
|
846
|
-
import { usePluginOption } from "platejs/react";
|
|
847
|
-
function getLastAssistantMessage(editor) {
|
|
848
|
-
const messages = editor.getOptions(AIChatPlugin).chat.messages;
|
|
849
|
-
return messages?.findLast((message) => message.role === "assistant");
|
|
850
|
-
}
|
|
851
|
-
function useLastAssistantMessage() {
|
|
852
|
-
const toolName = usePluginOption(AIChatPlugin, "toolName");
|
|
853
|
-
const chat = usePluginOption(AIChatPlugin, "chat");
|
|
854
|
-
if (toolName === "comment") return;
|
|
855
|
-
return chat.messages?.findLast((message) => message.role === "assistant");
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// src/react/ai-chat/hooks/useChatChunk.ts
|
|
859
1023
|
var useChatChunk = ({
|
|
860
1024
|
onChunk,
|
|
861
1025
|
onFinish
|
|
862
1026
|
}) => {
|
|
863
1027
|
const { status } = usePluginOption2(
|
|
864
|
-
{ key:
|
|
1028
|
+
{ key: KEYS13.aiChat },
|
|
865
1029
|
"chat"
|
|
866
1030
|
);
|
|
867
1031
|
const isLoading = status === "streaming" || status === "submitted";
|
|
@@ -901,7 +1065,7 @@ var useChatChunk = ({
|
|
|
901
1065
|
|
|
902
1066
|
// src/react/ai-chat/hooks/useEditorChat.ts
|
|
903
1067
|
import { useEffect as useEffect3 } from "react";
|
|
904
|
-
import { BlockSelectionPlugin as
|
|
1068
|
+
import { BlockSelectionPlugin as BlockSelectionPlugin6 } from "@platejs/selection/react";
|
|
905
1069
|
import { useEditorPlugin as useEditorPlugin2, usePluginOption as usePluginOption3 } from "platejs/react";
|
|
906
1070
|
var useEditorChat = ({
|
|
907
1071
|
chat,
|
|
@@ -916,9 +1080,9 @@ var useEditorChat = ({
|
|
|
916
1080
|
onOpenChange?.(open);
|
|
917
1081
|
if (open) {
|
|
918
1082
|
if (onOpenBlockSelection) {
|
|
919
|
-
const blockSelectionApi = editor.getApi(
|
|
1083
|
+
const blockSelectionApi = editor.getApi(BlockSelectionPlugin6).blockSelection;
|
|
920
1084
|
const isBlockSelecting = editor.getOption(
|
|
921
|
-
|
|
1085
|
+
BlockSelectionPlugin6,
|
|
922
1086
|
"isSelectingSome"
|
|
923
1087
|
);
|
|
924
1088
|
if (isBlockSelecting) {
|
|
@@ -946,7 +1110,7 @@ var streamDeserializeInlineMd = (editor, text, options) => {
|
|
|
946
1110
|
|
|
947
1111
|
// src/react/ai-chat/streaming/streamDeserializeMd.ts
|
|
948
1112
|
import { MarkdownPlugin as MarkdownPlugin3 } from "@platejs/markdown";
|
|
949
|
-
import { getPluginType as getPluginType4, KEYS as
|
|
1113
|
+
import { getPluginType as getPluginType4, KEYS as KEYS15, TextApi as TextApi4 } from "platejs";
|
|
950
1114
|
|
|
951
1115
|
// src/react/ai-chat/streaming/utils/utils.ts
|
|
952
1116
|
var getChunkTrimmed = (chunk, {
|
|
@@ -1001,10 +1165,10 @@ var getListNode = (editor, node) => {
|
|
|
1001
1165
|
};
|
|
1002
1166
|
|
|
1003
1167
|
// src/react/ai-chat/streaming/utils/isSameNode.ts
|
|
1004
|
-
import { isDefined, KEYS as
|
|
1168
|
+
import { isDefined, KEYS as KEYS14 } from "platejs";
|
|
1005
1169
|
var LIST_STYLE_TYPE = "listStyleType";
|
|
1006
1170
|
var isSameNode = (editor, node1, node2) => {
|
|
1007
|
-
if (node1.type !== editor.getType(
|
|
1171
|
+
if (node1.type !== editor.getType(KEYS14.p) || node2.type !== editor.getType(KEYS14.p))
|
|
1008
1172
|
return node1.type === node2.type;
|
|
1009
1173
|
if (isDefined(node1[LIST_STYLE_TYPE]) || isDefined(node2[LIST_STYLE_TYPE])) {
|
|
1010
1174
|
return node1[LIST_STYLE_TYPE] === node2[LIST_STYLE_TYPE];
|
|
@@ -1013,10 +1177,10 @@ var isSameNode = (editor, node1, node2) => {
|
|
|
1013
1177
|
};
|
|
1014
1178
|
|
|
1015
1179
|
// src/react/ai-chat/streaming/utils/nodesWithProps.ts
|
|
1016
|
-
import { ElementApi as
|
|
1180
|
+
import { ElementApi as ElementApi5 } from "platejs";
|
|
1017
1181
|
var nodesWithProps = (editor, nodes, options) => {
|
|
1018
1182
|
return nodes.map((node) => {
|
|
1019
|
-
if (
|
|
1183
|
+
if (ElementApi5.isElement(node)) {
|
|
1020
1184
|
return {
|
|
1021
1185
|
...getListNode(editor, node),
|
|
1022
1186
|
...options.elementProps,
|
|
@@ -1056,7 +1220,7 @@ var streamDeserializeMd = (editor, data, options) => {
|
|
|
1056
1220
|
}
|
|
1057
1221
|
];
|
|
1058
1222
|
const lastChild = lastBlock.children.at(-1);
|
|
1059
|
-
if (lastChild &&
|
|
1223
|
+
if (lastChild && TextApi4.isText(lastChild) && Object.keys(lastChild).length === 1) {
|
|
1060
1224
|
lastBlock.children.pop();
|
|
1061
1225
|
const textNode2 = [
|
|
1062
1226
|
{
|
|
@@ -1072,13 +1236,13 @@ var streamDeserializeMd = (editor, data, options) => {
|
|
|
1072
1236
|
if (addNewLine && !isCodeBlockOrTable) {
|
|
1073
1237
|
result.push({
|
|
1074
1238
|
children: [{ text: "" }],
|
|
1075
|
-
type:
|
|
1239
|
+
type: KEYS15.p
|
|
1076
1240
|
});
|
|
1077
1241
|
}
|
|
1078
1242
|
if (unshiftNewLine && !isCodeBlockOrTable) {
|
|
1079
1243
|
result.unshift({
|
|
1080
1244
|
children: [{ text: "" }],
|
|
1081
|
-
type:
|
|
1245
|
+
type: KEYS15.p
|
|
1082
1246
|
});
|
|
1083
1247
|
}
|
|
1084
1248
|
return result;
|
|
@@ -1098,7 +1262,7 @@ var withoutDeserializeInMdx = (editor, input) => {
|
|
|
1098
1262
|
text: input
|
|
1099
1263
|
}
|
|
1100
1264
|
],
|
|
1101
|
-
type: getPluginType4(editor,
|
|
1265
|
+
type: getPluginType4(editor, KEYS15.p)
|
|
1102
1266
|
}
|
|
1103
1267
|
];
|
|
1104
1268
|
}
|
|
@@ -1113,7 +1277,7 @@ var withoutDeserializeInMdx = (editor, input) => {
|
|
|
1113
1277
|
// src/react/ai-chat/streaming/streamInsertChunk.ts
|
|
1114
1278
|
import {
|
|
1115
1279
|
getPluginType as getPluginType5,
|
|
1116
|
-
KEYS as
|
|
1280
|
+
KEYS as KEYS17,
|
|
1117
1281
|
NodeApi as NodeApi4,
|
|
1118
1282
|
PathApi as PathApi2
|
|
1119
1283
|
} from "platejs";
|
|
@@ -1121,26 +1285,26 @@ import {
|
|
|
1121
1285
|
// src/react/ai-chat/streaming/streamSerializeMd.ts
|
|
1122
1286
|
import { MarkdownPlugin as MarkdownPlugin4 } from "@platejs/markdown";
|
|
1123
1287
|
import {
|
|
1124
|
-
ElementApi as
|
|
1288
|
+
ElementApi as ElementApi6,
|
|
1125
1289
|
getPluginKey,
|
|
1126
|
-
KEYS as
|
|
1127
|
-
TextApi as
|
|
1290
|
+
KEYS as KEYS16,
|
|
1291
|
+
TextApi as TextApi5
|
|
1128
1292
|
} from "platejs";
|
|
1129
1293
|
var trimEndHeading = (editor, value) => {
|
|
1130
1294
|
const headingKeys = /* @__PURE__ */ new Set([
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1295
|
+
KEYS16.h1,
|
|
1296
|
+
KEYS16.h2,
|
|
1297
|
+
KEYS16.h3,
|
|
1298
|
+
KEYS16.h4,
|
|
1299
|
+
KEYS16.h5,
|
|
1300
|
+
KEYS16.h6
|
|
1137
1301
|
]);
|
|
1138
1302
|
const lastBlock = value.at(-1);
|
|
1139
1303
|
if (lastBlock && headingKeys.has(
|
|
1140
1304
|
getPluginKey(editor, lastBlock.type) ?? lastBlock.type
|
|
1141
|
-
) &&
|
|
1305
|
+
) && ElementApi6.isElement(lastBlock)) {
|
|
1142
1306
|
const lastTextNode = lastBlock.children.at(-1);
|
|
1143
|
-
if (
|
|
1307
|
+
if (TextApi5.isText(lastTextNode)) {
|
|
1144
1308
|
const trimmedText = getChunkTrimmed(lastTextNode?.text);
|
|
1145
1309
|
const newChildren = [
|
|
1146
1310
|
...lastBlock.children.slice(0, -1),
|
|
@@ -1204,7 +1368,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1204
1368
|
const blocks = streamDeserializeMd(editor, chunk);
|
|
1205
1369
|
const path = getCurrentBlockPath(editor);
|
|
1206
1370
|
const startBlock = editor.api.node(path)[0];
|
|
1207
|
-
const startInEmptyParagraph = NodeApi4.string(startBlock).length === 0 && startBlock.type === getPluginType5(editor,
|
|
1371
|
+
const startInEmptyParagraph = NodeApi4.string(startBlock).length === 0 && startBlock.type === getPluginType5(editor, KEYS17.p);
|
|
1208
1372
|
if (startInEmptyParagraph) {
|
|
1209
1373
|
editor.tf.removeNodes({ at: path });
|
|
1210
1374
|
}
|
|
@@ -1284,7 +1448,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1284
1448
|
AIChatPlugin,
|
|
1285
1449
|
"_blockChunks",
|
|
1286
1450
|
// one block includes multiple children
|
|
1287
|
-
tempBlocks[0].type === getPluginType5(editor,
|
|
1451
|
+
tempBlocks[0].type === getPluginType5(editor, KEYS17.codeBlock) || tempBlocks[0].type === getPluginType5(editor, KEYS17.table) || tempBlocks[0].type === getPluginType5(editor, KEYS17.equation) ? tempBlockChunks : serializedBlock2
|
|
1288
1452
|
);
|
|
1289
1453
|
}
|
|
1290
1454
|
} else {
|
|
@@ -1344,152 +1508,12 @@ var getCurrentBlockPath = (editor) => {
|
|
|
1344
1508
|
};
|
|
1345
1509
|
const path = getAnchorPreviousPath(editor) ?? getFocusPath(editor) ?? [0];
|
|
1346
1510
|
const entry = editor.api.node(path);
|
|
1347
|
-
if (entry && (entry[0].type === getPluginType5(editor,
|
|
1511
|
+
if (entry && (entry[0].type === getPluginType5(editor, KEYS17.columnGroup) || entry[0].type === getPluginType5(editor, KEYS17.table))) {
|
|
1348
1512
|
return editor.api.above()?.[1] ?? path;
|
|
1349
1513
|
}
|
|
1350
1514
|
return path;
|
|
1351
1515
|
};
|
|
1352
1516
|
|
|
1353
|
-
// src/react/ai-chat/utils/applyAISuggestions.ts
|
|
1354
|
-
import { deserializeMd as deserializeMd2 } from "@platejs/markdown";
|
|
1355
|
-
import { BlockSelectionPlugin as BlockSelectionPlugin6 } from "@platejs/selection/react";
|
|
1356
|
-
import {
|
|
1357
|
-
diffToSuggestions,
|
|
1358
|
-
getTransientSuggestionKey as getTransientSuggestionKey3,
|
|
1359
|
-
SkipSuggestionDeletes
|
|
1360
|
-
} from "@platejs/suggestion";
|
|
1361
|
-
import {
|
|
1362
|
-
ElementApi as ElementApi6,
|
|
1363
|
-
KEYS as KEYS17,
|
|
1364
|
-
nanoid,
|
|
1365
|
-
TextApi as TextApi5
|
|
1366
|
-
} from "platejs";
|
|
1367
|
-
var applyAISuggestions = (editor, content) => {
|
|
1368
|
-
editor.getApi({ key: KEYS17.cursorOverlay })?.cursorOverlay?.removeCursor("selection");
|
|
1369
|
-
const isBlockSelecting = editor.getOption(
|
|
1370
|
-
BlockSelectionPlugin6,
|
|
1371
|
-
"isSelectingSome"
|
|
1372
|
-
);
|
|
1373
|
-
const { chatNodes } = editor.getOptions(AIChatPlugin);
|
|
1374
|
-
if (isBlockSelecting || editor.api.blocks({ mode: "highest" }).length > 1) {
|
|
1375
|
-
const setReplaceIds = (ids) => {
|
|
1376
|
-
editor.setOption(AIChatPlugin, "_replaceIds", ids);
|
|
1377
|
-
};
|
|
1378
|
-
if (editor.getOption(AIChatPlugin, "_replaceIds").length === 0) {
|
|
1379
|
-
setReplaceIds(chatNodes.map((node) => node.id));
|
|
1380
|
-
}
|
|
1381
|
-
const diffNodes = getDiffNodes(editor, content);
|
|
1382
|
-
const replaceNodes = Array.from(
|
|
1383
|
-
editor.api.nodes({
|
|
1384
|
-
at: [],
|
|
1385
|
-
match: (n) => ElementApi6.isElement(n) && editor.getOption(AIChatPlugin, "_replaceIds").includes(n.id)
|
|
1386
|
-
})
|
|
1387
|
-
);
|
|
1388
|
-
replaceNodes.forEach(([node, path], index) => {
|
|
1389
|
-
const replaceNode = node;
|
|
1390
|
-
const diffNode = diffNodes[index];
|
|
1391
|
-
const isSameString = SkipSuggestionDeletes(editor, replaceNode) === SkipSuggestionDeletes(editor, diffNode);
|
|
1392
|
-
const isSameSuggestion = replaceNode.suggestion?.type === diffNode.suggestion?.type;
|
|
1393
|
-
if (index === replaceNodes.length - 1 && diffNodes.length > replaceNodes.length) {
|
|
1394
|
-
editor.tf.replaceNodes(diffNodes.slice(index), {
|
|
1395
|
-
at: path
|
|
1396
|
-
});
|
|
1397
|
-
}
|
|
1398
|
-
if (isSameString && isSameSuggestion && node.id == diffNode.id) {
|
|
1399
|
-
return;
|
|
1400
|
-
}
|
|
1401
|
-
editor.tf.replaceNodes(diffNode, {
|
|
1402
|
-
at: path
|
|
1403
|
-
});
|
|
1404
|
-
});
|
|
1405
|
-
editor.getApi(BlockSelectionPlugin6).blockSelection.set(diffNodes.map((node) => node.id));
|
|
1406
|
-
setReplaceIds(diffNodes.map((node) => node.id));
|
|
1407
|
-
} else {
|
|
1408
|
-
const diffNodes = getDiffNodes(editor, content);
|
|
1409
|
-
editor.tf.insertFragment(diffNodes);
|
|
1410
|
-
const nodes = Array.from(
|
|
1411
|
-
editor.api.nodes({
|
|
1412
|
-
at: [],
|
|
1413
|
-
mode: "lowest",
|
|
1414
|
-
match: (n) => TextApi5.isText(n) && !!n[getTransientSuggestionKey3()]
|
|
1415
|
-
})
|
|
1416
|
-
);
|
|
1417
|
-
const range = editor.api.nodesRange(nodes);
|
|
1418
|
-
editor.tf.setSelection(range);
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
};
|
|
1422
|
-
var withProps = (diffNodes, chatNodes) => {
|
|
1423
|
-
return diffNodes.map((node, index) => {
|
|
1424
|
-
if (!ElementApi6.isElement(node)) return node;
|
|
1425
|
-
const originalNode = chatNodes?.[index];
|
|
1426
|
-
return {
|
|
1427
|
-
...node,
|
|
1428
|
-
...originalNode ?? { id: nanoid() },
|
|
1429
|
-
children: node.children
|
|
1430
|
-
};
|
|
1431
|
-
});
|
|
1432
|
-
};
|
|
1433
|
-
var withTransient = (diffNodes) => {
|
|
1434
|
-
return diffNodes.map((node) => {
|
|
1435
|
-
if (TextApi5.isText(node)) {
|
|
1436
|
-
return {
|
|
1437
|
-
...node,
|
|
1438
|
-
[getTransientSuggestionKey3()]: true
|
|
1439
|
-
};
|
|
1440
|
-
} else {
|
|
1441
|
-
return {
|
|
1442
|
-
...node,
|
|
1443
|
-
children: withTransient(node.children),
|
|
1444
|
-
[getTransientSuggestionKey3()]: true
|
|
1445
|
-
};
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
};
|
|
1449
|
-
var withoutSuggestionAndComments = (nodes) => {
|
|
1450
|
-
return nodes.map((node) => {
|
|
1451
|
-
if (TextApi5.isText(node)) {
|
|
1452
|
-
if (node[KEYS17.suggestion] || node[KEYS17.comment]) {
|
|
1453
|
-
return {
|
|
1454
|
-
text: node.text
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
|
-
return node;
|
|
1458
|
-
}
|
|
1459
|
-
if (ElementApi6.isElement(node)) {
|
|
1460
|
-
if (node[KEYS17.suggestion]) {
|
|
1461
|
-
const nodeWithoutSuggestion = {};
|
|
1462
|
-
Object.keys(node).forEach((key) => {
|
|
1463
|
-
if (key !== KEYS17.suggestion && !key.startsWith(KEYS17.suggestion)) {
|
|
1464
|
-
nodeWithoutSuggestion[key] = node[key];
|
|
1465
|
-
}
|
|
1466
|
-
});
|
|
1467
|
-
return {
|
|
1468
|
-
...nodeWithoutSuggestion,
|
|
1469
|
-
children: withoutSuggestionAndComments(node.children)
|
|
1470
|
-
};
|
|
1471
|
-
}
|
|
1472
|
-
return {
|
|
1473
|
-
...node,
|
|
1474
|
-
children: withoutSuggestionAndComments(node.children)
|
|
1475
|
-
};
|
|
1476
|
-
}
|
|
1477
|
-
return node;
|
|
1478
|
-
});
|
|
1479
|
-
};
|
|
1480
|
-
var getDiffNodes = (editor, aiContent) => {
|
|
1481
|
-
const chatNodes = withoutSuggestionAndComments(
|
|
1482
|
-
editor.getOption(AIChatPlugin, "chatNodes")
|
|
1483
|
-
);
|
|
1484
|
-
const aiNodes = withProps(deserializeMd2(editor, aiContent), chatNodes);
|
|
1485
|
-
const diffNodes = withTransient(
|
|
1486
|
-
diffToSuggestions(editor, chatNodes, aiNodes, {
|
|
1487
|
-
ignoreProps: ["id", "listStart"]
|
|
1488
|
-
})
|
|
1489
|
-
);
|
|
1490
|
-
return diffNodes;
|
|
1491
|
-
};
|
|
1492
|
-
|
|
1493
1517
|
// src/react/copilot/CopilotPlugin.tsx
|
|
1494
1518
|
import { serializeMd } from "@platejs/markdown";
|
|
1495
1519
|
import debounce from "lodash/debounce.js";
|
|
@@ -1918,9 +1942,9 @@ export {
|
|
|
1918
1942
|
AIPlugin,
|
|
1919
1943
|
CopilotPlugin,
|
|
1920
1944
|
acceptAIChat,
|
|
1945
|
+
acceptAISuggestions,
|
|
1921
1946
|
acceptCopilot,
|
|
1922
1947
|
acceptCopilotNextWord,
|
|
1923
|
-
acceptSuggestions,
|
|
1924
1948
|
aiCommentToRange,
|
|
1925
1949
|
applyAISuggestions,
|
|
1926
1950
|
callCompletionApi,
|
|
@@ -1938,6 +1962,7 @@ export {
|
|
|
1938
1962
|
isCompleteMath,
|
|
1939
1963
|
isSameNode,
|
|
1940
1964
|
nodesWithProps,
|
|
1965
|
+
rejectAISuggestions,
|
|
1941
1966
|
removeAnchorAIChat,
|
|
1942
1967
|
renderCopilotBelowNodes,
|
|
1943
1968
|
replaceSelectionAIChat,
|