@platejs/ai 52.3.10 → 52.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/getEditorPrompt-axDm9Fg4.js +235 -0
- package/dist/index-D2hJDomP.d.ts +137 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +41 -19
- package/dist/react/index.js +55 -28
- package/package.json +2 -2
- package/dist/getEditorPrompt-BnVrgUl3.js +0 -102
- package/dist/index-Dyi5V2wm.d.ts +0 -96
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { ElementApi, KEYS, TextApi, bindFirst, createTSlatePlugin, getPluginType } from "platejs";
|
|
2
|
+
import cloneDeep from "lodash/cloneDeep.js";
|
|
3
|
+
import { getTransientSuggestionKey } from "@platejs/suggestion";
|
|
4
|
+
import { isSelecting } from "@platejs/selection";
|
|
5
|
+
|
|
6
|
+
//#region src/lib/transforms/aiStreamSnapshot.ts
|
|
7
|
+
const AI_PREVIEW_KEY = "aiPreview";
|
|
8
|
+
const AI_STREAM_SNAPSHOT = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
const clearAIPreview = (editor) => {
|
|
10
|
+
AI_STREAM_SNAPSHOT.delete(editor);
|
|
11
|
+
};
|
|
12
|
+
const getAIPreview = (editor) => AI_STREAM_SNAPSHOT.get(editor);
|
|
13
|
+
const getAIPreviewRange = (editor) => {
|
|
14
|
+
let closed = false;
|
|
15
|
+
let end = -1;
|
|
16
|
+
let invalid = false;
|
|
17
|
+
let start = -1;
|
|
18
|
+
editor.children.forEach((node, index) => {
|
|
19
|
+
if (!node?.[AI_PREVIEW_KEY]) {
|
|
20
|
+
if (start !== -1) closed = true;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (closed) {
|
|
24
|
+
invalid = true;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (start === -1) start = index;
|
|
28
|
+
end = index;
|
|
29
|
+
});
|
|
30
|
+
if (invalid) return { kind: "invalid" };
|
|
31
|
+
if (start === -1 && end === -1) return { kind: "none" };
|
|
32
|
+
return {
|
|
33
|
+
end,
|
|
34
|
+
kind: "range",
|
|
35
|
+
start
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const removeAIPreviewAnchor = (editor) => {
|
|
39
|
+
const aiChatType = getPluginType(editor, KEYS.aiChat);
|
|
40
|
+
editor.tf.removeNodes({
|
|
41
|
+
at: [],
|
|
42
|
+
match: (node) => ElementApi.isElement(node) && node.type === aiChatType
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const restoreAIPreviewSelection = (editor, selection) => {
|
|
46
|
+
if (selection) {
|
|
47
|
+
editor.tf.select(cloneDeep(selection));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
editor.tf.deselect();
|
|
51
|
+
};
|
|
52
|
+
const removePreviewRange = (editor, range) => {
|
|
53
|
+
for (let index = range.end; index >= range.start; index--) editor.tf.removeNodes({ at: [index] });
|
|
54
|
+
};
|
|
55
|
+
const replacePreviewRange = (editor, range, blocks) => {
|
|
56
|
+
removePreviewRange(editor, range);
|
|
57
|
+
if (blocks.length === 0) return;
|
|
58
|
+
editor.tf.insertNodes(cloneDeep(blocks), { at: [range.start] });
|
|
59
|
+
};
|
|
60
|
+
const cloneAcceptedPreviewBlocks = (editor, range) => {
|
|
61
|
+
const aiType = getPluginType(editor, KEYS.ai);
|
|
62
|
+
const blocks = cloneDeep(editor.children.slice(range.start, range.end + 1));
|
|
63
|
+
const stripNode = (node) => {
|
|
64
|
+
if (ElementApi.isElement(node)) {
|
|
65
|
+
const { [AI_PREVIEW_KEY]: _preview, children, ...rest$1 } = node;
|
|
66
|
+
return {
|
|
67
|
+
...rest$1,
|
|
68
|
+
children: children.map(stripNode)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const { [aiType]: _ai, ...rest } = node;
|
|
72
|
+
return rest;
|
|
73
|
+
};
|
|
74
|
+
return blocks.map(stripNode);
|
|
75
|
+
};
|
|
76
|
+
const beginAIPreview = (editor, { originalBlocks = [] } = {}) => {
|
|
77
|
+
if (getAIPreview(editor)) return false;
|
|
78
|
+
AI_STREAM_SNAPSHOT.set(editor, {
|
|
79
|
+
originalBlocks: cloneDeep(originalBlocks),
|
|
80
|
+
selectionBefore: cloneDeep(editor.selection)
|
|
81
|
+
});
|
|
82
|
+
return true;
|
|
83
|
+
};
|
|
84
|
+
const hasAIPreview = (editor) => !!getAIPreview(editor);
|
|
85
|
+
const cancelAIPreview = (editor) => {
|
|
86
|
+
const preview = getAIPreview(editor);
|
|
87
|
+
if (!preview) return false;
|
|
88
|
+
const range = getAIPreviewRange(editor);
|
|
89
|
+
if (range.kind === "invalid") return false;
|
|
90
|
+
editor.tf.withoutSaving(() => {
|
|
91
|
+
if (range.kind === "range") replacePreviewRange(editor, range, preview.originalBlocks);
|
|
92
|
+
removeAIPreviewAnchor(editor);
|
|
93
|
+
restoreAIPreviewSelection(editor, preview.selectionBefore);
|
|
94
|
+
});
|
|
95
|
+
clearAIPreview(editor);
|
|
96
|
+
return true;
|
|
97
|
+
};
|
|
98
|
+
const discardAIPreview = (editor) => {
|
|
99
|
+
if (!getAIPreview(editor)) return false;
|
|
100
|
+
clearAIPreview(editor);
|
|
101
|
+
return true;
|
|
102
|
+
};
|
|
103
|
+
const acceptAIPreview = (editor, _value) => {
|
|
104
|
+
const preview = getAIPreview(editor);
|
|
105
|
+
if (!preview) return false;
|
|
106
|
+
const range = getAIPreviewRange(editor);
|
|
107
|
+
if (range.kind === "invalid") return false;
|
|
108
|
+
if (range.kind === "range") {
|
|
109
|
+
const acceptedBlocks = cloneAcceptedPreviewBlocks(editor, range);
|
|
110
|
+
editor.tf.withoutSaving(() => {
|
|
111
|
+
replacePreviewRange(editor, range, preview.originalBlocks);
|
|
112
|
+
removeAIPreviewAnchor(editor);
|
|
113
|
+
restoreAIPreviewSelection(editor, preview.selectionBefore);
|
|
114
|
+
});
|
|
115
|
+
editor.tf.withNewBatch(() => {
|
|
116
|
+
if (preview.originalBlocks.length > 0) for (let index = preview.originalBlocks.length - 1; index >= 0; index--) editor.tf.removeNodes({ at: [range.start + index] });
|
|
117
|
+
if (acceptedBlocks.length > 0) editor.tf.insertNodes(acceptedBlocks, { at: [range.start] });
|
|
118
|
+
});
|
|
119
|
+
const lastBatch = editor.history?.undos.at(-1);
|
|
120
|
+
if (lastBatch) lastBatch.selectionBefore = cloneDeep(preview.selectionBefore);
|
|
121
|
+
} else editor.tf.withoutSaving(() => {
|
|
122
|
+
removeAIPreviewAnchor(editor);
|
|
123
|
+
});
|
|
124
|
+
clearAIPreview(editor);
|
|
125
|
+
return true;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/lib/transforms/insertAINodes.ts
|
|
130
|
+
const insertAINodes = (editor, nodes, { target } = {}) => {
|
|
131
|
+
if (!target && !editor.selection?.focus.path) return;
|
|
132
|
+
const aiNodes = nodes.map((node) => ({
|
|
133
|
+
...node,
|
|
134
|
+
ai: true
|
|
135
|
+
}));
|
|
136
|
+
editor.tf.withoutNormalizing(() => {
|
|
137
|
+
editor.tf.insertNodes(aiNodes, {
|
|
138
|
+
at: editor.api.end(target || editor.selection.focus.path),
|
|
139
|
+
select: true
|
|
140
|
+
});
|
|
141
|
+
editor.tf.collapse({ edge: "end" });
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/lib/transforms/removeAIMarks.ts
|
|
147
|
+
const removeAIMarks = (editor, { at = [] } = {}) => {
|
|
148
|
+
const nodeType = getPluginType(editor, KEYS.ai);
|
|
149
|
+
editor.tf.unsetNodes(nodeType, {
|
|
150
|
+
at,
|
|
151
|
+
match: (n) => n[nodeType]
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/lib/transforms/removeAINodes.ts
|
|
157
|
+
const removeAINodes = (editor, { at = [] } = {}) => {
|
|
158
|
+
editor.tf.removeNodes({
|
|
159
|
+
at,
|
|
160
|
+
match: (n) => TextApi.isText(n) && !!n.ai
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/lib/transforms/undoAI.ts
|
|
166
|
+
const undoAI = (editor) => {
|
|
167
|
+
if (hasAIPreview(editor) && cancelAIPreview(editor)) return;
|
|
168
|
+
const hasAINodeOrAISuggestion = editor.api.some({
|
|
169
|
+
at: [],
|
|
170
|
+
match: (n) => !!n.ai
|
|
171
|
+
}) || editor.api.some({
|
|
172
|
+
at: [],
|
|
173
|
+
match: (n) => !!n[getTransientSuggestionKey()]
|
|
174
|
+
});
|
|
175
|
+
if (editor.history.undos.at(-1)?.ai && hasAINodeOrAISuggestion) {
|
|
176
|
+
editor.undo();
|
|
177
|
+
editor.history.redos.pop();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (hasAINodeOrAISuggestion) cancelAIPreview(editor);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/lib/transforms/withAIBatch.ts
|
|
185
|
+
const withAIBatch = (editor, fn, { split } = {}) => {
|
|
186
|
+
if (split) editor.tf.withNewBatch(fn);
|
|
187
|
+
else editor.tf.withMerging(fn);
|
|
188
|
+
const lastBatch = editor.history.undos?.at(-1);
|
|
189
|
+
if (lastBatch) lastBatch.ai = true;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/lib/BaseAIPlugin.ts
|
|
194
|
+
const getAITransforms = (editor) => ({
|
|
195
|
+
acceptPreview: bindFirst(acceptAIPreview, editor),
|
|
196
|
+
beginPreview: bindFirst(beginAIPreview, editor),
|
|
197
|
+
cancelPreview: bindFirst(cancelAIPreview, editor),
|
|
198
|
+
discardPreview: bindFirst(discardAIPreview, editor),
|
|
199
|
+
hasPreview: bindFirst(hasAIPreview, editor),
|
|
200
|
+
insertNodes: bindFirst(insertAINodes, editor),
|
|
201
|
+
removeMarks: bindFirst(removeAIMarks, editor),
|
|
202
|
+
removeNodes: bindFirst(removeAINodes, editor),
|
|
203
|
+
undo: bindFirst(undoAI, editor)
|
|
204
|
+
});
|
|
205
|
+
const BaseAIPlugin = createTSlatePlugin({
|
|
206
|
+
key: KEYS.ai,
|
|
207
|
+
node: {
|
|
208
|
+
isDecoration: false,
|
|
209
|
+
isLeaf: true
|
|
210
|
+
}
|
|
211
|
+
}).extendTransforms(({ editor }) => getAITransforms(editor)).extendEditorTransforms(({ editor }) => ({ ai: getAITransforms(editor) }));
|
|
212
|
+
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/lib/utils/getEditorPrompt.ts
|
|
215
|
+
const createPromptFromConfig = (config, params) => {
|
|
216
|
+
const { isBlockSelecting, isSelecting: isSelecting$1 } = params;
|
|
217
|
+
if (isBlockSelecting && config.blockSelecting) return config.blockSelecting ?? config.default;
|
|
218
|
+
if (isSelecting$1 && config.selecting) return config.selecting ?? config.default;
|
|
219
|
+
return config.default;
|
|
220
|
+
};
|
|
221
|
+
const getEditorPrompt = (editor, { prompt = "" }) => {
|
|
222
|
+
const params = {
|
|
223
|
+
editor,
|
|
224
|
+
isBlockSelecting: editor.getOption({ key: KEYS.blockSelection }, "isSelectingSome"),
|
|
225
|
+
isSelecting: isSelecting(editor)
|
|
226
|
+
};
|
|
227
|
+
let promptText = "";
|
|
228
|
+
if (typeof prompt === "function") promptText = prompt(params);
|
|
229
|
+
else if (typeof prompt === "object") promptText = createPromptFromConfig(prompt, params);
|
|
230
|
+
else promptText = prompt;
|
|
231
|
+
return promptText;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
//#endregion
|
|
235
|
+
export { removeAINodes as a, AI_PREVIEW_KEY as c, cancelAIPreview as d, discardAIPreview as f, undoAI as i, acceptAIPreview as l, BaseAIPlugin as n, removeAIMarks as o, hasAIPreview as p, withAIBatch as r, insertAINodes as s, getEditorPrompt as t, beginAIPreview as u };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as platejs0 from "platejs";
|
|
2
|
+
import { Descendant, History, OmitFirst, Path, PluginConfig, SlateEditor, TLocation, Value } from "platejs";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/transforms/aiStreamSnapshot.d.ts
|
|
5
|
+
type BeginAIPreviewOptions = {
|
|
6
|
+
originalBlocks?: Value;
|
|
7
|
+
};
|
|
8
|
+
declare const AI_PREVIEW_KEY = "aiPreview";
|
|
9
|
+
declare const beginAIPreview: (editor: SlateEditor, {
|
|
10
|
+
originalBlocks
|
|
11
|
+
}?: BeginAIPreviewOptions) => boolean;
|
|
12
|
+
declare const hasAIPreview: (editor: SlateEditor) => boolean;
|
|
13
|
+
declare const cancelAIPreview: (editor: SlateEditor) => boolean;
|
|
14
|
+
declare const discardAIPreview: (editor: SlateEditor) => boolean;
|
|
15
|
+
declare const acceptAIPreview: (editor: SlateEditor, _value?: Value) => boolean;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/lib/transforms/insertAINodes.d.ts
|
|
18
|
+
declare const insertAINodes: (editor: SlateEditor, nodes: Descendant[], {
|
|
19
|
+
target
|
|
20
|
+
}?: {
|
|
21
|
+
target?: Path;
|
|
22
|
+
}) => void;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/lib/transforms/removeAIMarks.d.ts
|
|
25
|
+
declare const removeAIMarks: (editor: SlateEditor, {
|
|
26
|
+
at
|
|
27
|
+
}?: {
|
|
28
|
+
at?: TLocation;
|
|
29
|
+
}) => void;
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/lib/transforms/removeAINodes.d.ts
|
|
32
|
+
declare const removeAINodes: (editor: SlateEditor, {
|
|
33
|
+
at
|
|
34
|
+
}?: {
|
|
35
|
+
at?: Path;
|
|
36
|
+
}) => void;
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/lib/transforms/undoAI.d.ts
|
|
39
|
+
declare const undoAI: (editor: SlateEditor) => void;
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/lib/transforms/withAIBatch.d.ts
|
|
42
|
+
type AIBatch = History['undos'][number] & {
|
|
43
|
+
ai?: boolean;
|
|
44
|
+
};
|
|
45
|
+
declare const withAIBatch: (editor: SlateEditor, fn: () => void, {
|
|
46
|
+
split
|
|
47
|
+
}?: {
|
|
48
|
+
split?: boolean;
|
|
49
|
+
}) => void;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/lib/BaseAIPlugin.d.ts
|
|
52
|
+
type BaseAIPluginConfig = PluginConfig<'ai', {}, {}, {
|
|
53
|
+
ai: {
|
|
54
|
+
/** Commit the active preview as one fresh undoable batch. */
|
|
55
|
+
acceptPreview: OmitFirst<typeof acceptAIPreview>;
|
|
56
|
+
/** Capture the rollback slice and selection for AI preview. */
|
|
57
|
+
beginPreview: OmitFirst<typeof beginAIPreview>;
|
|
58
|
+
/** Restore the rollback point and clear active preview state. */
|
|
59
|
+
cancelPreview: OmitFirst<typeof cancelAIPreview>;
|
|
60
|
+
/** Clear active preview bookkeeping without restoring content. */
|
|
61
|
+
discardPreview: OmitFirst<typeof discardAIPreview>;
|
|
62
|
+
/** Report whether an AI preview rollback point is active. */
|
|
63
|
+
hasPreview: OmitFirst<typeof hasAIPreview>;
|
|
64
|
+
insertNodes: OmitFirst<typeof insertAINodes>;
|
|
65
|
+
removeMarks: OmitFirst<typeof removeAIMarks>;
|
|
66
|
+
removeNodes: OmitFirst<typeof removeAINodes>;
|
|
67
|
+
undo: OmitFirst<typeof undoAI>;
|
|
68
|
+
};
|
|
69
|
+
}>;
|
|
70
|
+
declare const BaseAIPlugin: platejs0.SlatePlugin<PluginConfig<"ai", {}, {}, {
|
|
71
|
+
ai: {
|
|
72
|
+
acceptPreview: ((_value?: platejs0.Value | undefined) => boolean) & ((_value?: platejs0.Value | undefined) => boolean);
|
|
73
|
+
beginPreview: ((args_0?: {
|
|
74
|
+
originalBlocks?: platejs0.Value;
|
|
75
|
+
} | undefined) => boolean) & ((args_0?: {
|
|
76
|
+
originalBlocks?: platejs0.Value;
|
|
77
|
+
} | undefined) => boolean);
|
|
78
|
+
cancelPreview: (() => boolean) & (() => boolean);
|
|
79
|
+
discardPreview: (() => boolean) & (() => boolean);
|
|
80
|
+
hasPreview: (() => boolean) & (() => boolean);
|
|
81
|
+
insertNodes: ((nodes: platejs0.Descendant[], args_1?: {
|
|
82
|
+
target?: platejs0.Path;
|
|
83
|
+
} | undefined) => void) & ((nodes: platejs0.Descendant[], args_1?: {
|
|
84
|
+
target?: platejs0.Path;
|
|
85
|
+
} | undefined) => void);
|
|
86
|
+
removeMarks: ((args_0?: {
|
|
87
|
+
at?: platejs0.TLocation;
|
|
88
|
+
} | undefined) => void) & ((args_0?: {
|
|
89
|
+
at?: platejs0.TLocation;
|
|
90
|
+
} | undefined) => void);
|
|
91
|
+
removeNodes: ((args_0?: {
|
|
92
|
+
at?: platejs0.Path;
|
|
93
|
+
} | undefined) => void) & ((args_0?: {
|
|
94
|
+
at?: platejs0.Path;
|
|
95
|
+
} | undefined) => void);
|
|
96
|
+
undo: (() => void) & (() => void);
|
|
97
|
+
};
|
|
98
|
+
}, {}>>;
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/lib/types.d.ts
|
|
101
|
+
type AIToolName = 'comment' | 'edit' | 'generate' | null;
|
|
102
|
+
type AIMode = 'chat' | 'insert';
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/lib/utils/getEditorPrompt.d.ts
|
|
105
|
+
type EditorPrompt = ((params: EditorPromptParams) => string) | PromptConfig | string;
|
|
106
|
+
type EditorPromptParams = {
|
|
107
|
+
editor: SlateEditor;
|
|
108
|
+
isBlockSelecting: boolean;
|
|
109
|
+
isSelecting: boolean;
|
|
110
|
+
};
|
|
111
|
+
type PromptConfig = {
|
|
112
|
+
default: string;
|
|
113
|
+
blockSelecting?: string;
|
|
114
|
+
selecting?: string;
|
|
115
|
+
};
|
|
116
|
+
declare const getEditorPrompt: (editor: SlateEditor, {
|
|
117
|
+
prompt
|
|
118
|
+
}: {
|
|
119
|
+
prompt?: EditorPrompt;
|
|
120
|
+
}) => string;
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/lib/utils/replacePlaceholders.d.ts
|
|
123
|
+
type MarkdownType = 'block' | 'blockSelection' | 'blockSelectionWithBlockId' | 'blockWithBlockId' | 'editor' | 'editorWithBlockId' | 'tableCellWithId';
|
|
124
|
+
declare const replacePlaceholders: (editor: SlateEditor, text: string, {
|
|
125
|
+
prompt
|
|
126
|
+
}?: {
|
|
127
|
+
prompt?: string;
|
|
128
|
+
}) => string;
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/lib/utils/getMarkdown.d.ts
|
|
131
|
+
declare const getMarkdown: (editor: SlateEditor, {
|
|
132
|
+
type
|
|
133
|
+
}: {
|
|
134
|
+
type: MarkdownType;
|
|
135
|
+
}) => string;
|
|
136
|
+
//#endregion
|
|
137
|
+
export { hasAIPreview as C, discardAIPreview as S, insertAINodes as _, EditorPromptParams as a, beginAIPreview as b, AIMode as c, BaseAIPluginConfig as d, AIBatch as f, removeAIMarks as g, removeAINodes as h, EditorPrompt as i, AIToolName as l, undoAI as m, MarkdownType as n, PromptConfig as o, withAIBatch as p, replacePlaceholders as r, getEditorPrompt as s, getMarkdown as t, BaseAIPlugin as u, AI_PREVIEW_KEY as v, cancelAIPreview as x, acceptAIPreview as y };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as insertAINodes, a as EditorPromptParams, c as AIMode, d as BaseAIPluginConfig, f as AIBatch, g as removeAIMarks, h as removeAINodes, i as EditorPrompt, l as AIToolName, m as undoAI, n as MarkdownType, o as PromptConfig, p as withAIBatch, r as replacePlaceholders, s as getEditorPrompt, t as getMarkdown, u as BaseAIPlugin } from "./index-
|
|
2
|
-
export { AIBatch, AIMode, AIToolName, BaseAIPlugin, BaseAIPluginConfig, EditorPrompt, EditorPromptParams, MarkdownType, PromptConfig, getEditorPrompt, getMarkdown, insertAINodes, removeAIMarks, removeAINodes, replacePlaceholders, undoAI, withAIBatch };
|
|
1
|
+
import { C as hasAIPreview, S as discardAIPreview, _ as insertAINodes, a as EditorPromptParams, b as beginAIPreview, c as AIMode, d as BaseAIPluginConfig, f as AIBatch, g as removeAIMarks, h as removeAINodes, i as EditorPrompt, l as AIToolName, m as undoAI, n as MarkdownType, o as PromptConfig, p as withAIBatch, r as replacePlaceholders, s as getEditorPrompt, t as getMarkdown, u as BaseAIPlugin, v as AI_PREVIEW_KEY, x as cancelAIPreview, y as acceptAIPreview } from "./index-D2hJDomP";
|
|
2
|
+
export { AIBatch, AIMode, AIToolName, AI_PREVIEW_KEY, BaseAIPlugin, BaseAIPluginConfig, EditorPrompt, EditorPromptParams, MarkdownType, PromptConfig, acceptAIPreview, beginAIPreview, cancelAIPreview, discardAIPreview, getEditorPrompt, getMarkdown, hasAIPreview, insertAINodes, removeAIMarks, removeAINodes, replacePlaceholders, undoAI, withAIBatch };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as removeAINodes, i as undoAI, n as BaseAIPlugin, o as removeAIMarks, r as withAIBatch, s as insertAINodes, t as getEditorPrompt } from "./getEditorPrompt-
|
|
1
|
+
import { a as removeAINodes, c as AI_PREVIEW_KEY, d as cancelAIPreview, f as discardAIPreview, i as undoAI, l as acceptAIPreview, n as BaseAIPlugin, o as removeAIMarks, p as hasAIPreview, r as withAIBatch, s as insertAINodes, t as getEditorPrompt, u as beginAIPreview } from "./getEditorPrompt-axDm9Fg4.js";
|
|
2
2
|
import { KEYS } from "platejs";
|
|
3
3
|
import { serializeMd } from "@platejs/markdown";
|
|
4
4
|
import { getTableGridAbove } from "@platejs/table";
|
|
@@ -121,4 +121,4 @@ const replacePlaceholders = (editor, text, { prompt } = {}) => {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
//#endregion
|
|
124
|
-
export { BaseAIPlugin, getEditorPrompt, getMarkdown, insertAINodes, removeAIMarks, removeAINodes, replacePlaceholders, undoAI, withAIBatch };
|
|
124
|
+
export { AI_PREVIEW_KEY, BaseAIPlugin, acceptAIPreview, beginAIPreview, cancelAIPreview, discardAIPreview, getEditorPrompt, getMarkdown, hasAIPreview, insertAINodes, removeAIMarks, removeAINodes, replacePlaceholders, undoAI, withAIBatch };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as AIMode, d as BaseAIPluginConfig, i as EditorPrompt, l as AIToolName } from "../index-
|
|
2
|
-
import * as
|
|
1
|
+
import { c as AIMode, d as BaseAIPluginConfig, i as EditorPrompt, l as AIToolName } from "../index-D2hJDomP";
|
|
2
|
+
import * as platejs12 from "platejs";
|
|
3
3
|
import { Descendant, EditorNodesOptions, ExtendConfig, NodeEntry, OmitFirst, Path, PluginConfig, Range, RemoveNodesOptions, SlateEditor, TElement, TIdElement, TRange, TTableElement, TText } from "platejs";
|
|
4
4
|
import { DeserializeMdOptions, SerializeMdOptions } from "@platejs/markdown";
|
|
5
5
|
import * as platejs_react0 from "platejs/react";
|
|
@@ -11,18 +11,35 @@ import { TriggerComboboxPluginOptions } from "@platejs/combobox";
|
|
|
11
11
|
|
|
12
12
|
//#region src/react/ai/AIPlugin.d.ts
|
|
13
13
|
type AIPluginConfig = ExtendConfig<BaseAIPluginConfig>;
|
|
14
|
-
declare const AIPlugin: platejs_react0.PlatePlugin<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
declare const AIPlugin: platejs_react0.PlatePlugin<platejs12.PluginConfig<"ai", {}, {}, {
|
|
15
|
+
ai: {
|
|
16
|
+
acceptPreview: ((_value?: platejs12.Value | undefined) => boolean) & ((_value?: platejs12.Value | undefined) => boolean);
|
|
17
|
+
beginPreview: ((args_0?: {
|
|
18
|
+
originalBlocks?: platejs12.Value;
|
|
19
|
+
} | undefined) => boolean) & ((args_0?: {
|
|
20
|
+
originalBlocks?: platejs12.Value;
|
|
21
|
+
} | undefined) => boolean);
|
|
22
|
+
cancelPreview: (() => boolean) & (() => boolean);
|
|
23
|
+
discardPreview: (() => boolean) & (() => boolean);
|
|
24
|
+
hasPreview: (() => boolean) & (() => boolean);
|
|
25
|
+
insertNodes: ((nodes: platejs12.Descendant[], args_1?: {
|
|
26
|
+
target?: platejs12.Path;
|
|
27
|
+
} | undefined) => void) & ((nodes: platejs12.Descendant[], args_1?: {
|
|
28
|
+
target?: platejs12.Path;
|
|
29
|
+
} | undefined) => void);
|
|
30
|
+
removeMarks: ((args_0?: {
|
|
31
|
+
at?: platejs12.TLocation;
|
|
32
|
+
} | undefined) => void) & ((args_0?: {
|
|
33
|
+
at?: platejs12.TLocation;
|
|
34
|
+
} | undefined) => void);
|
|
35
|
+
removeNodes: ((args_0?: {
|
|
36
|
+
at?: platejs12.Path;
|
|
37
|
+
} | undefined) => void) & ((args_0?: {
|
|
38
|
+
at?: platejs12.Path;
|
|
39
|
+
} | undefined) => void);
|
|
40
|
+
undo: (() => void) & (() => void);
|
|
41
|
+
};
|
|
42
|
+
}, {}>>;
|
|
26
43
|
//#endregion
|
|
27
44
|
//#region src/react/ai-chat/internal/types.d.ts
|
|
28
45
|
type ToolName = 'comment' | 'edit' | 'generate';
|
|
@@ -206,7 +223,7 @@ declare const AIChatPlugin: platejs_react0.PlatePlugin<PluginConfig<"aiChat", {
|
|
|
206
223
|
reload: () => void;
|
|
207
224
|
show: () => void;
|
|
208
225
|
stop: () => void;
|
|
209
|
-
}, "node" | "
|
|
226
|
+
}, "node" | "reset" | "stop" | "submit">> & Record<"aiChat", {
|
|
210
227
|
hide: ({
|
|
211
228
|
focus,
|
|
212
229
|
undo
|
|
@@ -227,7 +244,7 @@ declare const AIChatPlugin: platejs_react0.PlatePlugin<PluginConfig<"aiChat", {
|
|
|
227
244
|
insertBelow: (sourceEditor: SlateEditor, args_1?: {
|
|
228
245
|
format?: "all" | "none" | "single";
|
|
229
246
|
} | undefined) => void;
|
|
230
|
-
removeAnchor: (options?:
|
|
247
|
+
removeAnchor: (options?: platejs12.RemoveNodesOptions | undefined) => void;
|
|
231
248
|
replaceSelection: (sourceEditor: SlateEditor, args_1?: {
|
|
232
249
|
format?: "all" | "none" | "single";
|
|
233
250
|
} | undefined) => void;
|
|
@@ -245,7 +262,7 @@ declare const withAIChat: OverrideEditor<AIChatPluginConfig>;
|
|
|
245
262
|
*/
|
|
246
263
|
declare const useAIChatEditor: (editor: SlateEditor, content: string, {
|
|
247
264
|
parser
|
|
248
|
-
}?: DeserializeMdOptions) =>
|
|
265
|
+
}?: DeserializeMdOptions) => platejs12.Value;
|
|
249
266
|
//#endregion
|
|
250
267
|
//#region src/react/ai-chat/hooks/useChatChunk.d.ts
|
|
251
268
|
declare const useChatChunk: ({
|
|
@@ -281,7 +298,7 @@ declare const useEditorChat: ({
|
|
|
281
298
|
}: UseEditorChatOptions) => void;
|
|
282
299
|
//#endregion
|
|
283
300
|
//#region src/react/ai-chat/streaming/streamDeserializeInlineMd.d.ts
|
|
284
|
-
declare const streamDeserializeInlineMd: (editor: PlateEditor, text: string, options?: DeserializeMdOptions) =>
|
|
301
|
+
declare const streamDeserializeInlineMd: (editor: PlateEditor, text: string, options?: DeserializeMdOptions) => platejs12.Descendant[] | {
|
|
285
302
|
text: string;
|
|
286
303
|
}[];
|
|
287
304
|
//#endregion
|
|
@@ -298,6 +315,11 @@ type SteamInsertChunkOptions = {
|
|
|
298
315
|
elementProps?: any;
|
|
299
316
|
textProps?: any;
|
|
300
317
|
};
|
|
318
|
+
declare const getInsertPreviewStart: (editor: SlateEditor) => {
|
|
319
|
+
path: Path;
|
|
320
|
+
startBlock: platejs12.TElement | platejs12.TText | undefined;
|
|
321
|
+
startInEmptyParagraph: boolean;
|
|
322
|
+
};
|
|
301
323
|
/** @experimental */
|
|
302
324
|
declare function streamInsertChunk(editor: PlateEditor, chunk: string, options?: SteamInsertChunkOptions): void;
|
|
303
325
|
declare const getCurrentBlockPath: (editor: SlateEditor) => Path;
|
|
@@ -584,4 +606,4 @@ declare const withCopilot: OverrideEditor<CopilotPluginConfig>;
|
|
|
584
606
|
//#region src/react/copilot/utils/withoutAbort.d.ts
|
|
585
607
|
declare const withoutAbort: (editor: PlateEditor, fn: () => void) => void;
|
|
586
608
|
//#endregion
|
|
587
|
-
export { AIChatPlugin, AIChatPluginConfig, AIPlugin, AIPluginConfig, CallCompletionApiOptions, CompleteOptions, CopilotPlugin, CopilotPluginConfig, GetNextWord, SteamInsertChunkOptions, TableCellUpdate, UseEditorChatOptions, acceptAIChat, acceptAISuggestions, acceptCopilot, acceptCopilotNextWord, aiCommentToRange, applyAISuggestions, applyTableCellSuggestion, callCompletionApi, createFormattedBlocks, escapeInput, findTextRangeInBlock, getChunkTrimmed, getCurrentBlockPath, getLastAssistantMessage, getListNode, getNextWord, getTableCellChildren, insertBelowAIChat, insertBelowGenerate, isCompleteCodeBlock, isCompleteMath, isSameNode, isSingleCellTable, nodesWithProps, rejectAISuggestions, removeAnchorAIChat, renderCopilotBelowNodes, replaceSelectionAIChat, resetAIChat, streamDeserializeInlineMd, streamDeserializeMd, streamInsertChunk, streamSerializeMd, submitAIChat, triggerCopilotSuggestion, useAIChatEditor, useChatChunk, useEditorChat, useLastAssistantMessage, withAIChat, withCopilot, withTransient, withoutAbort, withoutSuggestionAndComments };
|
|
609
|
+
export { AIChatPlugin, AIChatPluginConfig, AIPlugin, AIPluginConfig, CallCompletionApiOptions, CompleteOptions, CopilotPlugin, CopilotPluginConfig, GetNextWord, SteamInsertChunkOptions, TableCellUpdate, UseEditorChatOptions, acceptAIChat, acceptAISuggestions, acceptCopilot, acceptCopilotNextWord, aiCommentToRange, applyAISuggestions, applyTableCellSuggestion, callCompletionApi, createFormattedBlocks, escapeInput, findTextRangeInBlock, getChunkTrimmed, getCurrentBlockPath, getInsertPreviewStart, getLastAssistantMessage, getListNode, getNextWord, getTableCellChildren, insertBelowAIChat, insertBelowGenerate, isCompleteCodeBlock, isCompleteMath, isSameNode, isSingleCellTable, nodesWithProps, rejectAISuggestions, removeAnchorAIChat, renderCopilotBelowNodes, replaceSelectionAIChat, resetAIChat, streamDeserializeInlineMd, streamDeserializeMd, streamInsertChunk, streamSerializeMd, submitAIChat, triggerCopilotSuggestion, useAIChatEditor, useChatChunk, useEditorChat, useLastAssistantMessage, withAIChat, withCopilot, withTransient, withoutAbort, withoutSuggestionAndComments };
|
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { n as BaseAIPlugin, r as withAIBatch, t as getEditorPrompt } from "../getEditorPrompt-
|
|
1
|
+
import { c as AI_PREVIEW_KEY, n as BaseAIPlugin, p as hasAIPreview, r as withAIBatch, t as getEditorPrompt } from "../getEditorPrompt-axDm9Fg4.js";
|
|
2
2
|
import { ElementApi, KEYS, NodeApi, PathApi, RangeApi, TextApi, bindFirst, getPluginKey, getPluginType, isDefined, nanoid } from "platejs";
|
|
3
|
+
import cloneDeep from "lodash/cloneDeep.js";
|
|
3
4
|
import { SkipSuggestionDeletes, acceptSuggestion, diffToSuggestions, getSuggestionKey, getTransientSuggestionKey, rejectSuggestion } from "@platejs/suggestion";
|
|
4
5
|
import { isSelecting } from "@platejs/selection";
|
|
5
6
|
import { MarkdownPlugin, deserializeInlineMd, deserializeMd, serializeInlineMd, serializeMd } from "@platejs/markdown";
|
|
@@ -7,7 +8,6 @@ import { createTPlatePlugin, getEditorPlugin, toPlatePlugin, useEditorPlugin, us
|
|
|
7
8
|
import { distance } from "fastest-levenshtein";
|
|
8
9
|
import { BlockSelectionPlugin, removeBlockSelectionNodes } from "@platejs/selection/react";
|
|
9
10
|
import { SuggestionPlugin } from "@platejs/suggestion/react";
|
|
10
|
-
import cloneDeep from "lodash/cloneDeep.js";
|
|
11
11
|
import { c } from "react-compiler-runtime";
|
|
12
12
|
import React, { useEffect, useMemo, useRef } from "react";
|
|
13
13
|
import debounce from "lodash/debounce.js";
|
|
@@ -168,23 +168,31 @@ const acceptAISuggestions = (editor) => {
|
|
|
168
168
|
|
|
169
169
|
//#endregion
|
|
170
170
|
//#region src/react/ai-chat/transforms/acceptAIChat.ts
|
|
171
|
+
const getAcceptedInsertFocusPoint = (editor) => {
|
|
172
|
+
let endIndex = null;
|
|
173
|
+
editor.children.forEach((node, index) => {
|
|
174
|
+
if (ElementApi.isElement(node) && node[AI_PREVIEW_KEY]) endIndex = index;
|
|
175
|
+
});
|
|
176
|
+
if (endIndex === null) return null;
|
|
177
|
+
return editor.api.end([endIndex]) ?? null;
|
|
178
|
+
};
|
|
171
179
|
const acceptAIChat = (editor) => {
|
|
172
180
|
const mode = editor.getOption(AIChatPlugin, "mode");
|
|
173
181
|
if (mode === "insert") {
|
|
174
|
-
const
|
|
182
|
+
const ai = editor.getTransforms(BaseAIPlugin).ai;
|
|
175
183
|
const api = editor.getApi({ key: KEYS.ai });
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
const focusPoint = getAcceptedInsertFocusPoint(editor);
|
|
185
|
+
if (!ai.acceptPreview()) withAIBatch(editor, () => {
|
|
186
|
+
editor.tf.unsetNodes(AI_PREVIEW_KEY, {
|
|
187
|
+
at: [],
|
|
188
|
+
match: (node) => ElementApi.isElement(node) && !!node[AI_PREVIEW_KEY]
|
|
189
|
+
});
|
|
190
|
+
ai.removeMarks();
|
|
182
191
|
editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();
|
|
183
192
|
});
|
|
184
193
|
api.aiChat.hide();
|
|
185
194
|
editor.tf.focus();
|
|
186
|
-
|
|
187
|
-
editor.tf.setSelection({
|
|
195
|
+
if (focusPoint) editor.tf.select({
|
|
188
196
|
anchor: focusPoint,
|
|
189
197
|
focus: focusPoint
|
|
190
198
|
});
|
|
@@ -389,7 +397,8 @@ const resetAIChat = (editor, { undo = true } = {}) => {
|
|
|
389
397
|
mode: "insert",
|
|
390
398
|
toolName: null
|
|
391
399
|
});
|
|
392
|
-
if (undo) editor.getTransforms(
|
|
400
|
+
if (undo) editor.getTransforms(BaseAIPlugin).ai.undo();
|
|
401
|
+
else editor.getTransforms(BaseAIPlugin).ai.discardPreview();
|
|
393
402
|
};
|
|
394
403
|
|
|
395
404
|
//#endregion
|
|
@@ -401,7 +410,7 @@ const submitAIChat = (editor, input, { mode, options, prompt, toolName: toolName
|
|
|
401
410
|
if (!prompt && input?.length === 0) return;
|
|
402
411
|
if (!prompt) prompt = input;
|
|
403
412
|
if (!mode) mode = isSelecting(editor) ? "chat" : "insert";
|
|
404
|
-
if (mode === "insert") editor.getTransforms(
|
|
413
|
+
if (mode === "insert") editor.getTransforms(BaseAIPlugin).ai.undo();
|
|
405
414
|
setOption("mode", mode);
|
|
406
415
|
setOption("toolName", toolName);
|
|
407
416
|
const blocks = editor.getApi(BlockSelectionPlugin).blockSelection.getNodes();
|
|
@@ -517,7 +526,7 @@ const insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) =>
|
|
|
517
526
|
if (toolName === "generate") return insertBelowGenerate(editor, sourceEditor, { format });
|
|
518
527
|
const selectedBlocks = editor.getApi(BlockSelectionPlugin).blockSelection.getNodes();
|
|
519
528
|
const selectedIds = editor.getOptions(BlockSelectionPlugin).selectedIds;
|
|
520
|
-
editor.getTransforms(
|
|
529
|
+
editor.getTransforms(BaseAIPlugin).ai.undo();
|
|
521
530
|
const insertBlocksAndSelect = editor.getTransforms(BlockSelectionPlugin).blockSelection.insertBlocksAndSelect;
|
|
522
531
|
if (!selectedIds || selectedIds.size === 0) return;
|
|
523
532
|
const lastBlock = selectedBlocks.at(-1);
|
|
@@ -594,7 +603,7 @@ const removeAnchorAIChat = (editor, options) => {
|
|
|
594
603
|
//#endregion
|
|
595
604
|
//#region src/react/ai-chat/withAIChat.ts
|
|
596
605
|
const withAIChat = ({ api, editor, getOptions, tf: { insertText, normalizeNode }, type }) => {
|
|
597
|
-
const
|
|
606
|
+
const ai = editor.getTransforms(BaseAIPlugin).ai;
|
|
598
607
|
const matchesTrigger = (text) => {
|
|
599
608
|
const { trigger } = getOptions();
|
|
600
609
|
if (trigger instanceof RegExp) return trigger.test(text);
|
|
@@ -619,7 +628,7 @@ const withAIChat = ({ api, editor, getOptions, tf: { insertText, normalizeNode }
|
|
|
619
628
|
normalizeNode(entry) {
|
|
620
629
|
const [node, path] = entry;
|
|
621
630
|
if (node[KEYS.ai] && !getOptions().open) {
|
|
622
|
-
|
|
631
|
+
ai.removeMarks({ at: path });
|
|
623
632
|
return;
|
|
624
633
|
}
|
|
625
634
|
if (ElementApi.isElement(node) && node.type === type && !getOptions().open) {
|
|
@@ -683,7 +692,7 @@ const AIChatPlugin = createTPlatePlugin({
|
|
|
683
692
|
},
|
|
684
693
|
reload: () => {
|
|
685
694
|
const { chat, chatNodes, chatSelection } = getOptions();
|
|
686
|
-
editor.getTransforms(
|
|
695
|
+
editor.getTransforms(BaseAIPlugin).ai.undo();
|
|
687
696
|
if (chatSelection) editor.tf.setSelection(chatSelection);
|
|
688
697
|
else editor.getApi(BlockSelectionPlugin).blockSelection.set(chatNodes.map((node) => node.id));
|
|
689
698
|
const blocks = editor.getApi(BlockSelectionPlugin).blockSelection.getNodes();
|
|
@@ -995,17 +1004,35 @@ const getNextPath = (path, length) => {
|
|
|
995
1004
|
for (let i = 0; i < length; i++) result = PathApi.next(result);
|
|
996
1005
|
return result;
|
|
997
1006
|
};
|
|
1007
|
+
const withPreviewElementProps = (editor, options) => {
|
|
1008
|
+
if (!hasAIPreview(editor)) return options;
|
|
1009
|
+
return {
|
|
1010
|
+
...options,
|
|
1011
|
+
elementProps: {
|
|
1012
|
+
...options.elementProps,
|
|
1013
|
+
[AI_PREVIEW_KEY]: true
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
};
|
|
1017
|
+
const getInsertPreviewStart = (editor) => {
|
|
1018
|
+
const path = getCurrentBlockPath(editor);
|
|
1019
|
+
const startBlock = editor.api.node(path)?.[0];
|
|
1020
|
+
return {
|
|
1021
|
+
path,
|
|
1022
|
+
startBlock,
|
|
1023
|
+
startInEmptyParagraph: !!startBlock && NodeApi.string(startBlock).length === 0 && startBlock.type === getPluginType(editor, KEYS.p)
|
|
1024
|
+
};
|
|
1025
|
+
};
|
|
998
1026
|
/** @experimental */
|
|
999
1027
|
function streamInsertChunk(editor, chunk, options = {}) {
|
|
1028
|
+
const insertOptions = withPreviewElementProps(editor, options);
|
|
1000
1029
|
const { _blockChunks, _blockPath } = editor.getOptions(AIChatPlugin);
|
|
1001
1030
|
if (_blockPath === null) {
|
|
1002
1031
|
const blocks = streamDeserializeMd(editor, chunk);
|
|
1003
|
-
const path =
|
|
1004
|
-
const startBlock = editor.api.node(path)[0];
|
|
1005
|
-
const startInEmptyParagraph = NodeApi.string(startBlock).length === 0 && startBlock.type === getPluginType(editor, KEYS.p);
|
|
1032
|
+
const { path, startInEmptyParagraph } = getInsertPreviewStart(editor);
|
|
1006
1033
|
if (startInEmptyParagraph) editor.tf.removeNodes({ at: path });
|
|
1007
1034
|
if (blocks.length > 0) {
|
|
1008
|
-
editor.tf.insertNodes(nodesWithProps(editor, [blocks[0]],
|
|
1035
|
+
editor.tf.insertNodes(nodesWithProps(editor, [blocks[0]], insertOptions), {
|
|
1009
1036
|
at: path,
|
|
1010
1037
|
nextBlock: !startInEmptyParagraph,
|
|
1011
1038
|
select: true
|
|
@@ -1015,7 +1042,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1015
1042
|
if (blocks.length > 1) {
|
|
1016
1043
|
const nextBlocks = blocks.slice(1);
|
|
1017
1044
|
const nextPath = getCurrentBlockPath(editor);
|
|
1018
|
-
editor.tf.insertNodes(nodesWithProps(editor, nextBlocks,
|
|
1045
|
+
editor.tf.insertNodes(nodesWithProps(editor, nextBlocks, insertOptions), {
|
|
1019
1046
|
at: nextPath,
|
|
1020
1047
|
nextBlock: true,
|
|
1021
1048
|
select: true
|
|
@@ -1034,7 +1061,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1034
1061
|
const currentBlock = editor.api.node(_blockPath)[0];
|
|
1035
1062
|
if (isSameNode(editor, currentBlock, tempBlocks[0])) {
|
|
1036
1063
|
const chunkNodes = streamDeserializeInlineMd(editor, chunk);
|
|
1037
|
-
editor.tf.insertNodes(nodesWithProps(editor, chunkNodes,
|
|
1064
|
+
editor.tf.insertNodes(nodesWithProps(editor, chunkNodes, insertOptions), {
|
|
1038
1065
|
at: editor.api.end(_blockPath),
|
|
1039
1066
|
select: true
|
|
1040
1067
|
});
|
|
@@ -1042,7 +1069,7 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1042
1069
|
const blockText = NodeApi.string(tempBlocks[0]);
|
|
1043
1070
|
if (serializedBlock === tempBlockChunks && blockText === serializedBlock) editor.setOption(AIChatPlugin, "_blockChunks", tempBlockChunks);
|
|
1044
1071
|
else {
|
|
1045
|
-
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]],
|
|
1072
|
+
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]], insertOptions), {
|
|
1046
1073
|
at: _blockPath,
|
|
1047
1074
|
select: true
|
|
1048
1075
|
});
|
|
@@ -1051,20 +1078,20 @@ function streamInsertChunk(editor, chunk, options = {}) {
|
|
|
1051
1078
|
}
|
|
1052
1079
|
} else {
|
|
1053
1080
|
const serializedBlock = streamSerializeMd(editor, { value: [tempBlocks[0]] }, tempBlockChunks);
|
|
1054
|
-
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]],
|
|
1081
|
+
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]], insertOptions), {
|
|
1055
1082
|
at: _blockPath,
|
|
1056
1083
|
select: true
|
|
1057
1084
|
});
|
|
1058
1085
|
editor.setOption(AIChatPlugin, "_blockChunks", serializedBlock);
|
|
1059
1086
|
}
|
|
1060
1087
|
} else {
|
|
1061
|
-
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]],
|
|
1088
|
+
editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]], insertOptions), {
|
|
1062
1089
|
at: _blockPath,
|
|
1063
1090
|
select: true
|
|
1064
1091
|
});
|
|
1065
1092
|
if (tempBlocks.length > 1) {
|
|
1066
1093
|
const newEndBlockPath = getNextPath(_blockPath, tempBlocks.length - 1);
|
|
1067
|
-
editor.tf.insertNodes(nodesWithProps(editor, tempBlocks.slice(1),
|
|
1094
|
+
editor.tf.insertNodes(nodesWithProps(editor, tempBlocks.slice(1), insertOptions), {
|
|
1068
1095
|
at: PathApi.next(_blockPath),
|
|
1069
1096
|
select: true
|
|
1070
1097
|
});
|
|
@@ -1400,4 +1427,4 @@ const CopilotPlugin = createTPlatePlugin({
|
|
|
1400
1427
|
});
|
|
1401
1428
|
|
|
1402
1429
|
//#endregion
|
|
1403
|
-
export { AIChatPlugin, AIPlugin, CopilotPlugin, acceptAIChat, acceptAISuggestions, acceptCopilot, acceptCopilotNextWord, aiCommentToRange, applyAISuggestions, applyTableCellSuggestion, callCompletionApi, createFormattedBlocks, escapeInput, findTextRangeInBlock, getChunkTrimmed, getCurrentBlockPath, getLastAssistantMessage, getListNode, getNextWord, getTableCellChildren, insertBelowAIChat, insertBelowGenerate, isCompleteCodeBlock, isCompleteMath, isSameNode, isSingleCellTable, nodesWithProps, rejectAISuggestions, removeAnchorAIChat, renderCopilotBelowNodes, replaceSelectionAIChat, resetAIChat, streamDeserializeInlineMd, streamDeserializeMd, streamInsertChunk, streamSerializeMd, submitAIChat, triggerCopilotSuggestion, useAIChatEditor, useChatChunk, useEditorChat, useLastAssistantMessage, withAIChat, withCopilot, withTransient, withoutAbort, withoutSuggestionAndComments };
|
|
1430
|
+
export { AIChatPlugin, AIPlugin, CopilotPlugin, acceptAIChat, acceptAISuggestions, acceptCopilot, acceptCopilotNextWord, aiCommentToRange, applyAISuggestions, applyTableCellSuggestion, callCompletionApi, createFormattedBlocks, escapeInput, findTextRangeInBlock, getChunkTrimmed, getCurrentBlockPath, getInsertPreviewStart, getLastAssistantMessage, getListNode, getNextWord, getTableCellChildren, insertBelowAIChat, insertBelowGenerate, isCompleteCodeBlock, isCompleteMath, isSameNode, isSingleCellTable, nodesWithProps, rejectAISuggestions, removeAnchorAIChat, renderCopilotBelowNodes, replaceSelectionAIChat, resetAIChat, streamDeserializeInlineMd, streamDeserializeMd, streamInsertChunk, streamSerializeMd, submitAIChat, triggerCopilotSuggestion, useAIChatEditor, useChatChunk, useEditorChat, useLastAssistantMessage, withAIChat, withCopilot, withTransient, withoutAbort, withoutSuggestionAndComments };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platejs/ai",
|
|
3
|
-
"version": "52.3.
|
|
3
|
+
"version": "52.3.12",
|
|
4
4
|
"description": "Text AI plugin for Plate",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plate",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@ai-sdk/react": "^3.0.0",
|
|
42
42
|
"ai": "^6.0.0",
|
|
43
43
|
"@plate/scripts": "1.0.0",
|
|
44
|
-
"platejs": "^52.3.
|
|
44
|
+
"platejs": "^52.3.11"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"platejs": ">=52.0.15",
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { KEYS, TextApi, bindFirst, createTSlatePlugin, getPluginType } from "platejs";
|
|
2
|
-
import { getTransientSuggestionKey } from "@platejs/suggestion";
|
|
3
|
-
import { isSelecting } from "@platejs/selection";
|
|
4
|
-
|
|
5
|
-
//#region src/lib/transforms/insertAINodes.ts
|
|
6
|
-
const insertAINodes = (editor, nodes, { target } = {}) => {
|
|
7
|
-
if (!target && !editor.selection?.focus.path) return;
|
|
8
|
-
const aiNodes = nodes.map((node) => ({
|
|
9
|
-
...node,
|
|
10
|
-
ai: true
|
|
11
|
-
}));
|
|
12
|
-
editor.tf.withoutNormalizing(() => {
|
|
13
|
-
editor.tf.insertNodes(aiNodes, {
|
|
14
|
-
at: editor.api.end(target || editor.selection.focus.path),
|
|
15
|
-
select: true
|
|
16
|
-
});
|
|
17
|
-
editor.tf.collapse({ edge: "end" });
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/lib/transforms/removeAIMarks.ts
|
|
23
|
-
const removeAIMarks = (editor, { at = [] } = {}) => {
|
|
24
|
-
const nodeType = getPluginType(editor, KEYS.ai);
|
|
25
|
-
editor.tf.unsetNodes(nodeType, {
|
|
26
|
-
at,
|
|
27
|
-
match: (n) => n[nodeType]
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/lib/transforms/removeAINodes.ts
|
|
33
|
-
const removeAINodes = (editor, { at = [] } = {}) => {
|
|
34
|
-
editor.tf.removeNodes({
|
|
35
|
-
at,
|
|
36
|
-
match: (n) => TextApi.isText(n) && !!n.ai
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/lib/transforms/undoAI.ts
|
|
42
|
-
const undoAI = (editor) => {
|
|
43
|
-
const hasAINodeOrAISuggestion = editor.api.some({
|
|
44
|
-
at: [],
|
|
45
|
-
match: (n) => !!n.ai
|
|
46
|
-
}) || editor.api.some({
|
|
47
|
-
at: [],
|
|
48
|
-
match: (n) => !!n[getTransientSuggestionKey()]
|
|
49
|
-
});
|
|
50
|
-
if (editor.history.undos.at(-1)?.ai && hasAINodeOrAISuggestion) {
|
|
51
|
-
editor.undo();
|
|
52
|
-
editor.history.redos.pop();
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/lib/transforms/withAIBatch.ts
|
|
58
|
-
const withAIBatch = (editor, fn, { split } = {}) => {
|
|
59
|
-
if (split) editor.tf.withNewBatch(fn);
|
|
60
|
-
else editor.tf.withMerging(fn);
|
|
61
|
-
const lastBatch = editor.history.undos?.at(-1);
|
|
62
|
-
if (lastBatch) lastBatch.ai = true;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
//#endregion
|
|
66
|
-
//#region src/lib/BaseAIPlugin.ts
|
|
67
|
-
const BaseAIPlugin = createTSlatePlugin({
|
|
68
|
-
key: KEYS.ai,
|
|
69
|
-
node: {
|
|
70
|
-
isDecoration: false,
|
|
71
|
-
isLeaf: true
|
|
72
|
-
}
|
|
73
|
-
}).extendTransforms(({ editor }) => ({
|
|
74
|
-
insertNodes: bindFirst(insertAINodes, editor),
|
|
75
|
-
removeMarks: bindFirst(removeAIMarks, editor),
|
|
76
|
-
removeNodes: bindFirst(removeAINodes, editor),
|
|
77
|
-
undo: bindFirst(undoAI, editor)
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/lib/utils/getEditorPrompt.ts
|
|
82
|
-
const createPromptFromConfig = (config, params) => {
|
|
83
|
-
const { isBlockSelecting, isSelecting: isSelecting$1 } = params;
|
|
84
|
-
if (isBlockSelecting && config.blockSelecting) return config.blockSelecting ?? config.default;
|
|
85
|
-
if (isSelecting$1 && config.selecting) return config.selecting ?? config.default;
|
|
86
|
-
return config.default;
|
|
87
|
-
};
|
|
88
|
-
const getEditorPrompt = (editor, { prompt = "" }) => {
|
|
89
|
-
const params = {
|
|
90
|
-
editor,
|
|
91
|
-
isBlockSelecting: editor.getOption({ key: KEYS.blockSelection }, "isSelectingSome"),
|
|
92
|
-
isSelecting: isSelecting(editor)
|
|
93
|
-
};
|
|
94
|
-
let promptText = "";
|
|
95
|
-
if (typeof prompt === "function") promptText = prompt(params);
|
|
96
|
-
else if (typeof prompt === "object") promptText = createPromptFromConfig(prompt, params);
|
|
97
|
-
else promptText = prompt;
|
|
98
|
-
return promptText;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
//#endregion
|
|
102
|
-
export { removeAINodes as a, undoAI as i, BaseAIPlugin as n, removeAIMarks as o, withAIBatch as r, insertAINodes as s, getEditorPrompt as t };
|
package/dist/index-Dyi5V2wm.d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import * as platejs5 from "platejs";
|
|
2
|
-
import { Descendant, History, OmitFirst, Path, PluginConfig, SlateEditor, TLocation } from "platejs";
|
|
3
|
-
|
|
4
|
-
//#region src/lib/transforms/insertAINodes.d.ts
|
|
5
|
-
declare const insertAINodes: (editor: SlateEditor, nodes: Descendant[], {
|
|
6
|
-
target
|
|
7
|
-
}?: {
|
|
8
|
-
target?: Path;
|
|
9
|
-
}) => void;
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/lib/transforms/removeAIMarks.d.ts
|
|
12
|
-
declare const removeAIMarks: (editor: SlateEditor, {
|
|
13
|
-
at
|
|
14
|
-
}?: {
|
|
15
|
-
at?: TLocation;
|
|
16
|
-
}) => void;
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/lib/transforms/removeAINodes.d.ts
|
|
19
|
-
declare const removeAINodes: (editor: SlateEditor, {
|
|
20
|
-
at
|
|
21
|
-
}?: {
|
|
22
|
-
at?: Path;
|
|
23
|
-
}) => void;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/lib/transforms/undoAI.d.ts
|
|
26
|
-
declare const undoAI: (editor: SlateEditor) => void;
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region src/lib/transforms/withAIBatch.d.ts
|
|
29
|
-
type AIBatch = History['undos'][number] & {
|
|
30
|
-
ai?: boolean;
|
|
31
|
-
};
|
|
32
|
-
declare const withAIBatch: (editor: SlateEditor, fn: () => void, {
|
|
33
|
-
split
|
|
34
|
-
}?: {
|
|
35
|
-
split?: boolean;
|
|
36
|
-
}) => void;
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/lib/BaseAIPlugin.d.ts
|
|
39
|
-
type BaseAIPluginConfig = PluginConfig<'ai', {}, {}, {
|
|
40
|
-
ai: {
|
|
41
|
-
insertNodes: OmitFirst<typeof insertAINodes>;
|
|
42
|
-
removeMarks: OmitFirst<typeof removeAIMarks>;
|
|
43
|
-
removeNodes: OmitFirst<typeof removeAINodes>;
|
|
44
|
-
};
|
|
45
|
-
}>;
|
|
46
|
-
declare const BaseAIPlugin: platejs5.SlatePlugin<PluginConfig<any, {}, {}, Record<any, {
|
|
47
|
-
insertNodes: (nodes: platejs5.Descendant[], args_1?: {
|
|
48
|
-
target?: platejs5.Path;
|
|
49
|
-
} | undefined) => void;
|
|
50
|
-
removeMarks: (args_0?: {
|
|
51
|
-
at?: platejs5.TLocation;
|
|
52
|
-
} | undefined) => void;
|
|
53
|
-
removeNodes: (args_0?: {
|
|
54
|
-
at?: platejs5.Path;
|
|
55
|
-
} | undefined) => void;
|
|
56
|
-
undo: () => void;
|
|
57
|
-
}>, {}>>;
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/lib/types.d.ts
|
|
60
|
-
type AIToolName = 'comment' | 'edit' | 'generate' | null;
|
|
61
|
-
type AIMode = 'chat' | 'insert';
|
|
62
|
-
//#endregion
|
|
63
|
-
//#region src/lib/utils/getEditorPrompt.d.ts
|
|
64
|
-
type EditorPrompt = ((params: EditorPromptParams) => string) | PromptConfig | string;
|
|
65
|
-
type EditorPromptParams = {
|
|
66
|
-
editor: SlateEditor;
|
|
67
|
-
isBlockSelecting: boolean;
|
|
68
|
-
isSelecting: boolean;
|
|
69
|
-
};
|
|
70
|
-
type PromptConfig = {
|
|
71
|
-
default: string;
|
|
72
|
-
blockSelecting?: string;
|
|
73
|
-
selecting?: string;
|
|
74
|
-
};
|
|
75
|
-
declare const getEditorPrompt: (editor: SlateEditor, {
|
|
76
|
-
prompt
|
|
77
|
-
}: {
|
|
78
|
-
prompt?: EditorPrompt;
|
|
79
|
-
}) => string;
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/lib/utils/replacePlaceholders.d.ts
|
|
82
|
-
type MarkdownType = 'block' | 'blockSelection' | 'blockSelectionWithBlockId' | 'blockWithBlockId' | 'editor' | 'editorWithBlockId' | 'tableCellWithId';
|
|
83
|
-
declare const replacePlaceholders: (editor: SlateEditor, text: string, {
|
|
84
|
-
prompt
|
|
85
|
-
}?: {
|
|
86
|
-
prompt?: string;
|
|
87
|
-
}) => string;
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/lib/utils/getMarkdown.d.ts
|
|
90
|
-
declare const getMarkdown: (editor: SlateEditor, {
|
|
91
|
-
type
|
|
92
|
-
}: {
|
|
93
|
-
type: MarkdownType;
|
|
94
|
-
}) => string;
|
|
95
|
-
//#endregion
|
|
96
|
-
export { insertAINodes as _, EditorPromptParams as a, AIMode as c, BaseAIPluginConfig as d, AIBatch as f, removeAIMarks as g, removeAINodes as h, EditorPrompt as i, AIToolName as l, undoAI as m, MarkdownType as n, PromptConfig as o, withAIBatch as p, replacePlaceholders as r, getEditorPrompt as s, getMarkdown as t, BaseAIPlugin as u };
|