@platejs/ai 50.1.2 → 50.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.
@@ -36,7 +36,9 @@ __export(react_exports, {
36
36
  acceptAIChat: () => acceptAIChat,
37
37
  acceptCopilot: () => acceptCopilot,
38
38
  acceptCopilotNextWord: () => acceptCopilotNextWord,
39
+ acceptSuggestions: () => acceptSuggestions,
39
40
  aiCommentToRange: () => aiCommentToRange,
41
+ applyAISuggestions: () => applyAISuggestions,
40
42
  callCompletionApi: () => callCompletionApi,
41
43
  createFormattedBlocks: () => createFormattedBlocks,
42
44
  escapeInput: () => escapeInput,
@@ -47,6 +49,7 @@ __export(react_exports, {
47
49
  getListNode: () => getListNode,
48
50
  getNextWord: () => getNextWord,
49
51
  insertBelowAIChat: () => insertBelowAIChat,
52
+ insertBelowGenerate: () => insertBelowGenerate,
50
53
  isCompleteCodeBlock: () => isCompleteCodeBlock,
51
54
  isCompleteMath: () => isCompleteMath,
52
55
  isSameNode: () => isSameNode,
@@ -115,11 +118,16 @@ var removeAINodes = (editor, { at = [] } = {}) => {
115
118
  };
116
119
 
117
120
  // src/lib/transforms/undoAI.ts
121
+ var import_suggestion = require("@platejs/suggestion");
118
122
  var undoAI = (editor) => {
119
- if (editor.history.undos.at(-1)?.ai && editor.api.some({
123
+ const hasAINodeOrAISuggestion = editor.api.some({
120
124
  at: [],
121
125
  match: (n) => !!n.ai
122
- })) {
126
+ }) || editor.api.some({
127
+ at: [],
128
+ match: (n) => !!n[(0, import_suggestion.getTransientSuggestionKey)()]
129
+ });
130
+ if (editor.history.undos.at(-1)?.ai && hasAINodeOrAISuggestion) {
123
131
  editor.undo();
124
132
  editor.history.redos.pop();
125
133
  }
@@ -2982,37 +2990,70 @@ var aiCommentToRange = (editor, aiComment) => {
2982
2990
  };
2983
2991
 
2984
2992
  // src/react/ai-chat/AIChatPlugin.ts
2985
- var import_react8 = require("@platejs/selection/react");
2993
+ var import_react9 = require("@platejs/selection/react");
2986
2994
  var import_platejs13 = require("platejs");
2987
- var import_react9 = require("platejs/react");
2995
+ var import_react10 = require("platejs/react");
2988
2996
 
2989
2997
  // src/react/ai-chat/transforms/acceptAIChat.ts
2998
+ var import_suggestion2 = require("@platejs/suggestion");
2999
+ var import_react2 = require("@platejs/suggestion/react");
2990
3000
  var import_platejs6 = require("platejs");
2991
- var import_react2 = require("platejs/react");
3001
+ var import_react3 = require("platejs/react");
2992
3002
  var acceptAIChat = (editor) => {
2993
- const { tf } = (0, import_react2.getEditorPlugin)(editor, AIPlugin);
2994
- const api = editor.getApi({ key: import_platejs6.KEYS.ai });
2995
- const lastAINodePath = api.aiChat.node({ at: [], reverse: true })[1];
2996
- withAIBatch(editor, () => {
2997
- tf.ai.removeMarks();
2998
- editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();
3003
+ const mode = editor.getOption(AIChatPlugin, "mode");
3004
+ if (mode === "insert") {
3005
+ const { tf } = (0, import_react3.getEditorPlugin)(editor, AIPlugin);
3006
+ const api = editor.getApi({ key: import_platejs6.KEYS.ai });
3007
+ const lastAINodePath = api.aiChat.node({ at: [], reverse: true })[1];
3008
+ withAIBatch(editor, () => {
3009
+ tf.ai.removeMarks();
3010
+ editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();
3011
+ });
3012
+ api.aiChat.hide();
3013
+ editor.tf.focus();
3014
+ const focusPoint = editor.api.end(lastAINodePath);
3015
+ editor.tf.setSelection({
3016
+ anchor: focusPoint,
3017
+ focus: focusPoint
3018
+ });
3019
+ }
3020
+ if (mode === "chat") {
3021
+ withAIBatch(editor, () => {
3022
+ acceptSuggestions(editor);
3023
+ });
3024
+ editor.getApi(AIChatPlugin).aiChat.hide();
3025
+ }
3026
+ };
3027
+ var acceptSuggestions = (editor) => {
3028
+ const suggestions = editor.getApi(import_react2.SuggestionPlugin).suggestion.nodes({
3029
+ transient: true
3030
+ });
3031
+ suggestions.forEach(([suggestionNode]) => {
3032
+ const suggestionData = editor.getApi(import_react2.SuggestionPlugin).suggestion.suggestionData(suggestionNode);
3033
+ if (!suggestionData) return;
3034
+ const description = {
3035
+ createdAt: new Date(suggestionData.createdAt),
3036
+ keyId: (0, import_suggestion2.getSuggestionKey)(suggestionData.id),
3037
+ suggestionId: suggestionData.id,
3038
+ type: suggestionData.type,
3039
+ userId: suggestionData.userId
3040
+ };
3041
+ (0, import_suggestion2.acceptSuggestion)(editor, description);
2999
3042
  });
3000
- api.aiChat.hide();
3001
- editor.tf.focus();
3002
- const focusPoint = editor.api.end(lastAINodePath);
3003
- editor.tf.setSelection({
3004
- anchor: focusPoint,
3005
- focus: focusPoint
3043
+ editor.tf.unsetNodes([(0, import_suggestion2.getTransientSuggestionKey)()], {
3044
+ at: [],
3045
+ mode: "all",
3046
+ match: (n) => !!n[(0, import_suggestion2.getTransientSuggestionKey)()]
3006
3047
  });
3007
3048
  };
3008
3049
 
3009
3050
  // src/react/ai-chat/transforms/insertBelowAIChat.ts
3010
- var import_react4 = require("@platejs/selection/react");
3051
+ var import_react5 = require("@platejs/selection/react");
3011
3052
  var import_cloneDeep2 = __toESM(require("lodash/cloneDeep.js"));
3012
3053
  var import_platejs8 = require("platejs");
3013
3054
 
3014
3055
  // src/react/ai-chat/transforms/replaceSelectionAIChat.ts
3015
- var import_react3 = require("@platejs/selection/react");
3056
+ var import_react4 = require("@platejs/selection/react");
3016
3057
  var import_cloneDeep = __toESM(require("lodash/cloneDeep.js"));
3017
3058
  var import_platejs7 = require("platejs");
3018
3059
  var createFormattedBlocks = ({
@@ -3051,7 +3092,7 @@ var createFormattedBlocks = ({
3051
3092
  var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
3052
3093
  if (!sourceEditor || sourceEditor.api.isEmpty()) return;
3053
3094
  const isBlockSelecting = editor.getOption(
3054
- import_react3.BlockSelectionPlugin,
3095
+ import_react4.BlockSelectionPlugin,
3055
3096
  "isSelectingSome"
3056
3097
  );
3057
3098
  editor.getApi({ key: import_platejs7.KEYS.ai }).aiChat.hide();
@@ -3079,14 +3120,14 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
3079
3120
  editor.tf.focus();
3080
3121
  return;
3081
3122
  }
3082
- const blockSelectionApi = editor.getApi(import_react3.BlockSelectionPlugin).blockSelection;
3123
+ const blockSelectionApi = editor.getApi(import_react4.BlockSelectionPlugin).blockSelection;
3083
3124
  const selectedBlocks = blockSelectionApi.getNodes();
3084
3125
  if (selectedBlocks.length === 0) return;
3085
3126
  if (format === "none" || format === "single" && selectedBlocks.length > 1) {
3086
3127
  editor.tf.withoutNormalizing(() => {
3087
- (0, import_react3.removeBlockSelectionNodes)(editor);
3128
+ (0, import_react4.removeBlockSelectionNodes)(editor);
3088
3129
  editor.tf.withNewBatch(() => {
3089
- editor.getTransforms(import_react3.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(
3130
+ editor.getTransforms(import_react4.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(
3090
3131
  (0, import_cloneDeep.default)(sourceEditor.children),
3091
3132
  {
3092
3133
  at: selectedBlocks[0][1]
@@ -3094,7 +3135,7 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
3094
3135
  );
3095
3136
  });
3096
3137
  });
3097
- editor.getApi(import_react3.BlockSelectionPlugin).blockSelection.focus();
3138
+ editor.getApi(import_react4.BlockSelectionPlugin).blockSelection.focus();
3098
3139
  return;
3099
3140
  }
3100
3141
  const [, firstBlockPath] = selectedBlocks[0];
@@ -3105,28 +3146,51 @@ var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {})
3105
3146
  });
3106
3147
  if (!formattedBlocks) return;
3107
3148
  editor.tf.withoutNormalizing(() => {
3108
- (0, import_react3.removeBlockSelectionNodes)(editor);
3149
+ (0, import_react4.removeBlockSelectionNodes)(editor);
3109
3150
  editor.tf.withNewBatch(() => {
3110
- editor.getTransforms(import_react3.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(formattedBlocks, {
3151
+ editor.getTransforms(import_react4.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(formattedBlocks, {
3111
3152
  at: firstBlockPath
3112
3153
  });
3113
3154
  });
3114
3155
  });
3115
- editor.getApi(import_react3.BlockSelectionPlugin).blockSelection.focus();
3156
+ editor.getApi(import_react4.BlockSelectionPlugin).blockSelection.focus();
3116
3157
  };
3117
3158
 
3118
3159
  // src/react/ai-chat/transforms/insertBelowAIChat.ts
3119
3160
  var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
3161
+ const { toolName } = editor.getOptions(AIChatPlugin);
3162
+ if (toolName === "generate")
3163
+ return insertBelowGenerate(editor, sourceEditor, { format });
3164
+ const selectedBlocks = editor.getApi(import_react5.BlockSelectionPlugin).blockSelection.getNodes();
3165
+ const selectedIds = editor.getOptions(import_react5.BlockSelectionPlugin).selectedIds;
3166
+ editor.getTransforms(AIPlugin).ai.undo();
3167
+ const insertBlocksAndSelect = editor.getTransforms(import_react5.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect;
3168
+ if (!selectedIds || selectedIds.size === 0) return;
3169
+ const lastBlock = selectedBlocks.at(-1);
3170
+ if (!lastBlock) return;
3171
+ const nextPath = import_platejs8.PathApi.next(lastBlock[1]);
3172
+ const nodes = selectedBlocks.map((block) => block[0]);
3173
+ insertBlocksAndSelect(nodes, {
3174
+ at: nextPath,
3175
+ insertedCallback: () => {
3176
+ withAIBatch(editor, () => {
3177
+ acceptSuggestions(editor);
3178
+ });
3179
+ }
3180
+ });
3181
+ editor.getApi(AIChatPlugin).aiChat.hide({ focus: false });
3182
+ };
3183
+ var insertBelowGenerate = (editor, sourceEditor, { format = "single" } = {}) => {
3120
3184
  if (!sourceEditor || sourceEditor.api.isEmpty()) return;
3121
3185
  const isBlockSelecting = editor.getOption(
3122
- import_react4.BlockSelectionPlugin,
3186
+ import_react5.BlockSelectionPlugin,
3123
3187
  "isSelectingSome"
3124
3188
  );
3125
3189
  editor.getApi({ key: import_platejs8.KEYS.ai }).aiChat.hide();
3126
- const insertBlocksAndSelect = editor.getTransforms(import_react4.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect;
3190
+ const insertBlocksAndSelect = editor.getTransforms(import_react5.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect;
3127
3191
  if (isBlockSelecting) {
3128
- const selectedBlocks = editor.getApi(import_react4.BlockSelectionPlugin).blockSelection.getNodes();
3129
- const selectedIds = editor.getOptions(import_react4.BlockSelectionPlugin).selectedIds;
3192
+ const selectedBlocks = editor.getApi(import_react5.BlockSelectionPlugin).blockSelection.getNodes();
3193
+ const selectedIds = editor.getOptions(import_react5.BlockSelectionPlugin).selectedIds;
3130
3194
  if (!selectedIds || selectedIds.size === 0) return;
3131
3195
  const lastBlock = selectedBlocks.at(-1);
3132
3196
  if (!lastBlock) return;
@@ -3187,31 +3251,40 @@ var removeAnchorAIChat = (editor, options) => {
3187
3251
 
3188
3252
  // src/react/ai-chat/utils/resetAIChat.ts
3189
3253
  var import_platejs10 = require("platejs");
3190
- var import_react5 = require("platejs/react");
3254
+ var import_react6 = require("platejs/react");
3191
3255
  var resetAIChat = (editor) => {
3192
- const { api, getOptions } = (0, import_react5.getEditorPlugin)(editor, {
3193
- key: import_platejs10.KEYS.aiChat
3194
- });
3256
+ const { api, getOptions, setOptions } = (0, import_react6.getEditorPlugin)(
3257
+ editor,
3258
+ {
3259
+ key: import_platejs10.KEYS.aiChat
3260
+ }
3261
+ );
3195
3262
  api.aiChat.stop();
3196
3263
  const chat = getOptions().chat;
3197
3264
  if (chat.messages && chat.messages.length > 0) {
3198
3265
  chat.setMessages?.([]);
3199
3266
  }
3267
+ setOptions({
3268
+ _replaceIds: [],
3269
+ chatNodes: [],
3270
+ mode: "insert",
3271
+ toolName: "generate"
3272
+ });
3200
3273
  editor.getTransforms(AIPlugin).ai.undo();
3201
3274
  };
3202
3275
 
3203
3276
  // src/react/ai-chat/utils/submitAIChat.ts
3204
3277
  var import_selection2 = require("@platejs/selection");
3205
- var import_react6 = require("@platejs/selection/react");
3278
+ var import_react7 = require("@platejs/selection/react");
3206
3279
  var import_platejs11 = require("platejs");
3207
- var import_react7 = require("platejs/react");
3280
+ var import_react8 = require("platejs/react");
3208
3281
  var submitAIChat = (editor, input, {
3209
3282
  mode,
3210
3283
  options,
3211
3284
  prompt,
3212
3285
  toolName
3213
3286
  } = {}) => {
3214
- const { getOptions, setOption } = (0, import_react7.getEditorPlugin)(
3287
+ const { getOptions, setOption } = (0, import_react8.getEditorPlugin)(
3215
3288
  editor,
3216
3289
  {
3217
3290
  key: import_platejs11.KEYS.aiChat
@@ -3232,11 +3305,15 @@ var submitAIChat = (editor, input, {
3232
3305
  }
3233
3306
  setOption("mode", mode);
3234
3307
  setOption("toolName", toolName ?? null);
3235
- const blocks = editor.getApi(import_react6.BlockSelectionPlugin).blockSelection.getNodes();
3308
+ const blocks = editor.getApi(import_react7.BlockSelectionPlugin).blockSelection.getNodes();
3309
+ const blocksRange = editor.api.nodesRange(blocks);
3236
3310
  const promptText = getEditorPrompt(editor, {
3237
3311
  prompt
3238
3312
  });
3239
- const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
3313
+ const selection = blocks.length > 0 ? blocksRange : editor.selection;
3314
+ const chatNodes = blocks.length > 0 ? blocks.map((block) => block[0]) : editor.api.fragment();
3315
+ setOption("chatNodes", chatNodes);
3316
+ setOption("chatSelection", blocks.length > 0 ? null : editor.selection);
3240
3317
  const ctx = {
3241
3318
  children: editor.children,
3242
3319
  selection: selection ?? null,
@@ -3261,7 +3338,7 @@ var withAIChat = ({
3261
3338
  api,
3262
3339
  editor,
3263
3340
  getOptions,
3264
- tf: { insertText, normalizeNode, setSelection },
3341
+ tf: { apply, insertText, normalizeNode },
3265
3342
  type
3266
3343
  }) => {
3267
3344
  const tf = editor.getTransforms(AIPlugin);
@@ -3313,7 +3390,7 @@ var withAIChat = ({
3313
3390
  };
3314
3391
 
3315
3392
  // src/react/ai-chat/AIChatPlugin.ts
3316
- var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3393
+ var AIChatPlugin = (0, import_react10.createTPlatePlugin)({
3317
3394
  key: import_platejs13.KEYS.aiChat,
3318
3395
  dependencies: ["ai"],
3319
3396
  node: {
@@ -3323,8 +3400,11 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3323
3400
  _blockChunks: "",
3324
3401
  _blockPath: null,
3325
3402
  _mdxName: null,
3403
+ _replaceIds: [],
3326
3404
  aiEditor: null,
3327
3405
  chat: { messages: [] },
3406
+ chatNodes: [],
3407
+ chatSelection: null,
3328
3408
  experimental_lastTextId: null,
3329
3409
  mode: "insert",
3330
3410
  open: false,
@@ -3364,11 +3444,25 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3364
3444
  });
3365
3445
  },
3366
3446
  reload: () => {
3367
- const { chat, mode } = getOptions();
3368
- if (mode === "insert") {
3369
- editor.getTransforms(AIPlugin).ai.undo();
3447
+ const { chat, chatNodes, chatSelection } = getOptions();
3448
+ editor.getTransforms(AIPlugin).ai.undo();
3449
+ if (chatSelection) {
3450
+ editor.tf.setSelection(chatSelection);
3451
+ } else {
3452
+ editor.getApi(import_react9.BlockSelectionPlugin).blockSelection.set(chatNodes.map((node) => node.id));
3370
3453
  }
3371
- void chat.regenerate?.();
3454
+ const blocks = editor.getApi(import_react9.BlockSelectionPlugin).blockSelection.getNodes();
3455
+ const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
3456
+ const ctx = {
3457
+ children: editor.children,
3458
+ selection: selection ?? null,
3459
+ toolName: getOption("toolName")
3460
+ };
3461
+ void chat.regenerate?.({
3462
+ body: {
3463
+ ctx
3464
+ }
3465
+ });
3372
3466
  },
3373
3467
  stop: () => {
3374
3468
  setOption("streaming", false);
@@ -3376,12 +3470,15 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3376
3470
  }
3377
3471
  };
3378
3472
  }).extendApi(({ api, editor, getOptions, setOption, tf, type }) => ({
3379
- hide: () => {
3473
+ hide: ({ focus = true } = {}) => {
3380
3474
  api.aiChat.reset();
3381
3475
  setOption("open", false);
3382
- if (editor.getOption(import_react8.BlockSelectionPlugin, "isSelectingSome")) {
3383
- } else {
3384
- editor.tf.focus();
3476
+ if (focus) {
3477
+ if (editor.getOption(import_react9.BlockSelectionPlugin, "isSelectingSome")) {
3478
+ editor.getApi(import_react9.BlockSelectionPlugin).blockSelection.focus();
3479
+ } else {
3480
+ editor.tf.focus();
3481
+ }
3385
3482
  }
3386
3483
  const lastBatch = editor.history.undos.at(-1);
3387
3484
  if (lastBatch?.ai) {
@@ -3391,6 +3488,7 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3391
3488
  },
3392
3489
  show: () => {
3393
3490
  api.aiChat.reset();
3491
+ setOption("toolName", null);
3394
3492
  getOptions().chat.setMessages?.([]);
3395
3493
  setOption("open", true);
3396
3494
  }
@@ -3402,12 +3500,12 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3402
3500
  }));
3403
3501
 
3404
3502
  // src/react/ai-chat/hooks/useAIChatEditor.ts
3405
- var import_react10 = require("react");
3503
+ var import_react11 = require("react");
3406
3504
  var import_markdown2 = require("@platejs/markdown");
3407
- var import_react11 = require("platejs/react");
3505
+ var import_react12 = require("platejs/react");
3408
3506
  var useAIChatEditor = (editor, content, { parser } = {}) => {
3409
- const { setOption } = (0, import_react11.useEditorPlugin)(AIChatPlugin);
3410
- editor.children = (0, import_react10.useMemo)(
3507
+ const { setOption } = (0, import_react12.useEditorPlugin)(AIChatPlugin);
3508
+ editor.children = (0, import_react11.useMemo)(
3411
3509
  () => {
3412
3510
  return editor.getApi(import_markdown2.MarkdownPlugin).markdown.deserialize(content, {
3413
3511
  memoize: true,
@@ -3417,25 +3515,25 @@ var useAIChatEditor = (editor, content, { parser } = {}) => {
3417
3515
  // eslint-disable-next-line react-hooks/exhaustive-deps
3418
3516
  [content]
3419
3517
  );
3420
- (0, import_react10.useEffect)(() => {
3518
+ (0, import_react11.useEffect)(() => {
3421
3519
  setOption("aiEditor", editor);
3422
3520
  }, [editor, setOption]);
3423
3521
  };
3424
3522
 
3425
3523
  // src/react/ai-chat/hooks/useChatChunk.ts
3426
- var import_react13 = require("react");
3524
+ var import_react14 = require("react");
3427
3525
  var import_platejs14 = require("platejs");
3428
- var import_react14 = require("platejs/react");
3526
+ var import_react15 = require("platejs/react");
3429
3527
 
3430
3528
  // src/react/ai-chat/utils/getLastAssistantMessage.ts
3431
- var import_react12 = require("platejs/react");
3529
+ var import_react13 = require("platejs/react");
3432
3530
  function getLastAssistantMessage(editor) {
3433
3531
  const messages = editor.getOptions(AIChatPlugin).chat.messages;
3434
3532
  return messages?.findLast((message) => message.role === "assistant");
3435
3533
  }
3436
3534
  function useLastAssistantMessage() {
3437
- const toolName = (0, import_react12.usePluginOption)(AIChatPlugin, "toolName");
3438
- const chat = (0, import_react12.usePluginOption)(AIChatPlugin, "chat");
3535
+ const toolName = (0, import_react13.usePluginOption)(AIChatPlugin, "toolName");
3536
+ const chat = (0, import_react13.usePluginOption)(AIChatPlugin, "chat");
3439
3537
  if (toolName === "comment") return;
3440
3538
  return chat.messages?.findLast((message) => message.role === "assistant");
3441
3539
  }
@@ -3445,7 +3543,7 @@ var useChatChunk = ({
3445
3543
  onChunk,
3446
3544
  onFinish
3447
3545
  }) => {
3448
- const { status } = (0, import_react14.usePluginOption)(
3546
+ const { status } = (0, import_react15.usePluginOption)(
3449
3547
  { key: import_platejs14.KEYS.aiChat },
3450
3548
  "chat"
3451
3549
  );
@@ -3453,9 +3551,9 @@ var useChatChunk = ({
3453
3551
  const content = useLastAssistantMessage()?.parts.find(
3454
3552
  (part) => part.type === "text"
3455
3553
  )?.text;
3456
- const insertedTextRef = (0, import_react13.useRef)("");
3457
- const prevIsLoadingRef = (0, import_react13.useRef)(isLoading);
3458
- (0, import_react13.useEffect)(() => {
3554
+ const insertedTextRef = (0, import_react14.useRef)("");
3555
+ const prevIsLoadingRef = (0, import_react14.useRef)(isLoading);
3556
+ (0, import_react14.useEffect)(() => {
3459
3557
  if (!isLoading) {
3460
3558
  insertedTextRef.current = "";
3461
3559
  }
@@ -3464,7 +3562,7 @@ var useChatChunk = ({
3464
3562
  }
3465
3563
  prevIsLoadingRef.current = isLoading;
3466
3564
  }, [isLoading]);
3467
- (0, import_react13.useEffect)(() => {
3565
+ (0, import_react14.useEffect)(() => {
3468
3566
  if (!content) {
3469
3567
  return;
3470
3568
  }
@@ -3485,9 +3583,9 @@ var useChatChunk = ({
3485
3583
  };
3486
3584
 
3487
3585
  // src/react/ai-chat/hooks/useEditorChat.ts
3488
- var import_react15 = require("react");
3489
- var import_react16 = require("@platejs/selection/react");
3490
- var import_react17 = require("platejs/react");
3586
+ var import_react16 = require("react");
3587
+ var import_react17 = require("@platejs/selection/react");
3588
+ var import_react18 = require("platejs/react");
3491
3589
  var useEditorChat = ({
3492
3590
  chat,
3493
3591
  onOpenBlockSelection,
@@ -3495,15 +3593,15 @@ var useEditorChat = ({
3495
3593
  onOpenCursor,
3496
3594
  onOpenSelection
3497
3595
  }) => {
3498
- const { editor } = (0, import_react17.useEditorPlugin)(AIChatPlugin);
3499
- const open = (0, import_react17.usePluginOption)(AIChatPlugin, "open");
3500
- (0, import_react15.useEffect)(() => {
3596
+ const { editor } = (0, import_react18.useEditorPlugin)(AIChatPlugin);
3597
+ const open = (0, import_react18.usePluginOption)(AIChatPlugin, "open");
3598
+ (0, import_react16.useEffect)(() => {
3501
3599
  onOpenChange?.(open);
3502
3600
  if (open) {
3503
3601
  if (onOpenBlockSelection) {
3504
- const blockSelectionApi = editor.getApi(import_react16.BlockSelectionPlugin).blockSelection;
3602
+ const blockSelectionApi = editor.getApi(import_react17.BlockSelectionPlugin).blockSelection;
3505
3603
  const isBlockSelecting = editor.getOption(
3506
- import_react16.BlockSelectionPlugin,
3604
+ import_react17.BlockSelectionPlugin,
3507
3605
  "isSelectingSome"
3508
3606
  );
3509
3607
  if (isBlockSelecting) {
@@ -3925,44 +4023,171 @@ var getCurrentBlockPath = (editor) => {
3925
4023
  return path;
3926
4024
  };
3927
4025
 
4026
+ // src/react/ai-chat/utils/applyAISuggestions.ts
4027
+ var import_markdown6 = require("@platejs/markdown");
4028
+ var import_react19 = require("@platejs/selection/react");
4029
+ var import_suggestion3 = require("@platejs/suggestion");
4030
+ var import_platejs20 = require("platejs");
4031
+ var applyAISuggestions = (editor, content) => {
4032
+ const isBlockSelecting = editor.getOption(
4033
+ import_react19.BlockSelectionPlugin,
4034
+ "isSelectingSome"
4035
+ );
4036
+ const { chatNodes } = editor.getOptions(AIChatPlugin);
4037
+ if (isBlockSelecting) {
4038
+ const setReplaceIds = (ids) => {
4039
+ editor.setOption(AIChatPlugin, "_replaceIds", ids);
4040
+ };
4041
+ if (editor.getOption(AIChatPlugin, "_replaceIds").length === 0) {
4042
+ setReplaceIds(chatNodes.map((node) => node.id));
4043
+ }
4044
+ const diffNodes = getDiffNodes(editor, content);
4045
+ const replaceNodes = Array.from(
4046
+ editor.api.nodes({
4047
+ at: [],
4048
+ match: (n) => import_platejs20.ElementApi.isElement(n) && editor.getOption(AIChatPlugin, "_replaceIds").includes(n.id)
4049
+ })
4050
+ );
4051
+ replaceNodes.forEach(([node, path], index) => {
4052
+ const replaceNode = node;
4053
+ const diffNode = diffNodes[index];
4054
+ const isSameString = (0, import_suggestion3.SkipSuggestionDeletes)(editor, replaceNode) === (0, import_suggestion3.SkipSuggestionDeletes)(editor, diffNode);
4055
+ const isSameSuggestion = replaceNode.suggestion?.type === diffNode.suggestion?.type;
4056
+ if (isSameString && isSameSuggestion && node.id == diffNode.id) {
4057
+ return;
4058
+ }
4059
+ if (index === replaceNodes.length - 1 && diffNodes.length > replaceNodes.length) {
4060
+ editor.tf.replaceNodes(diffNodes.slice(index), {
4061
+ at: path
4062
+ });
4063
+ } else {
4064
+ editor.tf.replaceNodes(diffNode, {
4065
+ at: path
4066
+ });
4067
+ }
4068
+ });
4069
+ editor.getApi(import_react19.BlockSelectionPlugin).blockSelection.set(diffNodes.map((node) => node.id));
4070
+ setReplaceIds(diffNodes.map((node) => node.id));
4071
+ } else {
4072
+ const diffNodes = getDiffNodes(editor, content);
4073
+ editor.tf.insertFragment(diffNodes);
4074
+ const nodes = editor.api.nodes({
4075
+ at: [],
4076
+ mode: "lowest",
4077
+ match: (n) => import_platejs20.TextApi.isText(n) && !!n[(0, import_suggestion3.getTransientSuggestionKey)()]
4078
+ });
4079
+ const range = editor.api.nodesRange(Array.from(nodes));
4080
+ editor.tf.setSelection(range);
4081
+ return;
4082
+ }
4083
+ };
4084
+ var withProps = (diffNodes, chatNodes) => {
4085
+ return diffNodes.map((node, index) => {
4086
+ if (!import_platejs20.ElementApi.isElement(node)) return node;
4087
+ const originalNode = chatNodes?.[index];
4088
+ return {
4089
+ ...node,
4090
+ ...originalNode ?? { id: (0, import_platejs20.nanoid)() },
4091
+ children: node.children
4092
+ };
4093
+ });
4094
+ };
4095
+ var withTransient = (diffNodes) => {
4096
+ return diffNodes.map((node) => {
4097
+ if (import_platejs20.TextApi.isText(node)) {
4098
+ return {
4099
+ ...node,
4100
+ [(0, import_suggestion3.getTransientSuggestionKey)()]: true
4101
+ };
4102
+ } else {
4103
+ return {
4104
+ ...node,
4105
+ children: withTransient(node.children),
4106
+ [(0, import_suggestion3.getTransientSuggestionKey)()]: true
4107
+ };
4108
+ }
4109
+ });
4110
+ };
4111
+ var withoutSuggestionAndComments = (nodes) => {
4112
+ return nodes.map((node) => {
4113
+ if (import_platejs20.TextApi.isText(node)) {
4114
+ if (node[import_platejs20.KEYS.suggestion] || node[import_platejs20.KEYS.comment]) {
4115
+ return {
4116
+ text: node.text
4117
+ };
4118
+ }
4119
+ return node;
4120
+ }
4121
+ if (import_platejs20.ElementApi.isElement(node)) {
4122
+ if (node[import_platejs20.KEYS.suggestion]) {
4123
+ const nodeWithoutSuggestion = {};
4124
+ Object.keys(node).forEach((key) => {
4125
+ if (key !== import_platejs20.KEYS.suggestion && !key.startsWith(import_platejs20.KEYS.suggestion)) {
4126
+ nodeWithoutSuggestion[key] = node[key];
4127
+ }
4128
+ });
4129
+ return {
4130
+ ...nodeWithoutSuggestion,
4131
+ children: withoutSuggestionAndComments(node.children)
4132
+ };
4133
+ }
4134
+ return {
4135
+ ...node,
4136
+ children: withoutSuggestionAndComments(node.children)
4137
+ };
4138
+ }
4139
+ return node;
4140
+ });
4141
+ };
4142
+ var getDiffNodes = (editor, aiContent) => {
4143
+ const chatNodes = withoutSuggestionAndComments(
4144
+ editor.getOption(AIChatPlugin, "chatNodes")
4145
+ );
4146
+ const aiNodes = withProps((0, import_markdown6.deserializeMd)(editor, aiContent), chatNodes);
4147
+ const diffNodes = withTransient(
4148
+ (0, import_suggestion3.diffToSuggestions)(editor, chatNodes, aiNodes, { ignoreProps: ["id"] })
4149
+ );
4150
+ return diffNodes;
4151
+ };
4152
+
3928
4153
  // src/react/copilot/CopilotPlugin.tsx
3929
- var import_markdown9 = require("@platejs/markdown");
4154
+ var import_markdown10 = require("@platejs/markdown");
3930
4155
  var import_debounce = __toESM(require("lodash/debounce.js"));
3931
- var import_platejs25 = require("platejs");
3932
- var import_react22 = require("platejs/react");
4156
+ var import_platejs26 = require("platejs");
4157
+ var import_react24 = require("platejs/react");
3933
4158
 
3934
4159
  // src/react/copilot/renderCopilotBelowNodes.tsx
3935
- var import_react18 = __toESM(require("react"));
3936
- var import_platejs20 = require("platejs");
3937
- var import_react19 = require("platejs/react");
4160
+ var import_react20 = __toESM(require("react"));
4161
+ var import_platejs21 = require("platejs");
4162
+ var import_react21 = require("platejs/react");
3938
4163
  var renderCopilotBelowNodes = ({
3939
4164
  editor
3940
4165
  }) => {
3941
- const copilot = (0, import_react19.getEditorPlugin)(editor, {
3942
- key: import_platejs20.KEYS.copilot
4166
+ const copilot = (0, import_react21.getEditorPlugin)(editor, {
4167
+ key: import_platejs21.KEYS.copilot
3943
4168
  });
3944
4169
  const { renderGhostText: GhostText } = copilot.getOptions();
3945
4170
  if (!GhostText) return;
3946
4171
  return ({ children }) => {
3947
- return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, children, /* @__PURE__ */ import_react18.default.createElement(GhostText, null));
4172
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, children, /* @__PURE__ */ import_react20.default.createElement(GhostText, null));
3948
4173
  };
3949
4174
  };
3950
4175
 
3951
4176
  // src/react/copilot/transforms/acceptCopilot.ts
3952
- var import_markdown6 = require("@platejs/markdown");
3953
- var import_platejs21 = require("platejs");
4177
+ var import_markdown7 = require("@platejs/markdown");
4178
+ var import_platejs22 = require("platejs");
3954
4179
  var acceptCopilot = (editor) => {
3955
4180
  const { suggestionText } = editor.getOptions({
3956
- key: import_platejs21.KEYS.copilot
4181
+ key: import_platejs22.KEYS.copilot
3957
4182
  });
3958
4183
  if (!suggestionText?.length) return false;
3959
- editor.tf.insertFragment((0, import_markdown6.deserializeInlineMd)(editor, suggestionText));
4184
+ editor.tf.insertFragment((0, import_markdown7.deserializeInlineMd)(editor, suggestionText));
3960
4185
  };
3961
4186
 
3962
4187
  // src/react/copilot/transforms/acceptCopilotNextWord.ts
3963
- var import_markdown7 = require("@platejs/markdown");
3964
- var import_platejs23 = require("platejs");
3965
- var import_react21 = require("platejs/react");
4188
+ var import_markdown8 = require("@platejs/markdown");
4189
+ var import_platejs24 = require("platejs");
4190
+ var import_react23 = require("platejs/react");
3966
4191
 
3967
4192
  // src/react/copilot/utils/callCompletionApi.ts
3968
4193
  var getOriginalFetch = () => fetch;
@@ -4079,17 +4304,17 @@ var getNextWord = ({ text }) => {
4079
4304
  };
4080
4305
 
4081
4306
  // src/react/copilot/utils/triggerCopilotSuggestion.ts
4082
- var import_platejs22 = require("platejs");
4083
- var import_react20 = require("platejs/react");
4307
+ var import_platejs23 = require("platejs");
4308
+ var import_react22 = require("platejs/react");
4084
4309
  var triggerCopilotSuggestion = async (editor) => {
4085
- const { api, getOptions, setOption } = (0, import_react20.getEditorPlugin)(
4310
+ const { api, getOptions, setOption } = (0, import_react22.getEditorPlugin)(
4086
4311
  editor,
4087
4312
  {
4088
- key: import_platejs22.KEYS.copilot
4313
+ key: import_platejs23.KEYS.copilot
4089
4314
  }
4090
4315
  );
4091
4316
  const { completeOptions, getPrompt, isLoading, triggerQuery } = getOptions();
4092
- if (isLoading || editor.getOptions({ key: import_platejs22.KEYS.aiChat }).chat?.isLoading) {
4317
+ if (isLoading || editor.getOptions({ key: import_platejs23.KEYS.aiChat }).chat?.isLoading) {
4093
4318
  return false;
4094
4319
  }
4095
4320
  if (!triggerQuery({ editor })) return false;
@@ -4122,8 +4347,8 @@ var withoutAbort = (editor, fn) => {
4122
4347
 
4123
4348
  // src/react/copilot/transforms/acceptCopilotNextWord.ts
4124
4349
  var acceptCopilotNextWord = (editor) => {
4125
- const { api, getOptions } = (0, import_react21.getEditorPlugin)(editor, {
4126
- key: import_platejs23.KEYS.copilot
4350
+ const { api, getOptions } = (0, import_react23.getEditorPlugin)(editor, {
4351
+ key: import_platejs24.KEYS.copilot
4127
4352
  });
4128
4353
  const { getNextWord: getNextWord2, suggestionText } = getOptions();
4129
4354
  if (!suggestionText?.length) {
@@ -4134,19 +4359,19 @@ var acceptCopilotNextWord = (editor) => {
4134
4359
  text: remainingText
4135
4360
  });
4136
4361
  withoutAbort(editor, () => {
4137
- editor.tf.insertFragment((0, import_markdown7.deserializeInlineMd)(editor, firstWord));
4362
+ editor.tf.insertFragment((0, import_markdown8.deserializeInlineMd)(editor, firstWord));
4138
4363
  });
4139
4364
  };
4140
4365
 
4141
4366
  // src/react/copilot/withCopilot.ts
4142
- var import_markdown8 = require("@platejs/markdown");
4143
- var import_platejs24 = require("platejs");
4367
+ var import_markdown9 = require("@platejs/markdown");
4368
+ var import_platejs25 = require("platejs");
4144
4369
  var getPatchString = (editor, operations) => {
4145
4370
  let string = "";
4146
4371
  for (const operation of operations) {
4147
4372
  if (operation.type === "insert_node") {
4148
4373
  const node = operation.node;
4149
- const text = (0, import_markdown8.serializeInlineMd)(editor, { value: [node] });
4374
+ const text = (0, import_markdown9.serializeInlineMd)(editor, { value: [node] });
4150
4375
  string += text;
4151
4376
  } else if (operation.type === "insert_text") {
4152
4377
  string += operation.text;
@@ -4202,7 +4427,7 @@ var withCopilot = ({
4202
4427
  },
4203
4428
  setSelection(props) {
4204
4429
  setSelection(props);
4205
- if (editor.selection && (!prevSelection || !import_platejs24.RangeApi.equals(prevSelection, editor.selection)) && getOptions().autoTriggerQuery({ editor }) && editor.api.isFocused()) {
4430
+ if (editor.selection && (!prevSelection || !import_platejs25.RangeApi.equals(prevSelection, editor.selection)) && getOptions().autoTriggerQuery({ editor }) && editor.api.isFocused()) {
4206
4431
  void api.copilot.triggerSuggestion();
4207
4432
  }
4208
4433
  prevSelection = editor.selection;
@@ -4236,8 +4461,8 @@ var withCopilot = ({
4236
4461
  };
4237
4462
 
4238
4463
  // src/react/copilot/CopilotPlugin.tsx
4239
- var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4240
- key: import_platejs25.KEYS.copilot,
4464
+ var CopilotPlugin = (0, import_react24.createTPlatePlugin)({
4465
+ key: import_platejs26.KEYS.copilot,
4241
4466
  handlers: {
4242
4467
  onBlur: ({ api }) => {
4243
4468
  api.copilot.reject();
@@ -4259,20 +4484,20 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4259
4484
  suggestionNodeId: null,
4260
4485
  suggestionText: null,
4261
4486
  autoTriggerQuery: ({ editor }) => {
4262
- if (editor.getOptions({ key: import_platejs25.KEYS.copilot }).suggestionText) {
4487
+ if (editor.getOptions({ key: import_platejs26.KEYS.copilot }).suggestionText) {
4263
4488
  return false;
4264
4489
  }
4265
4490
  const isEmpty = editor.api.isEmpty(editor.selection, { block: true });
4266
4491
  if (isEmpty) return false;
4267
4492
  const blockAbove = editor.api.block();
4268
4493
  if (!blockAbove) return false;
4269
- const blockString = import_platejs25.NodeApi.string(blockAbove[0]);
4494
+ const blockString = import_platejs26.NodeApi.string(blockAbove[0]);
4270
4495
  return blockString.at(-1) === " ";
4271
4496
  },
4272
4497
  getPrompt: ({ editor }) => {
4273
4498
  const contextEntry = editor.api.block({ highest: true });
4274
4499
  if (!contextEntry) return "";
4275
- return (0, import_markdown9.serializeMd)(editor, {
4500
+ return (0, import_markdown10.serializeMd)(editor, {
4276
4501
  value: [contextEntry[0]]
4277
4502
  });
4278
4503
  },
@@ -4286,15 +4511,15 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4286
4511
  }).overrideEditor(withCopilot).extendSelectors(({ getOptions }) => ({
4287
4512
  isSuggested: (id) => getOptions().suggestionNodeId === id
4288
4513
  })).extendTransforms(({ editor }) => ({
4289
- accept: (0, import_platejs25.bindFirst)(acceptCopilot, editor),
4290
- acceptNextWord: (0, import_platejs25.bindFirst)(acceptCopilotNextWord, editor)
4514
+ accept: (0, import_platejs26.bindFirst)(acceptCopilot, editor),
4515
+ acceptNextWord: (0, import_platejs26.bindFirst)(acceptCopilotNextWord, editor)
4291
4516
  })).extendApi(
4292
4517
  ({ api, editor, getOptions, setOption, setOptions }) => {
4293
4518
  const debounceDelay = getOptions().debounceDelay;
4294
- let triggerSuggestion = (0, import_platejs25.bindFirst)(triggerCopilotSuggestion, editor);
4519
+ let triggerSuggestion = (0, import_platejs26.bindFirst)(triggerCopilotSuggestion, editor);
4295
4520
  if (debounceDelay) {
4296
4521
  triggerSuggestion = (0, import_debounce.default)(
4297
- (0, import_platejs25.bindFirst)(triggerCopilotSuggestion, editor),
4522
+ (0, import_platejs26.bindFirst)(triggerCopilotSuggestion, editor),
4298
4523
  debounceDelay
4299
4524
  );
4300
4525
  }
@@ -4350,7 +4575,9 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4350
4575
  acceptAIChat,
4351
4576
  acceptCopilot,
4352
4577
  acceptCopilotNextWord,
4578
+ acceptSuggestions,
4353
4579
  aiCommentToRange,
4580
+ applyAISuggestions,
4354
4581
  callCompletionApi,
4355
4582
  createFormattedBlocks,
4356
4583
  escapeInput,
@@ -4361,6 +4588,7 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4361
4588
  getListNode,
4362
4589
  getNextWord,
4363
4590
  insertBelowAIChat,
4591
+ insertBelowGenerate,
4364
4592
  isCompleteCodeBlock,
4365
4593
  isCompleteMath,
4366
4594
  isSameNode,