@blocknote/xl-ai 0.42.3 → 0.43.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.
- package/dist/blocknote-xl-ai.cjs +34 -5
- package/dist/blocknote-xl-ai.cjs.map +1 -1
- package/dist/blocknote-xl-ai.js +25678 -1443
- package/dist/blocknote-xl-ai.js.map +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +5 -6
- package/src/AIExtension.ts +366 -409
- package/src/api/formats/json/tools/jsontools.test.ts +2 -2
- package/src/api/formats/tests/sharedTestCases.ts +2 -2
- package/src/components/AIMenu/AIMenu.tsx +17 -8
- package/src/components/AIMenu/AIMenuController.tsx +83 -29
- package/src/components/AIMenu/PromptSuggestionMenu.tsx +4 -2
- package/src/components/AIMenu/getDefaultAIMenuItems.tsx +17 -5
- package/src/components/FormattingToolbar/AIToolbarButton.tsx +8 -4
- package/src/components/SuggestionMenu/getAISlashMenuItems.tsx +5 -2
- package/src/index.ts +0 -1
- package/src/prosemirror/agent.test.ts +2 -2
- package/src/testUtil/cases/editors/blockFormatting.ts +2 -2
- package/src/testUtil/cases/editors/emptyEditor.ts +2 -2
- package/src/testUtil/cases/editors/formattingAndMentions.ts +2 -2
- package/src/testUtil/cases/editors/simpleEditor.ts +3 -3
- package/src/testUtil/cases/editors/tables.ts +2 -2
- package/src/testUtil/cases/updateOperationTestCases.ts +4 -4
- package/types/src/AIExtension.d.ts +34 -49
- package/types/src/components/AIMenu/AIMenuController.d.ts +2 -0
- package/types/src/index.d.ts +0 -1
- package/src/components/AIMenu/BlockPositioner.tsx +0 -86
- package/types/src/components/AIMenu/BlockPositioner.d.ts +0 -10
|
@@ -13,7 +13,7 @@ import { DeleteBlockToolCall } from "../../base-tools/delete.js";
|
|
|
13
13
|
import { tools } from "./index.js";
|
|
14
14
|
|
|
15
15
|
// Helper function to create a mock stream from operations
|
|
16
|
-
import {
|
|
16
|
+
import { AIExtension } from "../../../../AIExtension.js";
|
|
17
17
|
import { StreamToolExecutor } from "../../../../streamTool/StreamToolExecutor.js";
|
|
18
18
|
import { StreamTool } from "../../../../streamTool/streamTool.js";
|
|
19
19
|
import { getExpectedEditor } from "../../../../testUtil/cases/index.js";
|
|
@@ -64,7 +64,7 @@ async function executeTestCase(
|
|
|
64
64
|
|
|
65
65
|
validateRejectingResultsInOriginalDoc(editor, originalDoc);
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
editor.getExtension(AIExtension)?.acceptChanges();
|
|
68
68
|
expect(editor.document).toEqual(getExpectedEditor(testCase).document);
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -4,7 +4,7 @@ import { getCurrentTest, TaskContext } from "@vitest/runner";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { TextSelection } from "prosemirror-state";
|
|
6
6
|
import { describe, expect, it } from "vitest";
|
|
7
|
-
import {
|
|
7
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
8
8
|
import { aiDocumentFormats, defaultAIRequestSender } from "../../../index.js";
|
|
9
9
|
import { addOperationTestCases } from "../../../testUtil/cases/addOperationTestCases.js";
|
|
10
10
|
import { combinedOperationsTestCases } from "../../../testUtil/cases/combinedOperationsTestCases.js";
|
|
@@ -118,7 +118,7 @@ export function generateSharedTestCases(
|
|
|
118
118
|
validateRejectingResultsInOriginalDoc(editor, originalDoc);
|
|
119
119
|
|
|
120
120
|
// we first need to accept changes to get the correct result
|
|
121
|
-
|
|
121
|
+
editor.getExtension(AIExtension)?.acceptChanges();
|
|
122
122
|
expect(editor.document).toEqual(
|
|
123
123
|
getExpectedEditor(test, {
|
|
124
124
|
deleteEmptyCursorBlock: true,
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useBlockNoteEditor,
|
|
4
|
+
useComponentsContext,
|
|
5
|
+
useExtension,
|
|
6
|
+
useExtensionState,
|
|
7
|
+
} from "@blocknote/react";
|
|
3
8
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
9
|
import { RiSparkling2Fill } from "react-icons/ri";
|
|
5
|
-
import { useStore } from "zustand";
|
|
6
10
|
|
|
7
|
-
import {
|
|
11
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
8
12
|
import { useAIDictionary } from "../../i18n/useAIDictionary.js";
|
|
9
13
|
import { PromptSuggestionMenu } from "./PromptSuggestionMenu.js";
|
|
10
14
|
import {
|
|
@@ -33,11 +37,12 @@ export const AIMenu = (props: AIMenuProps) => {
|
|
|
33
37
|
|
|
34
38
|
const Components = useComponentsContext()!;
|
|
35
39
|
|
|
36
|
-
const ai =
|
|
40
|
+
const ai = useExtension(AIExtension);
|
|
37
41
|
|
|
38
|
-
const aiResponseStatus =
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
const aiResponseStatus = useExtensionState(AIExtension, {
|
|
43
|
+
selector: (state) =>
|
|
44
|
+
state.aiMenuState !== "closed" ? state.aiMenuState.status : "closed",
|
|
45
|
+
});
|
|
41
46
|
|
|
42
47
|
const { items: externalItems } = props;
|
|
43
48
|
// note, technically there might be a bug with this useMemo when quickly changing the selection and opening the menu
|
|
@@ -74,7 +79,11 @@ export const AIMenu = (props: AIMenuProps) => {
|
|
|
74
79
|
|
|
75
80
|
useEffect(() => {
|
|
76
81
|
// this is a bit hacky to run a useeffect to reset the prompt when the AI response is done
|
|
77
|
-
if (
|
|
82
|
+
if (
|
|
83
|
+
aiResponseStatus === "ai-writing" ||
|
|
84
|
+
aiResponseStatus === "user-reviewing" ||
|
|
85
|
+
aiResponseStatus === "error"
|
|
86
|
+
) {
|
|
78
87
|
setPrompt("");
|
|
79
88
|
}
|
|
80
89
|
}, [aiResponseStatus]);
|
|
@@ -1,42 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
BlockPopover,
|
|
3
|
+
FloatingUIOptions,
|
|
4
|
+
useBlockNoteEditor,
|
|
5
|
+
useExtension,
|
|
6
|
+
useExtensionState,
|
|
7
|
+
} from "@blocknote/react";
|
|
8
|
+
import { offset, size } from "@floating-ui/react";
|
|
9
|
+
import { FC, useMemo } from "react";
|
|
4
10
|
|
|
5
|
-
import {
|
|
11
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
6
12
|
import { AIMenu, AIMenuProps } from "./AIMenu.js";
|
|
7
|
-
import { BlockPositioner } from "./BlockPositioner.js";
|
|
8
13
|
|
|
9
|
-
export const AIMenuController = (props: {
|
|
14
|
+
export const AIMenuController = (props: {
|
|
15
|
+
aiMenu?: FC<AIMenuProps>;
|
|
16
|
+
floatingUIOptions?: FloatingUIOptions;
|
|
17
|
+
}) => {
|
|
10
18
|
const editor = useBlockNoteEditor();
|
|
11
|
-
const ai =
|
|
19
|
+
const ai = useExtension(AIExtension);
|
|
12
20
|
|
|
13
|
-
const aiMenuState =
|
|
21
|
+
const aiMenuState = useExtensionState(AIExtension, {
|
|
22
|
+
editor,
|
|
23
|
+
selector: (state) => state.aiMenuState,
|
|
24
|
+
});
|
|
14
25
|
|
|
15
26
|
const blockId = aiMenuState === "closed" ? undefined : aiMenuState.blockId;
|
|
16
27
|
|
|
28
|
+
const floatingUIOptions = useMemo<FloatingUIOptions>(
|
|
29
|
+
() => ({
|
|
30
|
+
useFloatingOptions: {
|
|
31
|
+
open: aiMenuState !== "closed",
|
|
32
|
+
placement: "bottom",
|
|
33
|
+
middleware: [
|
|
34
|
+
offset(10),
|
|
35
|
+
// flip(),
|
|
36
|
+
size({
|
|
37
|
+
apply({ rects, elements }) {
|
|
38
|
+
Object.assign(elements.floating.style, {
|
|
39
|
+
width: `${rects.reference.width}px`,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
onOpenChange: (open) => {
|
|
45
|
+
if (open || aiMenuState === "closed") {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (aiMenuState.status === "user-input") {
|
|
50
|
+
ai.closeAIMenu();
|
|
51
|
+
} else if (
|
|
52
|
+
aiMenuState.status === "user-reviewing" ||
|
|
53
|
+
aiMenuState.status === "error"
|
|
54
|
+
) {
|
|
55
|
+
ai.rejectChanges();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
useDismissProps: {
|
|
60
|
+
enabled:
|
|
61
|
+
aiMenuState === "closed" || aiMenuState.status === "user-input",
|
|
62
|
+
// We should just be able to set `referencePress: true` instead of
|
|
63
|
+
// using this listener, but this doesn't seem to trigger.
|
|
64
|
+
// (probably because we don't assign the referenceProps to the reference element)
|
|
65
|
+
outsidePress: (event) => {
|
|
66
|
+
if (event.target instanceof Element) {
|
|
67
|
+
const blockElement = event.target.closest(".bn-block");
|
|
68
|
+
if (
|
|
69
|
+
blockElement &&
|
|
70
|
+
blockElement.getAttribute("data-id") === blockId
|
|
71
|
+
) {
|
|
72
|
+
ai.closeAIMenu();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return true;
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
elementProps: {
|
|
80
|
+
style: {
|
|
81
|
+
zIndex: 100,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
...props.floatingUIOptions,
|
|
85
|
+
}),
|
|
86
|
+
[ai, aiMenuState, blockId, props.floatingUIOptions],
|
|
87
|
+
);
|
|
88
|
+
|
|
17
89
|
const Component = props.aiMenu || AIMenu;
|
|
18
90
|
|
|
19
91
|
return (
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
blockID={blockId}
|
|
25
|
-
onOpenChange={(open) => {
|
|
26
|
-
if (open || aiMenuState === "closed") {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (aiMenuState.status === "user-input") {
|
|
30
|
-
ai.closeAIMenu();
|
|
31
|
-
} else if (
|
|
32
|
-
aiMenuState.status === "user-reviewing" ||
|
|
33
|
-
aiMenuState.status === "error"
|
|
34
|
-
) {
|
|
35
|
-
ai.rejectChanges();
|
|
36
|
-
}
|
|
37
|
-
}}
|
|
38
|
-
>
|
|
39
|
-
<Component />
|
|
40
|
-
</BlockPositioner>
|
|
92
|
+
<BlockPopover blockId={blockId} {...floatingUIOptions}>
|
|
93
|
+
{aiMenuState !== "closed" && <Component />}
|
|
94
|
+
</BlockPopover>
|
|
41
95
|
);
|
|
42
96
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mergeCSSClasses } from "@blocknote/core";
|
|
2
|
+
import { filterSuggestionItems } from "@blocknote/core/extensions";
|
|
2
3
|
import {
|
|
3
4
|
DefaultReactSuggestionItem,
|
|
4
5
|
useComponentsContext,
|
|
@@ -111,7 +112,8 @@ export const PromptSuggestionMenu = (props: PromptSuggestionMenuProps) => {
|
|
|
111
112
|
</Components.Generic.Form.Root>
|
|
112
113
|
<Components.SuggestionMenu.Root
|
|
113
114
|
className={"bn-combobox-items"}
|
|
114
|
-
id={"ai-suggestion-menu"}
|
|
115
|
+
id={"ai-suggestion-menu"}
|
|
116
|
+
>
|
|
115
117
|
{items.map((item, i) => (
|
|
116
118
|
<Components.SuggestionMenu.Item
|
|
117
119
|
key={item.title}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
RiTextWrap,
|
|
19
19
|
} from "react-icons/ri";
|
|
20
20
|
|
|
21
|
-
import {
|
|
21
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
22
22
|
import { aiDocumentFormats } from "../../api/index.js";
|
|
23
23
|
import { getAIDictionary } from "../../i18n/dictionary.js";
|
|
24
24
|
|
|
@@ -40,7 +40,10 @@ function getDefaultAIMenuItemsWithoutSelection<
|
|
|
40
40
|
S extends StyleSchema,
|
|
41
41
|
>(editor: BlockNoteEditor<BSchema, I, S>): AIMenuSuggestionItem[] {
|
|
42
42
|
const dict = getAIDictionary(editor);
|
|
43
|
-
const ai =
|
|
43
|
+
const ai = editor.getExtension(AIExtension);
|
|
44
|
+
if (!ai) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
44
47
|
return [
|
|
45
48
|
{
|
|
46
49
|
key: "continue_writing",
|
|
@@ -128,7 +131,10 @@ function getDefaultAIMenuItemsWithSelection<
|
|
|
128
131
|
>(editor: BlockNoteEditor<BSchema, I, S>): AIMenuSuggestionItem[] {
|
|
129
132
|
const dict = getAIDictionary(editor);
|
|
130
133
|
|
|
131
|
-
const ai =
|
|
134
|
+
const ai = editor.getExtension(AIExtension);
|
|
135
|
+
if (!ai) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
132
138
|
|
|
133
139
|
return [
|
|
134
140
|
{
|
|
@@ -216,7 +222,10 @@ function getDefaultAIMenuItemsForReview<
|
|
|
216
222
|
S extends StyleSchema,
|
|
217
223
|
>(editor: BlockNoteEditor<BSchema, I, S>): AIMenuSuggestionItem[] {
|
|
218
224
|
const dict = getAIDictionary(editor);
|
|
219
|
-
const ai =
|
|
225
|
+
const ai = editor.getExtension(AIExtension);
|
|
226
|
+
if (!ai) {
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
220
229
|
|
|
221
230
|
return [
|
|
222
231
|
{
|
|
@@ -251,7 +260,10 @@ function getDefaultAIMenuItemsForError<
|
|
|
251
260
|
S extends StyleSchema,
|
|
252
261
|
>(editor: BlockNoteEditor<BSchema, I, S>): AIMenuSuggestionItem[] {
|
|
253
262
|
const dict = getAIDictionary(editor);
|
|
254
|
-
const ai =
|
|
263
|
+
const ai = editor.getExtension(AIExtension);
|
|
264
|
+
if (!ai) {
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
255
267
|
|
|
256
268
|
return [
|
|
257
269
|
{
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { BlockSchema, InlineContentSchema, StyleSchema } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { FormattingToolbarExtension } from "@blocknote/core/extensions";
|
|
3
|
+
import { useComponentsContext, useExtension } from "@blocknote/react";
|
|
3
4
|
import { RiSparkling2Fill } from "react-icons/ri";
|
|
4
5
|
|
|
5
6
|
import { useBlockNoteEditor } from "@blocknote/react";
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
8
9
|
import { useAIDictionary } from "../../i18n/useAIDictionary.js";
|
|
9
10
|
|
|
10
11
|
export const AIToolbarButton = () => {
|
|
@@ -17,16 +18,19 @@ export const AIToolbarButton = () => {
|
|
|
17
18
|
StyleSchema
|
|
18
19
|
>();
|
|
19
20
|
|
|
20
|
-
const ai =
|
|
21
|
+
const ai = useExtension(AIExtension);
|
|
22
|
+
const formattingToolbar = useExtension(FormattingToolbarExtension);
|
|
21
23
|
|
|
22
24
|
const onClick = () => {
|
|
23
|
-
editor.formattingToolbar.closeMenu();
|
|
24
25
|
const selection = editor.getSelection();
|
|
25
26
|
if (!selection) {
|
|
26
27
|
throw new Error("No selection");
|
|
27
28
|
}
|
|
29
|
+
|
|
28
30
|
const position = selection.blocks[selection.blocks.length - 1].id;
|
|
31
|
+
|
|
29
32
|
ai.openAIMenuAtBlock(position);
|
|
33
|
+
formattingToolbar.store.setState(false);
|
|
30
34
|
};
|
|
31
35
|
|
|
32
36
|
if (!editor.isEditable) {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { DefaultReactSuggestionItem } from "@blocknote/react";
|
|
8
8
|
import { RiSparkling2Fill } from "react-icons/ri";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
11
11
|
import { getAIDictionary } from "../../i18n/dictionary.js";
|
|
12
12
|
const Icons = {
|
|
13
13
|
AI: RiSparkling2Fill,
|
|
@@ -21,7 +21,10 @@ export function getAISlashMenuItems<
|
|
|
21
21
|
I extends InlineContentSchema,
|
|
22
22
|
S extends StyleSchema,
|
|
23
23
|
>(editor: BlockNoteEditor<BSchema, I, S>): DefaultReactSuggestionItem[] {
|
|
24
|
-
const ai =
|
|
24
|
+
const ai = editor.getExtension(AIExtension);
|
|
25
|
+
if (!ai) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
25
28
|
const items = [
|
|
26
29
|
{
|
|
27
30
|
key: "ai",
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,6 @@ export * from "./api/index.js";
|
|
|
5
5
|
export * from "./blocknoteAIClient/client.js";
|
|
6
6
|
export * from "./components/AIMenu/AIMenu.js";
|
|
7
7
|
export * from "./components/AIMenu/AIMenuController.js";
|
|
8
|
-
export * from "./components/AIMenu/BlockPositioner.js";
|
|
9
8
|
export * from "./components/AIMenu/getDefaultAIMenuItems.js";
|
|
10
9
|
export * from "./components/AIMenu/PromptSuggestionMenu.js";
|
|
11
10
|
export * from "./components/FormattingToolbar/AIToolbarButton.js";
|
|
@@ -2,7 +2,7 @@ import { BlockNoteEditor, getBlockInfo, getNodeById } from "@blocknote/core";
|
|
|
2
2
|
import { Fragment, Slice } from "prosemirror-model";
|
|
3
3
|
import { ReplaceStep, Transform } from "prosemirror-transform";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
-
import {
|
|
5
|
+
import { AIExtension } from "../AIExtension.js";
|
|
6
6
|
import {
|
|
7
7
|
DocumentOperationTestCase,
|
|
8
8
|
getExpectedEditor,
|
|
@@ -247,7 +247,7 @@ async function executeTestCase(
|
|
|
247
247
|
validateRejectingResultsInOriginalDoc(editor, doc);
|
|
248
248
|
expect(results).toMatchSnapshot();
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
editor.getExtension(AIExtension)?.acceptChanges();
|
|
251
251
|
expect(editor.document).toEqual(getExpectedEditor(test).document);
|
|
252
252
|
|
|
253
253
|
return results;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
3
3
|
import { schemaWithMention as schema } from "../schemas/mention.js";
|
|
4
4
|
|
|
5
5
|
export function getEditorWithBlockFormatting() {
|
|
@@ -22,7 +22,7 @@ export function getEditorWithBlockFormatting() {
|
|
|
22
22
|
],
|
|
23
23
|
trailingBlock: false,
|
|
24
24
|
schema,
|
|
25
|
-
extensions: [
|
|
25
|
+
extensions: [AIExtension()],
|
|
26
26
|
});
|
|
27
27
|
return editor;
|
|
28
28
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
3
3
|
|
|
4
4
|
export function getEmptyEditor() {
|
|
5
5
|
const editor = BlockNoteEditor.create({
|
|
@@ -10,7 +10,7 @@ export function getEmptyEditor() {
|
|
|
10
10
|
},
|
|
11
11
|
],
|
|
12
12
|
trailingBlock: false,
|
|
13
|
-
extensions: [
|
|
13
|
+
extensions: [AIExtension()],
|
|
14
14
|
});
|
|
15
15
|
return editor;
|
|
16
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
3
3
|
import { schemaWithMention as schema } from "../schemas/mention.js";
|
|
4
4
|
|
|
5
5
|
export function getEditorWithFormattingAndMentions() {
|
|
@@ -72,7 +72,7 @@ export function getEditorWithFormattingAndMentions() {
|
|
|
72
72
|
],
|
|
73
73
|
trailingBlock: false,
|
|
74
74
|
schema,
|
|
75
|
-
extensions: [
|
|
75
|
+
extensions: [AIExtension()],
|
|
76
76
|
});
|
|
77
77
|
return editor;
|
|
78
78
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
3
3
|
import { schemaWithMention as schema } from "../schemas/mention.js";
|
|
4
4
|
|
|
5
5
|
export function getSimpleEditor() {
|
|
@@ -16,7 +16,7 @@ export function getSimpleEditor() {
|
|
|
16
16
|
],
|
|
17
17
|
trailingBlock: false,
|
|
18
18
|
schema,
|
|
19
|
-
extensions: [
|
|
19
|
+
extensions: [AIExtension()],
|
|
20
20
|
});
|
|
21
21
|
return editor;
|
|
22
22
|
}
|
|
@@ -39,7 +39,7 @@ export function getSimpleEditorWithCursorBetweenBlocks() {
|
|
|
39
39
|
],
|
|
40
40
|
trailingBlock: false,
|
|
41
41
|
schema,
|
|
42
|
-
extensions: [
|
|
42
|
+
extensions: [AIExtension()],
|
|
43
43
|
});
|
|
44
44
|
editor.setTextCursorPosition("ref2");
|
|
45
45
|
return editor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../../AIExtension.js";
|
|
3
3
|
import { schemaWithMention as schema } from "../schemas/mention.js";
|
|
4
4
|
|
|
5
5
|
export function getEditorWithTables() {
|
|
@@ -38,7 +38,7 @@ export function getEditorWithTables() {
|
|
|
38
38
|
],
|
|
39
39
|
schema,
|
|
40
40
|
trailingBlock: false,
|
|
41
|
-
extensions: [
|
|
41
|
+
extensions: [AIExtension()],
|
|
42
42
|
});
|
|
43
43
|
return editor;
|
|
44
44
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockNoteEditor, getBlockInfo, getNodeById } from "@blocknote/core";
|
|
2
|
-
import {
|
|
2
|
+
import { AIExtension } from "../../AIExtension.js";
|
|
3
3
|
import { getEditorWithBlockFormatting } from "./editors/blockFormatting.js";
|
|
4
4
|
import { getEditorWithFormattingAndMentions } from "./editors/formattingAndMentions.js";
|
|
5
5
|
import { DocumentOperationTestCase } from "./index.js";
|
|
@@ -683,7 +683,7 @@ export const updateOperationTestCases: DocumentOperationTestCase[] = [
|
|
|
683
683
|
},
|
|
684
684
|
],
|
|
685
685
|
schema,
|
|
686
|
-
extensions: [
|
|
686
|
+
extensions: [AIExtension()],
|
|
687
687
|
});
|
|
688
688
|
return editor;
|
|
689
689
|
},
|
|
@@ -736,7 +736,7 @@ export const updateOperationTestCases: DocumentOperationTestCase[] = [
|
|
|
736
736
|
},
|
|
737
737
|
],
|
|
738
738
|
schema,
|
|
739
|
-
extensions: [
|
|
739
|
+
extensions: [AIExtension()],
|
|
740
740
|
});
|
|
741
741
|
return editor;
|
|
742
742
|
},
|
|
@@ -771,7 +771,7 @@ export const updateOperationTestCases: DocumentOperationTestCase[] = [
|
|
|
771
771
|
},
|
|
772
772
|
],
|
|
773
773
|
schema,
|
|
774
|
-
extensions: [
|
|
774
|
+
extensions: [AIExtension()],
|
|
775
775
|
});
|
|
776
776
|
return editor;
|
|
777
777
|
},
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createStore, StoreApi } from "zustand/vanilla";
|
|
1
|
+
import { Plugin } from "prosemirror-state";
|
|
3
2
|
import { AIRequestHelpers, InvokeAIOptions } from "./types.js";
|
|
4
|
-
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
|
|
5
3
|
type AIPluginState = {
|
|
6
4
|
aiMenuState: ({
|
|
7
5
|
/**
|
|
@@ -16,58 +14,53 @@ type AIPluginState = {
|
|
|
16
14
|
status: "user-input" | "thinking" | "ai-writing" | "user-reviewing";
|
|
17
15
|
})) | "closed";
|
|
18
16
|
};
|
|
19
|
-
export declare
|
|
20
|
-
readonly editor: BlockNoteEditor<any, any, any>;
|
|
21
|
-
private chatSession;
|
|
22
|
-
private scrollInProgress;
|
|
23
|
-
private autoScroll;
|
|
24
|
-
static key(): string;
|
|
25
|
-
private readonly _store;
|
|
17
|
+
export declare const AIExtension: (options?: (AIRequestHelpers & {
|
|
26
18
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Returns a zustand store with the global configuration of the AI Extension.
|
|
32
|
-
* These options are used by default across all LLM calls when calling {@link executeLLMRequest}
|
|
33
|
-
*/
|
|
34
|
-
readonly options: ReturnType<ReturnType<typeof createStore<AIRequestHelpers>>>;
|
|
35
|
-
/**
|
|
36
|
-
* @internal use `createAIExtension` instead
|
|
19
|
+
* The name and color of the agent cursor
|
|
20
|
+
*
|
|
21
|
+
* @default { name: "AI", color: "#8bc6ff" }
|
|
37
22
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
23
|
+
agentCursor?: {
|
|
24
|
+
name: string;
|
|
25
|
+
color: string;
|
|
26
|
+
};
|
|
27
|
+
}) | undefined) => import("@blocknote/core").ExtensionFactoryInstance<{
|
|
28
|
+
readonly key: "ai";
|
|
29
|
+
readonly options: import("@tanstack/store").Store<AIRequestHelpers, (cb: AIRequestHelpers) => AIRequestHelpers>;
|
|
30
|
+
readonly store: import("@tanstack/store").Store<AIPluginState, (cb: AIPluginState) => AIPluginState>;
|
|
31
|
+
readonly mount: ({ signal }: {
|
|
32
|
+
signal: AbortSignal;
|
|
33
|
+
}) => void;
|
|
34
|
+
readonly prosemirrorPlugins: readonly [Plugin<any>, Plugin<{
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
}>, Plugin<{
|
|
37
|
+
selection: {
|
|
38
|
+
anchor: number;
|
|
39
|
+
head: number;
|
|
40
|
+
} | undefined;
|
|
41
|
+
}>];
|
|
49
42
|
/**
|
|
50
43
|
* Open the AI menu at a specific block
|
|
51
44
|
*/
|
|
52
|
-
openAIMenuAtBlock(blockID: string)
|
|
45
|
+
readonly openAIMenuAtBlock: (blockID: string) => void;
|
|
53
46
|
/**
|
|
54
47
|
* Close the AI menu
|
|
55
48
|
*/
|
|
56
|
-
closeAIMenu()
|
|
49
|
+
readonly closeAIMenu: () => void;
|
|
57
50
|
/**
|
|
58
51
|
* Accept the changes made by the LLM
|
|
59
52
|
*/
|
|
60
|
-
acceptChanges()
|
|
53
|
+
readonly acceptChanges: () => void;
|
|
61
54
|
/**
|
|
62
55
|
* Reject the changes made by the LLM
|
|
63
56
|
*/
|
|
64
|
-
rejectChanges()
|
|
57
|
+
readonly rejectChanges: () => void;
|
|
65
58
|
/**
|
|
66
59
|
* Retry the previous LLM call.
|
|
67
60
|
*
|
|
68
61
|
* Only valid if the current status is "error"
|
|
69
62
|
*/
|
|
70
|
-
retry()
|
|
63
|
+
readonly retry: () => Promise<void>;
|
|
71
64
|
/**
|
|
72
65
|
* Update the status of a call to an LLM
|
|
73
66
|
*
|
|
@@ -75,25 +68,17 @@ export declare class AIExtension extends BlockNoteExtension {
|
|
|
75
68
|
* if you want to implement how an LLM call is executed. Usually, you should
|
|
76
69
|
* use {@link executeLLMRequest} instead which will handle the status updates for you.
|
|
77
70
|
*/
|
|
78
|
-
setAIResponseStatus(status: "user-input" | "thinking" | "ai-writing" | "user-reviewing" | {
|
|
71
|
+
readonly setAIResponseStatus: (status: "user-input" | "thinking" | "ai-writing" | "user-reviewing" | {
|
|
79
72
|
status: "error";
|
|
80
73
|
error: any;
|
|
81
|
-
})
|
|
74
|
+
}) => void;
|
|
82
75
|
/**
|
|
83
76
|
* @deprecated Use {@link invokeAI} instead
|
|
84
77
|
*/
|
|
85
|
-
callLLM(opts: InvokeAIOptions)
|
|
78
|
+
readonly callLLM: (opts: InvokeAIOptions) => Promise<void>;
|
|
86
79
|
/**
|
|
87
80
|
* Execute a call to an LLM and apply the result to the editor
|
|
88
81
|
*/
|
|
89
|
-
invokeAI(opts: InvokeAIOptions)
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Create a new AIExtension instance, this can be passed to the BlockNote editor via the `extensions` option
|
|
93
|
-
*/
|
|
94
|
-
export declare function createAIExtension(options: ConstructorParameters<typeof AIExtension>[1]): (editor: BlockNoteEditor<any, any, any>) => AIExtension;
|
|
95
|
-
/**
|
|
96
|
-
* Return the AIExtension instance from the editor
|
|
97
|
-
*/
|
|
98
|
-
export declare function getAIExtension(editor: BlockNoteEditor<any, any, any>): AIExtension;
|
|
82
|
+
readonly invokeAI: (opts: InvokeAIOptions) => Promise<void>;
|
|
83
|
+
}>;
|
|
99
84
|
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { FloatingUIOptions } from "@blocknote/react";
|
|
1
2
|
import { FC } from "react";
|
|
2
3
|
import { AIMenuProps } from "./AIMenu.js";
|
|
3
4
|
export declare const AIMenuController: (props: {
|
|
4
5
|
aiMenu?: FC<AIMenuProps>;
|
|
6
|
+
floatingUIOptions?: FloatingUIOptions;
|
|
5
7
|
}) => import("react/jsx-runtime").JSX.Element;
|
package/types/src/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export * from "./api/index.js";
|
|
|
4
4
|
export * from "./blocknoteAIClient/client.js";
|
|
5
5
|
export * from "./components/AIMenu/AIMenu.js";
|
|
6
6
|
export * from "./components/AIMenu/AIMenuController.js";
|
|
7
|
-
export * from "./components/AIMenu/BlockPositioner.js";
|
|
8
7
|
export * from "./components/AIMenu/getDefaultAIMenuItems.js";
|
|
9
8
|
export * from "./components/AIMenu/PromptSuggestionMenu.js";
|
|
10
9
|
export * from "./components/FormattingToolbar/AIToolbarButton.js";
|