@platejs/ai 50.1.1 → 50.2.0

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,14 @@ 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);
3240
3316
  const ctx = {
3241
3317
  children: editor.children,
3242
3318
  selection: selection ?? null,
@@ -3261,7 +3337,7 @@ var withAIChat = ({
3261
3337
  api,
3262
3338
  editor,
3263
3339
  getOptions,
3264
- tf: { insertText, normalizeNode, setSelection },
3340
+ tf: { apply, insertText, normalizeNode },
3265
3341
  type
3266
3342
  }) => {
3267
3343
  const tf = editor.getTransforms(AIPlugin);
@@ -3313,7 +3389,7 @@ var withAIChat = ({
3313
3389
  };
3314
3390
 
3315
3391
  // src/react/ai-chat/AIChatPlugin.ts
3316
- var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3392
+ var AIChatPlugin = (0, import_react10.createTPlatePlugin)({
3317
3393
  key: import_platejs13.KEYS.aiChat,
3318
3394
  dependencies: ["ai"],
3319
3395
  node: {
@@ -3323,8 +3399,10 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3323
3399
  _blockChunks: "",
3324
3400
  _blockPath: null,
3325
3401
  _mdxName: null,
3402
+ _replaceIds: [],
3326
3403
  aiEditor: null,
3327
3404
  chat: { messages: [] },
3405
+ chatNodes: [],
3328
3406
  experimental_lastTextId: null,
3329
3407
  mode: "insert",
3330
3408
  open: false,
@@ -3364,11 +3442,20 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3364
3442
  });
3365
3443
  },
3366
3444
  reload: () => {
3367
- const { chat, mode } = getOptions();
3368
- if (mode === "insert") {
3369
- editor.getTransforms(AIPlugin).ai.undo();
3370
- }
3371
- void chat.regenerate?.();
3445
+ const { chat } = getOptions();
3446
+ editor.getTransforms(AIPlugin).ai.undo();
3447
+ const blocks = editor.getApi(import_react9.BlockSelectionPlugin).blockSelection.getNodes();
3448
+ const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
3449
+ const ctx = {
3450
+ children: editor.children,
3451
+ selection: selection ?? null,
3452
+ toolName: getOption("toolName")
3453
+ };
3454
+ void chat.regenerate?.({
3455
+ body: {
3456
+ ctx
3457
+ }
3458
+ });
3372
3459
  },
3373
3460
  stop: () => {
3374
3461
  setOption("streaming", false);
@@ -3376,12 +3463,15 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3376
3463
  }
3377
3464
  };
3378
3465
  }).extendApi(({ api, editor, getOptions, setOption, tf, type }) => ({
3379
- hide: () => {
3466
+ hide: ({ focus = true } = {}) => {
3380
3467
  api.aiChat.reset();
3381
3468
  setOption("open", false);
3382
- if (editor.getOption(import_react8.BlockSelectionPlugin, "isSelectingSome")) {
3383
- } else {
3384
- editor.tf.focus();
3469
+ if (focus) {
3470
+ if (editor.getOption(import_react9.BlockSelectionPlugin, "isSelectingSome")) {
3471
+ editor.getApi(import_react9.BlockSelectionPlugin).blockSelection.focus();
3472
+ } else {
3473
+ editor.tf.focus();
3474
+ }
3385
3475
  }
3386
3476
  const lastBatch = editor.history.undos.at(-1);
3387
3477
  if (lastBatch?.ai) {
@@ -3391,6 +3481,7 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3391
3481
  },
3392
3482
  show: () => {
3393
3483
  api.aiChat.reset();
3484
+ setOption("toolName", null);
3394
3485
  getOptions().chat.setMessages?.([]);
3395
3486
  setOption("open", true);
3396
3487
  }
@@ -3402,12 +3493,12 @@ var AIChatPlugin = (0, import_react9.createTPlatePlugin)({
3402
3493
  }));
3403
3494
 
3404
3495
  // src/react/ai-chat/hooks/useAIChatEditor.ts
3405
- var import_react10 = require("react");
3496
+ var import_react11 = require("react");
3406
3497
  var import_markdown2 = require("@platejs/markdown");
3407
- var import_react11 = require("platejs/react");
3498
+ var import_react12 = require("platejs/react");
3408
3499
  var useAIChatEditor = (editor, content, { parser } = {}) => {
3409
- const { setOption } = (0, import_react11.useEditorPlugin)(AIChatPlugin);
3410
- editor.children = (0, import_react10.useMemo)(
3500
+ const { setOption } = (0, import_react12.useEditorPlugin)(AIChatPlugin);
3501
+ editor.children = (0, import_react11.useMemo)(
3411
3502
  () => {
3412
3503
  return editor.getApi(import_markdown2.MarkdownPlugin).markdown.deserialize(content, {
3413
3504
  memoize: true,
@@ -3417,25 +3508,25 @@ var useAIChatEditor = (editor, content, { parser } = {}) => {
3417
3508
  // eslint-disable-next-line react-hooks/exhaustive-deps
3418
3509
  [content]
3419
3510
  );
3420
- (0, import_react10.useEffect)(() => {
3511
+ (0, import_react11.useEffect)(() => {
3421
3512
  setOption("aiEditor", editor);
3422
3513
  }, [editor, setOption]);
3423
3514
  };
3424
3515
 
3425
3516
  // src/react/ai-chat/hooks/useChatChunk.ts
3426
- var import_react13 = require("react");
3517
+ var import_react14 = require("react");
3427
3518
  var import_platejs14 = require("platejs");
3428
- var import_react14 = require("platejs/react");
3519
+ var import_react15 = require("platejs/react");
3429
3520
 
3430
3521
  // src/react/ai-chat/utils/getLastAssistantMessage.ts
3431
- var import_react12 = require("platejs/react");
3522
+ var import_react13 = require("platejs/react");
3432
3523
  function getLastAssistantMessage(editor) {
3433
3524
  const messages = editor.getOptions(AIChatPlugin).chat.messages;
3434
3525
  return messages?.findLast((message) => message.role === "assistant");
3435
3526
  }
3436
3527
  function useLastAssistantMessage() {
3437
- const toolName = (0, import_react12.usePluginOption)(AIChatPlugin, "toolName");
3438
- const chat = (0, import_react12.usePluginOption)(AIChatPlugin, "chat");
3528
+ const toolName = (0, import_react13.usePluginOption)(AIChatPlugin, "toolName");
3529
+ const chat = (0, import_react13.usePluginOption)(AIChatPlugin, "chat");
3439
3530
  if (toolName === "comment") return;
3440
3531
  return chat.messages?.findLast((message) => message.role === "assistant");
3441
3532
  }
@@ -3445,7 +3536,7 @@ var useChatChunk = ({
3445
3536
  onChunk,
3446
3537
  onFinish
3447
3538
  }) => {
3448
- const { status } = (0, import_react14.usePluginOption)(
3539
+ const { status } = (0, import_react15.usePluginOption)(
3449
3540
  { key: import_platejs14.KEYS.aiChat },
3450
3541
  "chat"
3451
3542
  );
@@ -3453,9 +3544,9 @@ var useChatChunk = ({
3453
3544
  const content = useLastAssistantMessage()?.parts.find(
3454
3545
  (part) => part.type === "text"
3455
3546
  )?.text;
3456
- const insertedTextRef = (0, import_react13.useRef)("");
3457
- const prevIsLoadingRef = (0, import_react13.useRef)(isLoading);
3458
- (0, import_react13.useEffect)(() => {
3547
+ const insertedTextRef = (0, import_react14.useRef)("");
3548
+ const prevIsLoadingRef = (0, import_react14.useRef)(isLoading);
3549
+ (0, import_react14.useEffect)(() => {
3459
3550
  if (!isLoading) {
3460
3551
  insertedTextRef.current = "";
3461
3552
  }
@@ -3464,7 +3555,7 @@ var useChatChunk = ({
3464
3555
  }
3465
3556
  prevIsLoadingRef.current = isLoading;
3466
3557
  }, [isLoading]);
3467
- (0, import_react13.useEffect)(() => {
3558
+ (0, import_react14.useEffect)(() => {
3468
3559
  if (!content) {
3469
3560
  return;
3470
3561
  }
@@ -3485,9 +3576,9 @@ var useChatChunk = ({
3485
3576
  };
3486
3577
 
3487
3578
  // 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");
3579
+ var import_react16 = require("react");
3580
+ var import_react17 = require("@platejs/selection/react");
3581
+ var import_react18 = require("platejs/react");
3491
3582
  var useEditorChat = ({
3492
3583
  chat,
3493
3584
  onOpenBlockSelection,
@@ -3495,15 +3586,15 @@ var useEditorChat = ({
3495
3586
  onOpenCursor,
3496
3587
  onOpenSelection
3497
3588
  }) => {
3498
- const { editor } = (0, import_react17.useEditorPlugin)(AIChatPlugin);
3499
- const open = (0, import_react17.usePluginOption)(AIChatPlugin, "open");
3500
- (0, import_react15.useEffect)(() => {
3589
+ const { editor } = (0, import_react18.useEditorPlugin)(AIChatPlugin);
3590
+ const open = (0, import_react18.usePluginOption)(AIChatPlugin, "open");
3591
+ (0, import_react16.useEffect)(() => {
3501
3592
  onOpenChange?.(open);
3502
3593
  if (open) {
3503
3594
  if (onOpenBlockSelection) {
3504
- const blockSelectionApi = editor.getApi(import_react16.BlockSelectionPlugin).blockSelection;
3595
+ const blockSelectionApi = editor.getApi(import_react17.BlockSelectionPlugin).blockSelection;
3505
3596
  const isBlockSelecting = editor.getOption(
3506
- import_react16.BlockSelectionPlugin,
3597
+ import_react17.BlockSelectionPlugin,
3507
3598
  "isSelectingSome"
3508
3599
  );
3509
3600
  if (isBlockSelecting) {
@@ -3738,7 +3829,6 @@ var streamSerializeMd = (editor, options, chunk) => {
3738
3829
  const { value } = trimEndHeading(editor, optionsValue ?? editor.children);
3739
3830
  let result = "";
3740
3831
  result = editor.getApi(import_markdown5.MarkdownPlugin).markdown.serialize({
3741
- preserveEmptyParagraphs: false,
3742
3832
  value,
3743
3833
  ...restOptions
3744
3834
  });
@@ -3926,44 +4016,170 @@ var getCurrentBlockPath = (editor) => {
3926
4016
  return path;
3927
4017
  };
3928
4018
 
4019
+ // src/react/ai-chat/utils/applyAISuggestions.ts
4020
+ var import_markdown6 = require("@platejs/markdown");
4021
+ var import_react19 = require("@platejs/selection/react");
4022
+ var import_suggestion3 = require("@platejs/suggestion");
4023
+ var import_platejs20 = require("platejs");
4024
+ var applyAISuggestions = (editor, content) => {
4025
+ const isBlockSelecting = editor.getOption(
4026
+ import_react19.BlockSelectionPlugin,
4027
+ "isSelectingSome"
4028
+ );
4029
+ const { chatNodes } = editor.getOptions(AIChatPlugin);
4030
+ if (isBlockSelecting) {
4031
+ const setReplaceIds = (ids) => {
4032
+ editor.setOption(AIChatPlugin, "_replaceIds", ids);
4033
+ };
4034
+ if (editor.getOption(AIChatPlugin, "_replaceIds").length === 0) {
4035
+ setReplaceIds(chatNodes.map((node) => node.id));
4036
+ }
4037
+ const diffNodes = getDiffNodes(editor, content);
4038
+ const replaceNodes = Array.from(
4039
+ editor.api.nodes({
4040
+ at: [],
4041
+ match: (n) => import_platejs20.ElementApi.isElement(n) && editor.getOption(AIChatPlugin, "_replaceIds").includes(n.id)
4042
+ })
4043
+ );
4044
+ replaceNodes.forEach(([node, path], index) => {
4045
+ const replaceNode = node;
4046
+ const diffNode = diffNodes[index];
4047
+ const isSameString = (0, import_suggestion3.SkipSuggestionDeletes)(editor, replaceNode) === (0, import_suggestion3.SkipSuggestionDeletes)(editor, diffNode);
4048
+ const isSameSuggestion = replaceNode.suggestion?.type === diffNode.suggestion?.type;
4049
+ if (isSameString && isSameSuggestion && node.id == diffNode.id) {
4050
+ return;
4051
+ }
4052
+ if (index === replaceNodes.length - 1 && diffNodes.length > replaceNodes.length) {
4053
+ editor.tf.replaceNodes(diffNodes.slice(index), {
4054
+ at: path
4055
+ });
4056
+ } else {
4057
+ editor.tf.replaceNodes(diffNode, {
4058
+ at: path
4059
+ });
4060
+ }
4061
+ });
4062
+ setReplaceIds(diffNodes.map((node) => node.id));
4063
+ } else {
4064
+ const diffNodes = getDiffNodes(editor, content);
4065
+ editor.tf.insertFragment(diffNodes);
4066
+ const nodes = editor.api.nodes({
4067
+ at: [],
4068
+ mode: "lowest",
4069
+ match: (n) => import_platejs20.TextApi.isText(n) && !!n[(0, import_suggestion3.getTransientSuggestionKey)()]
4070
+ });
4071
+ const range = editor.api.nodesRange(Array.from(nodes));
4072
+ editor.tf.setSelection(range);
4073
+ return;
4074
+ }
4075
+ };
4076
+ var withProps = (diffNodes, chatNodes) => {
4077
+ return diffNodes.map((node, index) => {
4078
+ if (!import_platejs20.ElementApi.isElement(node)) return node;
4079
+ const originalNode = chatNodes?.[index];
4080
+ return {
4081
+ ...node,
4082
+ ...originalNode ?? { id: (0, import_platejs20.nanoid)() },
4083
+ children: node.children
4084
+ };
4085
+ });
4086
+ };
4087
+ var withTransient = (diffNodes) => {
4088
+ return diffNodes.map((node) => {
4089
+ if (import_platejs20.TextApi.isText(node)) {
4090
+ return {
4091
+ ...node,
4092
+ [(0, import_suggestion3.getTransientSuggestionKey)()]: true
4093
+ };
4094
+ } else {
4095
+ return {
4096
+ ...node,
4097
+ children: withTransient(node.children),
4098
+ [(0, import_suggestion3.getTransientSuggestionKey)()]: true
4099
+ };
4100
+ }
4101
+ });
4102
+ };
4103
+ var withoutSuggestionAndComments = (nodes) => {
4104
+ return nodes.map((node) => {
4105
+ if (import_platejs20.TextApi.isText(node)) {
4106
+ if (node[import_platejs20.KEYS.suggestion] || node[import_platejs20.KEYS.comment]) {
4107
+ return {
4108
+ text: node.text
4109
+ };
4110
+ }
4111
+ return node;
4112
+ }
4113
+ if (import_platejs20.ElementApi.isElement(node)) {
4114
+ if (node[import_platejs20.KEYS.suggestion]) {
4115
+ const nodeWithoutSuggestion = {};
4116
+ Object.keys(node).forEach((key) => {
4117
+ if (key !== import_platejs20.KEYS.suggestion && !key.startsWith(import_platejs20.KEYS.suggestion)) {
4118
+ nodeWithoutSuggestion[key] = node[key];
4119
+ }
4120
+ });
4121
+ return {
4122
+ ...nodeWithoutSuggestion,
4123
+ children: withoutSuggestionAndComments(node.children)
4124
+ };
4125
+ }
4126
+ return {
4127
+ ...node,
4128
+ children: withoutSuggestionAndComments(node.children)
4129
+ };
4130
+ }
4131
+ return node;
4132
+ });
4133
+ };
4134
+ var getDiffNodes = (editor, aiContent) => {
4135
+ const chatNodes = withoutSuggestionAndComments(
4136
+ editor.getOption(AIChatPlugin, "chatNodes")
4137
+ );
4138
+ const aiNodes = withProps((0, import_markdown6.deserializeMd)(editor, aiContent), chatNodes);
4139
+ const diffNodes = withTransient(
4140
+ (0, import_suggestion3.diffToSuggestions)(editor, chatNodes, aiNodes, { ignoreProps: ["id"] })
4141
+ );
4142
+ return diffNodes;
4143
+ };
4144
+
3929
4145
  // src/react/copilot/CopilotPlugin.tsx
3930
- var import_markdown9 = require("@platejs/markdown");
4146
+ var import_markdown10 = require("@platejs/markdown");
3931
4147
  var import_debounce = __toESM(require("lodash/debounce.js"));
3932
- var import_platejs25 = require("platejs");
3933
- var import_react22 = require("platejs/react");
4148
+ var import_platejs26 = require("platejs");
4149
+ var import_react24 = require("platejs/react");
3934
4150
 
3935
4151
  // src/react/copilot/renderCopilotBelowNodes.tsx
3936
- var import_react18 = __toESM(require("react"));
3937
- var import_platejs20 = require("platejs");
3938
- var import_react19 = require("platejs/react");
4152
+ var import_react20 = __toESM(require("react"));
4153
+ var import_platejs21 = require("platejs");
4154
+ var import_react21 = require("platejs/react");
3939
4155
  var renderCopilotBelowNodes = ({
3940
4156
  editor
3941
4157
  }) => {
3942
- const copilot = (0, import_react19.getEditorPlugin)(editor, {
3943
- key: import_platejs20.KEYS.copilot
4158
+ const copilot = (0, import_react21.getEditorPlugin)(editor, {
4159
+ key: import_platejs21.KEYS.copilot
3944
4160
  });
3945
4161
  const { renderGhostText: GhostText } = copilot.getOptions();
3946
4162
  if (!GhostText) return;
3947
4163
  return ({ children }) => {
3948
- return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, children, /* @__PURE__ */ import_react18.default.createElement(GhostText, null));
4164
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, children, /* @__PURE__ */ import_react20.default.createElement(GhostText, null));
3949
4165
  };
3950
4166
  };
3951
4167
 
3952
4168
  // src/react/copilot/transforms/acceptCopilot.ts
3953
- var import_markdown6 = require("@platejs/markdown");
3954
- var import_platejs21 = require("platejs");
4169
+ var import_markdown7 = require("@platejs/markdown");
4170
+ var import_platejs22 = require("platejs");
3955
4171
  var acceptCopilot = (editor) => {
3956
4172
  const { suggestionText } = editor.getOptions({
3957
- key: import_platejs21.KEYS.copilot
4173
+ key: import_platejs22.KEYS.copilot
3958
4174
  });
3959
4175
  if (!suggestionText?.length) return false;
3960
- editor.tf.insertFragment((0, import_markdown6.deserializeInlineMd)(editor, suggestionText));
4176
+ editor.tf.insertFragment((0, import_markdown7.deserializeInlineMd)(editor, suggestionText));
3961
4177
  };
3962
4178
 
3963
4179
  // src/react/copilot/transforms/acceptCopilotNextWord.ts
3964
- var import_markdown7 = require("@platejs/markdown");
3965
- var import_platejs23 = require("platejs");
3966
- var import_react21 = require("platejs/react");
4180
+ var import_markdown8 = require("@platejs/markdown");
4181
+ var import_platejs24 = require("platejs");
4182
+ var import_react23 = require("platejs/react");
3967
4183
 
3968
4184
  // src/react/copilot/utils/callCompletionApi.ts
3969
4185
  var getOriginalFetch = () => fetch;
@@ -4080,17 +4296,17 @@ var getNextWord = ({ text }) => {
4080
4296
  };
4081
4297
 
4082
4298
  // src/react/copilot/utils/triggerCopilotSuggestion.ts
4083
- var import_platejs22 = require("platejs");
4084
- var import_react20 = require("platejs/react");
4299
+ var import_platejs23 = require("platejs");
4300
+ var import_react22 = require("platejs/react");
4085
4301
  var triggerCopilotSuggestion = async (editor) => {
4086
- const { api, getOptions, setOption } = (0, import_react20.getEditorPlugin)(
4302
+ const { api, getOptions, setOption } = (0, import_react22.getEditorPlugin)(
4087
4303
  editor,
4088
4304
  {
4089
- key: import_platejs22.KEYS.copilot
4305
+ key: import_platejs23.KEYS.copilot
4090
4306
  }
4091
4307
  );
4092
4308
  const { completeOptions, getPrompt, isLoading, triggerQuery } = getOptions();
4093
- if (isLoading || editor.getOptions({ key: import_platejs22.KEYS.aiChat }).chat?.isLoading) {
4309
+ if (isLoading || editor.getOptions({ key: import_platejs23.KEYS.aiChat }).chat?.isLoading) {
4094
4310
  return false;
4095
4311
  }
4096
4312
  if (!triggerQuery({ editor })) return false;
@@ -4123,8 +4339,8 @@ var withoutAbort = (editor, fn) => {
4123
4339
 
4124
4340
  // src/react/copilot/transforms/acceptCopilotNextWord.ts
4125
4341
  var acceptCopilotNextWord = (editor) => {
4126
- const { api, getOptions } = (0, import_react21.getEditorPlugin)(editor, {
4127
- key: import_platejs23.KEYS.copilot
4342
+ const { api, getOptions } = (0, import_react23.getEditorPlugin)(editor, {
4343
+ key: import_platejs24.KEYS.copilot
4128
4344
  });
4129
4345
  const { getNextWord: getNextWord2, suggestionText } = getOptions();
4130
4346
  if (!suggestionText?.length) {
@@ -4135,19 +4351,19 @@ var acceptCopilotNextWord = (editor) => {
4135
4351
  text: remainingText
4136
4352
  });
4137
4353
  withoutAbort(editor, () => {
4138
- editor.tf.insertFragment((0, import_markdown7.deserializeInlineMd)(editor, firstWord));
4354
+ editor.tf.insertFragment((0, import_markdown8.deserializeInlineMd)(editor, firstWord));
4139
4355
  });
4140
4356
  };
4141
4357
 
4142
4358
  // src/react/copilot/withCopilot.ts
4143
- var import_markdown8 = require("@platejs/markdown");
4144
- var import_platejs24 = require("platejs");
4359
+ var import_markdown9 = require("@platejs/markdown");
4360
+ var import_platejs25 = require("platejs");
4145
4361
  var getPatchString = (editor, operations) => {
4146
4362
  let string = "";
4147
4363
  for (const operation of operations) {
4148
4364
  if (operation.type === "insert_node") {
4149
4365
  const node = operation.node;
4150
- const text = (0, import_markdown8.serializeInlineMd)(editor, { value: [node] });
4366
+ const text = (0, import_markdown9.serializeInlineMd)(editor, { value: [node] });
4151
4367
  string += text;
4152
4368
  } else if (operation.type === "insert_text") {
4153
4369
  string += operation.text;
@@ -4203,7 +4419,7 @@ var withCopilot = ({
4203
4419
  },
4204
4420
  setSelection(props) {
4205
4421
  setSelection(props);
4206
- if (editor.selection && (!prevSelection || !import_platejs24.RangeApi.equals(prevSelection, editor.selection)) && getOptions().autoTriggerQuery({ editor }) && editor.api.isFocused()) {
4422
+ if (editor.selection && (!prevSelection || !import_platejs25.RangeApi.equals(prevSelection, editor.selection)) && getOptions().autoTriggerQuery({ editor }) && editor.api.isFocused()) {
4207
4423
  void api.copilot.triggerSuggestion();
4208
4424
  }
4209
4425
  prevSelection = editor.selection;
@@ -4237,8 +4453,8 @@ var withCopilot = ({
4237
4453
  };
4238
4454
 
4239
4455
  // src/react/copilot/CopilotPlugin.tsx
4240
- var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4241
- key: import_platejs25.KEYS.copilot,
4456
+ var CopilotPlugin = (0, import_react24.createTPlatePlugin)({
4457
+ key: import_platejs26.KEYS.copilot,
4242
4458
  handlers: {
4243
4459
  onBlur: ({ api }) => {
4244
4460
  api.copilot.reject();
@@ -4260,20 +4476,20 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4260
4476
  suggestionNodeId: null,
4261
4477
  suggestionText: null,
4262
4478
  autoTriggerQuery: ({ editor }) => {
4263
- if (editor.getOptions({ key: import_platejs25.KEYS.copilot }).suggestionText) {
4479
+ if (editor.getOptions({ key: import_platejs26.KEYS.copilot }).suggestionText) {
4264
4480
  return false;
4265
4481
  }
4266
4482
  const isEmpty = editor.api.isEmpty(editor.selection, { block: true });
4267
4483
  if (isEmpty) return false;
4268
4484
  const blockAbove = editor.api.block();
4269
4485
  if (!blockAbove) return false;
4270
- const blockString = import_platejs25.NodeApi.string(blockAbove[0]);
4486
+ const blockString = import_platejs26.NodeApi.string(blockAbove[0]);
4271
4487
  return blockString.at(-1) === " ";
4272
4488
  },
4273
4489
  getPrompt: ({ editor }) => {
4274
4490
  const contextEntry = editor.api.block({ highest: true });
4275
4491
  if (!contextEntry) return "";
4276
- return (0, import_markdown9.serializeMd)(editor, {
4492
+ return (0, import_markdown10.serializeMd)(editor, {
4277
4493
  value: [contextEntry[0]]
4278
4494
  });
4279
4495
  },
@@ -4287,15 +4503,15 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4287
4503
  }).overrideEditor(withCopilot).extendSelectors(({ getOptions }) => ({
4288
4504
  isSuggested: (id) => getOptions().suggestionNodeId === id
4289
4505
  })).extendTransforms(({ editor }) => ({
4290
- accept: (0, import_platejs25.bindFirst)(acceptCopilot, editor),
4291
- acceptNextWord: (0, import_platejs25.bindFirst)(acceptCopilotNextWord, editor)
4506
+ accept: (0, import_platejs26.bindFirst)(acceptCopilot, editor),
4507
+ acceptNextWord: (0, import_platejs26.bindFirst)(acceptCopilotNextWord, editor)
4292
4508
  })).extendApi(
4293
4509
  ({ api, editor, getOptions, setOption, setOptions }) => {
4294
4510
  const debounceDelay = getOptions().debounceDelay;
4295
- let triggerSuggestion = (0, import_platejs25.bindFirst)(triggerCopilotSuggestion, editor);
4511
+ let triggerSuggestion = (0, import_platejs26.bindFirst)(triggerCopilotSuggestion, editor);
4296
4512
  if (debounceDelay) {
4297
4513
  triggerSuggestion = (0, import_debounce.default)(
4298
- (0, import_platejs25.bindFirst)(triggerCopilotSuggestion, editor),
4514
+ (0, import_platejs26.bindFirst)(triggerCopilotSuggestion, editor),
4299
4515
  debounceDelay
4300
4516
  );
4301
4517
  }
@@ -4351,7 +4567,9 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4351
4567
  acceptAIChat,
4352
4568
  acceptCopilot,
4353
4569
  acceptCopilotNextWord,
4570
+ acceptSuggestions,
4354
4571
  aiCommentToRange,
4572
+ applyAISuggestions,
4355
4573
  callCompletionApi,
4356
4574
  createFormattedBlocks,
4357
4575
  escapeInput,
@@ -4362,6 +4580,7 @@ var CopilotPlugin = (0, import_react22.createTPlatePlugin)({
4362
4580
  getListNode,
4363
4581
  getNextWord,
4364
4582
  insertBelowAIChat,
4583
+ insertBelowGenerate,
4365
4584
  isCompleteCodeBlock,
4366
4585
  isCompleteMath,
4367
4586
  isSameNode,