@platejs/ai 51.1.1 → 51.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -94,11 +94,11 @@ var createPromptFromConfig = (config, params) => {
94
94
  const { isBlockSelecting, isSelecting: isSelecting3 } = params;
95
95
  if (isBlockSelecting && config.blockSelecting) {
96
96
  return config.blockSelecting ?? config.default;
97
- } else if (isSelecting3 && config.selecting) {
97
+ }
98
+ if (isSelecting3 && config.selecting) {
98
99
  return config.selecting ?? config.default;
99
- } else {
100
- return config.default;
101
100
  }
101
+ return config.default;
102
102
  };
103
103
  var getEditorPrompt = (editor, {
104
104
  prompt = ""
@@ -163,7 +163,7 @@ function findTextRangeInBlock({
163
163
  let matchEnd = matchStart >= 0 ? matchStart + findText.length : -1;
164
164
  if (matchStart === -1) {
165
165
  const maxDist = maxAllowedDistance(findText.length);
166
- let bestMatch = { distance: Infinity, end: -1, start: -1 };
166
+ let bestMatch = { distance: Number.POSITIVE_INFINITY, end: -1, start: -1 };
167
167
  for (let i = 0; i <= fullText.length - findText.length; i++) {
168
168
  for (let lenOffset = -maxDist; lenOffset <= maxDist; lenOffset++) {
169
169
  const len = findText.length + lenOffset;
@@ -193,7 +193,6 @@ function findTextRangeInBlock({
193
193
  }
194
194
  if (matchStart === -1) return null;
195
195
  const findPoint = (charOffset, isEnd = false) => {
196
- const accumulated = 0;
197
196
  if (!isEnd) {
198
197
  for (const segment of textSegments) {
199
198
  if (charOffset === segment.offset) {
@@ -285,7 +284,11 @@ import { KEYS as KEYS4 } from "platejs";
285
284
  import { getEditorPlugin } from "platejs/react";
286
285
 
287
286
  // src/react/ai-chat/utils/acceptAISuggestions.ts
288
- import { acceptSuggestion, getSuggestionKey, getTransientSuggestionKey as getTransientSuggestionKey2 } from "@platejs/suggestion";
287
+ import {
288
+ acceptSuggestion,
289
+ getSuggestionKey,
290
+ getTransientSuggestionKey as getTransientSuggestionKey2
291
+ } from "@platejs/suggestion";
289
292
  import { SuggestionPlugin } from "@platejs/suggestion/react";
290
293
  var acceptAISuggestions = (editor) => {
291
294
  const suggestions = editor.getApi(SuggestionPlugin).suggestion.nodes({
@@ -387,7 +390,7 @@ var applyAISuggestions = (editor, content) => {
387
390
  at: path
388
391
  });
389
392
  }
390
- if (isSameString && isSameSuggestion && node.id == diffNode.id) {
393
+ if (isSameString && isSameSuggestion && node.id === diffNode.id) {
391
394
  return;
392
395
  }
393
396
  editor.tf.replaceNodes(diffNode, {
@@ -411,64 +414,57 @@ var applyAISuggestions = (editor, content) => {
411
414
  return;
412
415
  }
413
416
  };
414
- var withProps = (diffNodes, chatNodes) => {
415
- return diffNodes.map((node, index) => {
416
- if (!ElementApi.isElement(node)) return node;
417
- const originalNode = chatNodes?.[index];
417
+ var withProps = (diffNodes, chatNodes) => diffNodes.map((node, index) => {
418
+ if (!ElementApi.isElement(node)) return node;
419
+ const originalNode = chatNodes?.[index];
420
+ return {
421
+ ...node,
422
+ ...originalNode ?? { id: nanoid() },
423
+ children: node.children
424
+ };
425
+ });
426
+ var withTransient = (diffNodes) => diffNodes.map((node) => {
427
+ if (TextApi2.isText(node)) {
418
428
  return {
419
429
  ...node,
420
- ...originalNode ?? { id: nanoid() },
421
- children: node.children
430
+ [getTransientSuggestionKey3()]: true
422
431
  };
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 {
432
+ }
433
+ return {
434
+ ...node,
435
+ children: withTransient(node.children),
436
+ [getTransientSuggestionKey3()]: true
437
+ };
438
+ });
439
+ var withoutSuggestionAndComments = (nodes) => nodes.map((node) => {
440
+ if (TextApi2.isText(node)) {
441
+ if (node[KEYS5.suggestion] || node[KEYS5.comment]) {
433
442
  return {
434
- ...node,
435
- children: withTransient(node.children),
436
- [getTransientSuggestionKey3()]: true
443
+ text: node.text
437
444
  };
438
445
  }
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
- }
446
+ return node;
447
+ }
448
+ if (ElementApi.isElement(node)) {
449
+ if (node[KEYS5.suggestion]) {
450
+ const nodeWithoutSuggestion = {};
451
+ Object.keys(node).forEach((key) => {
452
+ if (key !== KEYS5.suggestion && !key.startsWith(KEYS5.suggestion)) {
453
+ nodeWithoutSuggestion[key] = node[key];
454
+ }
455
+ });
464
456
  return {
465
- ...node,
457
+ ...nodeWithoutSuggestion,
466
458
  children: withoutSuggestionAndComments(node.children)
467
459
  };
468
460
  }
469
- return node;
470
- });
471
- };
461
+ return {
462
+ ...node,
463
+ children: withoutSuggestionAndComments(node.children)
464
+ };
465
+ }
466
+ return node;
467
+ });
472
468
  var getDiffNodes = (editor, aiContent) => {
473
469
  const chatNodes = withoutSuggestionAndComments(
474
470
  editor.getOption(AIChatPlugin, "chatNodes")
@@ -496,7 +492,11 @@ function useLastAssistantMessage() {
496
492
  }
497
493
 
498
494
  // src/react/ai-chat/utils/rejectAISuggestions.ts
499
- import { getSuggestionKey as getSuggestionKey2, getTransientSuggestionKey as getTransientSuggestionKey4, rejectSuggestion } from "@platejs/suggestion";
495
+ import {
496
+ getSuggestionKey as getSuggestionKey2,
497
+ getTransientSuggestionKey as getTransientSuggestionKey4,
498
+ rejectSuggestion
499
+ } from "@platejs/suggestion";
500
500
  import { SuggestionPlugin as SuggestionPlugin2 } from "@platejs/suggestion/react";
501
501
  var rejectAISuggestions = (editor) => {
502
502
  const suggestions = editor.getApi(SuggestionPlugin2).suggestion.nodes({
@@ -831,7 +831,7 @@ var withAIChat = ({
831
831
  api,
832
832
  editor,
833
833
  getOptions,
834
- tf: { apply, insertText, normalizeNode },
834
+ tf: { insertText, normalizeNode },
835
835
  type
836
836
  }) => {
837
837
  const tf = editor.getTransforms(AIPlugin);
@@ -906,63 +906,61 @@ var AIChatPlugin = createTPlatePlugin({
906
906
  trigger: " ",
907
907
  triggerPreviousCharPattern: /^\s?$/
908
908
  }
909
- }).overrideEditor(withAIChat).extendApi(({ editor, getOption, getOptions, setOption, type }) => {
910
- return {
911
- reset: bindFirst2(resetAIChat, editor),
912
- submit: bindFirst2(submitAIChat, editor),
913
- node: (options = {}) => {
914
- const { anchor = false, streaming = false, ...rest } = options;
915
- if (anchor) {
916
- return editor.api.node({
917
- at: [],
918
- match: (n) => ElementApi4.isElement(n) && n.type === type,
919
- ...rest
920
- });
921
- }
922
- if (streaming) {
923
- if (!getOption("streaming")) return;
924
- const path = getOption("_blockPath");
925
- if (!path) return;
926
- return editor.api.node({
927
- at: path,
928
- mode: "lowest",
929
- reverse: true,
930
- match: (t) => !!t[getPluginType3(editor, KEYS12.ai)],
931
- ...rest
932
- });
933
- }
909
+ }).overrideEditor(withAIChat).extendApi(({ editor, getOption, getOptions, setOption, type }) => ({
910
+ reset: bindFirst2(resetAIChat, editor),
911
+ submit: bindFirst2(submitAIChat, editor),
912
+ node: (options = {}) => {
913
+ const { anchor = false, streaming = false, ...rest } = options;
914
+ if (anchor) {
934
915
  return editor.api.node({
935
- match: (n) => n[getPluginType3(editor, KEYS12.ai)],
916
+ at: [],
917
+ match: (n) => ElementApi4.isElement(n) && n.type === type,
936
918
  ...rest
937
919
  });
938
- },
939
- reload: () => {
940
- const { chat, chatNodes, chatSelection } = getOptions();
941
- editor.getTransforms(AIPlugin).ai.undo();
942
- if (chatSelection) {
943
- editor.tf.setSelection(chatSelection);
944
- } else {
945
- editor.getApi(BlockSelectionPlugin5).blockSelection.set(chatNodes.map((node) => node.id));
946
- }
947
- const blocks = editor.getApi(BlockSelectionPlugin5).blockSelection.getNodes();
948
- const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
949
- const ctx = {
950
- children: editor.children,
951
- selection: selection ?? null,
952
- toolName: getOption("toolName")
953
- };
954
- void chat.regenerate?.({
955
- body: {
956
- ctx
957
- }
920
+ }
921
+ if (streaming) {
922
+ if (!getOption("streaming")) return;
923
+ const path = getOption("_blockPath");
924
+ if (!path) return;
925
+ return editor.api.node({
926
+ at: path,
927
+ mode: "lowest",
928
+ reverse: true,
929
+ match: (t) => !!t[getPluginType3(editor, KEYS12.ai)],
930
+ ...rest
958
931
  });
959
- },
960
- stop: () => {
961
- setOption("streaming", false);
962
- getOptions().chat.stop?.();
963
932
  }
964
- };
965
- }).extendApi(({ api, editor, getOptions, setOption, tf, type }) => ({
933
+ return editor.api.node({
934
+ match: (n) => n[getPluginType3(editor, KEYS12.ai)],
935
+ ...rest
936
+ });
937
+ },
938
+ reload: () => {
939
+ const { chat, chatNodes, chatSelection } = getOptions();
940
+ editor.getTransforms(AIPlugin).ai.undo();
941
+ if (chatSelection) {
942
+ editor.tf.setSelection(chatSelection);
943
+ } else {
944
+ editor.getApi(BlockSelectionPlugin5).blockSelection.set(chatNodes.map((node) => node.id));
945
+ }
946
+ const blocks = editor.getApi(BlockSelectionPlugin5).blockSelection.getNodes();
947
+ const selection = blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;
948
+ const ctx = {
949
+ children: editor.children,
950
+ selection: selection ?? null,
951
+ toolName: getOption("toolName")
952
+ };
953
+ void chat.regenerate?.({
954
+ body: {
955
+ ctx
956
+ }
957
+ });
958
+ },
959
+ stop: () => {
960
+ setOption("streaming", false);
961
+ getOptions().chat.stop?.();
962
+ }
963
+ })).extendApi(({ api, editor, getOptions, setOption, tf }) => ({
966
964
  hide: ({
967
965
  focus = true,
968
966
  undo = true
@@ -978,7 +976,7 @@ var AIChatPlugin = createTPlatePlugin({
978
976
  }
979
977
  const lastBatch = editor.history.undos.at(-1);
980
978
  if (lastBatch?.ai) {
981
- delete lastBatch.ai;
979
+ lastBatch.ai = void 0;
982
980
  }
983
981
  tf.aiChat.removeAnchor();
984
982
  },
@@ -1002,12 +1000,10 @@ import { useEditorPlugin } from "platejs/react";
1002
1000
  var useAIChatEditor = (editor, content, { parser } = {}) => {
1003
1001
  const { setOption } = useEditorPlugin(AIChatPlugin);
1004
1002
  editor.children = useMemo(
1005
- () => {
1006
- return editor.getApi(MarkdownPlugin).markdown.deserialize(content, {
1007
- memoize: true,
1008
- parser
1009
- });
1010
- },
1003
+ () => editor.getApi(MarkdownPlugin).markdown.deserialize(content, {
1004
+ memoize: true,
1005
+ parser
1006
+ }),
1011
1007
  // eslint-disable-next-line react-hooks/exhaustive-deps
1012
1008
  [content]
1013
1009
  );
@@ -1068,7 +1064,6 @@ import { useEffect as useEffect3 } from "react";
1068
1064
  import { BlockSelectionPlugin as BlockSelectionPlugin6 } from "@platejs/selection/react";
1069
1065
  import { useEditorPlugin as useEditorPlugin2, usePluginOption as usePluginOption3 } from "platejs/react";
1070
1066
  var useEditorChat = ({
1071
- chat,
1072
1067
  onOpenBlockSelection,
1073
1068
  onOpenChange,
1074
1069
  onOpenCursor,
@@ -1104,9 +1099,7 @@ var useEditorChat = ({
1104
1099
 
1105
1100
  // src/react/ai-chat/streaming/streamDeserializeInlineMd.ts
1106
1101
  import { MarkdownPlugin as MarkdownPlugin2 } from "@platejs/markdown";
1107
- var streamDeserializeInlineMd = (editor, text, options) => {
1108
- return editor.getApi(MarkdownPlugin2).markdown.deserializeInline(text, options);
1109
- };
1102
+ var streamDeserializeInlineMd = (editor, text, options) => editor.getApi(MarkdownPlugin2).markdown.deserializeInline(text, options);
1110
1103
 
1111
1104
  // src/react/ai-chat/streaming/streamDeserializeMd.ts
1112
1105
  import { MarkdownPlugin as MarkdownPlugin3 } from "@platejs/markdown";
@@ -1119,9 +1112,8 @@ var getChunkTrimmed = (chunk, {
1119
1112
  const str = direction === "right" ? chunk.trimEnd() : chunk.trimStart();
1120
1113
  if (direction === "right") {
1121
1114
  return chunk.slice(str.length);
1122
- } else {
1123
- return chunk.slice(0, chunk.length - str.length);
1124
1115
  }
1116
+ return chunk.slice(0, chunk.length - str.length);
1125
1117
  };
1126
1118
  function isCompleteCodeBlock(str) {
1127
1119
  const trimmed = str.trim();
@@ -1153,13 +1145,12 @@ var getListNode = (editor, node) => {
1153
1145
  })?.[0];
1154
1146
  if (previousNode?.listStyleType && previousNode?.listStart) {
1155
1147
  return node;
1156
- } else {
1157
- if (node.listStart === 1) return node;
1158
- return {
1159
- ...node,
1160
- listRestartPolite: node.listStart
1161
- };
1162
1148
  }
1149
+ if (node.listStart === 1) return node;
1150
+ return {
1151
+ ...node,
1152
+ listRestartPolite: node.listStart
1153
+ };
1163
1154
  }
1164
1155
  return node;
1165
1156
  };
@@ -1178,23 +1169,20 @@ var isSameNode = (editor, node1, node2) => {
1178
1169
 
1179
1170
  // src/react/ai-chat/streaming/utils/nodesWithProps.ts
1180
1171
  import { ElementApi as ElementApi5 } from "platejs";
1181
- var nodesWithProps = (editor, nodes, options) => {
1182
- return nodes.map((node) => {
1183
- if (ElementApi5.isElement(node)) {
1184
- return {
1185
- ...getListNode(editor, node),
1186
- ...options.elementProps,
1187
- children: nodesWithProps(editor, node.children, options)
1188
- };
1189
- } else {
1190
- return {
1191
- ...options.textProps,
1192
- ...node,
1193
- text: node.text
1194
- };
1195
- }
1196
- });
1197
- };
1172
+ var nodesWithProps = (editor, nodes, options) => nodes.map((node) => {
1173
+ if (ElementApi5.isElement(node)) {
1174
+ return {
1175
+ ...getListNode(editor, node),
1176
+ ...options.elementProps,
1177
+ children: nodesWithProps(editor, node.children, options)
1178
+ };
1179
+ }
1180
+ return {
1181
+ ...options.textProps,
1182
+ ...node,
1183
+ text: node.text
1184
+ };
1185
+ });
1198
1186
 
1199
1187
  // src/react/ai-chat/streaming/streamDeserializeMd.ts
1200
1188
  var statMdxTagRegex = /<([A-Za-z][A-Za-z0-9._:-]*)(?:\s[^>]*?)?(?<!\/)>/;
@@ -1254,23 +1242,21 @@ var withoutDeserializeInMdx = (editor, input) => {
1254
1242
  if (isMdxEnd) {
1255
1243
  editor.setOption(AIChatPlugin, "_mdxName", null);
1256
1244
  return false;
1257
- } else {
1258
- return [
1259
- {
1260
- children: [
1261
- {
1262
- text: input
1263
- }
1264
- ],
1265
- type: getPluginType4(editor, KEYS15.p)
1266
- }
1267
- ];
1268
- }
1269
- } else {
1270
- const newMdxName = statMdxTagRegex.exec(input)?.[1];
1271
- if (input.startsWith(`<${newMdxName}`)) {
1272
- editor.setOption(AIChatPlugin, "_mdxName", newMdxName ?? null);
1273
1245
  }
1246
+ return [
1247
+ {
1248
+ children: [
1249
+ {
1250
+ text: input
1251
+ }
1252
+ ],
1253
+ type: getPluginType4(editor, KEYS15.p)
1254
+ }
1255
+ ];
1256
+ }
1257
+ const newMdxName = statMdxTagRegex.exec(input)?.[1];
1258
+ if (input.startsWith(`<${newMdxName}`)) {
1259
+ editor.setOption(AIChatPlugin, "_mdxName", newMdxName ?? null);
1274
1260
  }
1275
1261
  };
1276
1262
 
@@ -1503,9 +1489,7 @@ var getCurrentBlockPath = (editor) => {
1503
1489
  return PathApi2.previous(anchorNode[1]);
1504
1490
  }
1505
1491
  };
1506
- const getFocusPath = (editor2) => {
1507
- return editor2.selection?.focus.path.slice(0, 1);
1508
- };
1492
+ const getFocusPath = (editor2) => editor2.selection?.focus.path.slice(0, 1);
1509
1493
  const path = getAnchorPreviousPath(editor) ?? getFocusPath(editor) ?? [0];
1510
1494
  const entry = editor.api.node(path);
1511
1495
  if (entry && (entry[0].type === getPluginType5(editor, KEYS17.columnGroup) || entry[0].type === getPluginType5(editor, KEYS17.table))) {
@@ -1536,9 +1520,7 @@ var renderCopilotBelowNodes = ({
1536
1520
  });
1537
1521
  const { renderGhostText: GhostText } = copilot.getOptions();
1538
1522
  if (!GhostText) return;
1539
- return ({ children }) => {
1540
- return /* @__PURE__ */ React.createElement(React.Fragment, null, children, /* @__PURE__ */ React.createElement(GhostText, null));
1541
- };
1523
+ return ({ children }) => /* @__PURE__ */ React.createElement(React.Fragment, null, children, /* @__PURE__ */ React.createElement(GhostText, null));
1542
1524
  };
1543
1525
 
1544
1526
  // src/react/copilot/transforms/acceptCopilot.ts
@@ -1635,21 +1617,22 @@ async function callCompletionApi({
1635
1617
  }
1636
1618
 
1637
1619
  // src/react/copilot/utils/getNextWord.ts
1620
+ var nonSpaceRegex = /^\s*(\S)/;
1621
+ var cjkCharRegex = /[\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF]/;
1622
+ var cjkMatchRegex = /^(\s*)([\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF])([\u3000-\u303F\uFF00-\uFFEF])?/;
1623
+ var nonCjkMatchRegex = /^(\s*\S+?)(?=[\s\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF]|$)/;
1638
1624
  var getNextWord = ({ text }) => {
1639
1625
  if (!text) return { firstWord: "", remainingText: "" };
1640
- const nonSpaceMatch = /^\s*(\S)/.exec(text);
1626
+ const nonSpaceMatch = nonSpaceRegex.exec(text);
1641
1627
  if (!nonSpaceMatch) return { firstWord: "", remainingText: "" };
1642
1628
  const firstNonSpaceChar = nonSpaceMatch[1];
1643
- const isCJKChar = /[\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF]/.test(
1644
- firstNonSpaceChar
1645
- );
1646
- let firstWord, remainingText;
1629
+ const isCJKChar = cjkCharRegex.test(firstNonSpaceChar);
1630
+ let firstWord;
1631
+ let remainingText;
1647
1632
  if (isCJKChar) {
1648
- const match = /^(\s*)([\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF])([\u3000-\u303F\uFF00-\uFFEF])?/.exec(
1649
- text
1650
- );
1633
+ const match = cjkMatchRegex.exec(text);
1651
1634
  if (match) {
1652
- const [fullMatch, spaces = "", char = "", punctuation = ""] = match;
1635
+ const [, spaces = "", char = "", punctuation = ""] = match;
1653
1636
  firstWord = spaces + char + punctuation;
1654
1637
  remainingText = text.slice(firstWord.length);
1655
1638
  } else {
@@ -1657,9 +1640,7 @@ var getNextWord = ({ text }) => {
1657
1640
  remainingText = text;
1658
1641
  }
1659
1642
  } else {
1660
- const match = /^(\s*\S+?)(?=[\s\u1100-\u11FF\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uAC00-\uD7AF\uF900-\uFAFF]|$)/.exec(
1661
- text
1662
- );
1643
+ const match = nonCjkMatchRegex.exec(text);
1663
1644
  if (match) {
1664
1645
  firstWord = match[0];
1665
1646
  remainingText = text.slice(firstWord.length);