@blocknote/xl-ai 0.46.2 → 0.47.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 +1 -1
- package/dist/blocknote-xl-ai.cjs.map +1 -1
- package/dist/blocknote-xl-ai.js +274 -264
- package/dist/blocknote-xl-ai.js.map +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +4 -4
- package/src/components/AIMenu/AIMenuController.tsx +66 -59
- package/src/components/AIMenu/PromptSuggestionMenu.tsx +25 -4
package/dist/webpack-stats.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"builtAt":
|
|
1
|
+
{"builtAt":1771832557664,"assets":[{"name":"server.cjs","size":1169},{"name":"blocknote-xl-ai.cjs","size":26166},{"name":"locales.cjs","size":23791},{"name":"client-BPNTLm1-.cjs","size":38123},{"name":"client-BPNTLm1-.cjs.map","size":193335},{"name":"server.cjs.map","size":91},{"name":"locales.cjs.map","size":55283},{"name":"blocknote-xl-ai.cjs.map","size":2218279}],"chunks":[{"id":"91fd206","entry":true,"initial":true,"files":["server.cjs"],"names":["server"]},{"id":"a1ee98a","entry":true,"initial":true,"files":["blocknote-xl-ai.cjs"],"names":["blocknote-xl-ai"]},{"id":"842df4c","entry":true,"initial":true,"files":["locales.cjs"],"names":["locales"]},{"id":"8392e5f","entry":false,"initial":true,"files":["client-BPNTLm1-.cjs"],"names":["client"]}],"modules":[{"name":"./src/server.ts","size":0,"chunks":["91fd206"]},{"name":"./src/style.css","size":0,"chunks":["a1ee98a"]},{"name":"./src/plugins/AgentCursorPlugin.ts","size":2444,"chunks":["a1ee98a"]},{"name":"./src/AIExtension.ts","size":11092,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@19.2.3/node_modules/react-icons/lib/iconContext.mjs","size":251,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@19.2.3/node_modules/react-icons/lib/iconBase.mjs","size":4003,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@19.2.3/node_modules/react-icons/ri/index.mjs","size":6747,"chunks":["a1ee98a"]},{"name":"./src/hooks/useAIDictionary.ts","size":120,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/PromptSuggestionMenu.tsx","size":3485,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/getDefaultAIMenuItems.tsx","size":7846,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenu.tsx","size":3596,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenuController.tsx","size":2944,"chunks":["a1ee98a"]},{"name":"./src/components/FormattingToolbar/AIToolbarButton.tsx","size":960,"chunks":["a1ee98a"]},{"name":"./src/components/SuggestionMenu/getAISlashMenuItems.tsx","size":728,"chunks":["a1ee98a"]},{"name":"./src/index.ts","size":0,"chunks":["a1ee98a"]},{"name":"./src/i18n/locales/ar.ts","size":1531,"chunks":["842df4c"]},{"name":"./src/i18n/locales/de.ts","size":1585,"chunks":["842df4c"]},{"name":"./src/i18n/locales/en.ts","size":1483,"chunks":["842df4c"]},{"name":"./src/i18n/locales/es.ts","size":1553,"chunks":["842df4c"]},{"name":"./src/i18n/locales/fr.ts","size":1569,"chunks":["842df4c"]},{"name":"./src/i18n/locales/he.ts","size":1401,"chunks":["842df4c"]},{"name":"./src/i18n/locales/hr.ts","size":1494,"chunks":["842df4c"]},{"name":"./src/i18n/locales/is.ts","size":1562,"chunks":["842df4c"]},{"name":"./src/i18n/locales/it.ts","size":1555,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ja.ts","size":1372,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ko.ts","size":1394,"chunks":["842df4c"]},{"name":"./src/i18n/locales/nl.ts","size":1536,"chunks":["842df4c"]},{"name":"./src/i18n/locales/no.ts","size":1509,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pl.ts","size":1510,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pt.ts","size":1548,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ru.ts","size":1549,"chunks":["842df4c"]},{"name":"./src/i18n/locales/sk.ts","size":1511,"chunks":["842df4c"]},{"name":"./src/i18n/locales/uk.ts","size":1556,"chunks":["842df4c"]},{"name":"./src/i18n/locales/vi.ts","size":1506,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh-tw.ts","size":1345,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh.ts","size":1340,"chunks":["842df4c"]},{"name":"./src/i18n/locales/index.ts","size":0,"chunks":["842df4c"]},{"name":"./src/util/emptyBlock.ts","size":170,"chunks":["8392e5f"]},{"name":"./src/util/trimArray.ts","size":327,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/trimEmptyBlocks.ts","size":272,"chunks":["8392e5f"]},{"name":"./src/api/aiRequest/builder.ts","size":1347,"chunks":["8392e5f"]},{"name":"./src/streamTool/jsonSchema.ts","size":1630,"chunks":["8392e5f"]},{"name":"./src/streamTool/ChunkExecutionError.ts","size":237,"chunks":["8392e5f"]},{"name":"./src/streamTool/StreamToolExecutor.ts","size":4984,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/util/injectDocumentStateMessages.ts","size":2819,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/util/toolDefinitions.ts","size":750,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/clientside/ClientSideTransport.ts","size":1493,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/util/appendableStream.ts","size":1196,"chunks":["8392e5f"]},{"name":"./src/util/stream.ts","size":1069,"chunks":["8392e5f"]},{"name":"./src/streamTool/filterNewOrUpdatedOperations.ts","size":933,"chunks":["8392e5f"]},{"name":"./src/streamTool/filterValidOperations.ts","size":681,"chunks":["8392e5f"]},{"name":"./src/streamTool/toValidatedOperations.ts","size":1182,"chunks":["8392e5f"]},{"name":"./src/streamTool/preprocess.ts","size":594,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/util/UIMessageStreamToOperationsResult.ts","size":306,"chunks":["8392e5f"]},{"name":"./src/streamTool/vercelAiSdk/util/chatHandlers.ts","size":4645,"chunks":["8392e5f"]},{"name":"./src/api/aiRequest/sendMessageWithAIRequest.ts","size":819,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/addCursorPosition.ts","size":390,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/convertBlocks.ts","size":183,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/flattenBlocks.ts","size":162,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/suffixIds.ts","size":204,"chunks":["8392e5f"]},{"name":"./src/api/formats/DocumentStateBuilder.ts","size":1985,"chunks":["8392e5f"]},{"name":"./src/prosemirror/fragmentUtil.ts","size":262,"chunks":["8392e5f"]},{"name":"./src/prosemirror/agent.ts","size":6220,"chunks":["8392e5f"]},{"name":"./src/prosemirror/changeset.ts","size":6000,"chunks":["8392e5f"]},{"name":"./src/streamTool/streamTool.ts","size":48,"chunks":["8392e5f"]},{"name":"./src/util/AbortError.ts","size":131,"chunks":["8392e5f"]},{"name":"./src/api/formats/base-tools/util/validateBlockArray.ts","size":574,"chunks":["8392e5f"]},{"name":"./src/api/formats/base-tools/createAddBlocksTool.ts","size":5549,"chunks":["8392e5f"]},{"name":"./src/api/formats/base-tools/createUpdateBlockTool.ts","size":4418,"chunks":["8392e5f"]},{"name":"./src/api/formats/base-tools/delete.ts","size":1869,"chunks":["8392e5f"]},{"name":"./src/api/formats/html-blocks/tools/getPartialHTML.ts","size":699,"chunks":["8392e5f"]},{"name":"./src/prosemirror/rebaseTool.ts","size":1508,"chunks":["8392e5f"]},{"name":"./src/api/formats/html-blocks/tools/rebaseTool.ts","size":893,"chunks":["8392e5f"]},{"name":"./src/api/formats/html-blocks/tools/validate.ts","size":204,"chunks":["8392e5f"]},{"name":"./src/api/formats/html-blocks/tools/index.ts","size":1886,"chunks":["8392e5f"]},{"name":"./src/api/formats/html-blocks/htmlBlocks.ts","size":2890,"chunks":["8392e5f"]},{"name":"./src/api/schema/mergeSchema.ts","size":829,"chunks":["8392e5f"]},{"name":"./src/api/schema/schemaToJSONSchema.ts","size":4910,"chunks":["8392e5f"]},{"name":"./src/api/formats/json/tools/validate.ts","size":1603,"chunks":["8392e5f"]},{"name":"./src/api/formats/json/tools/index.ts","size":1324,"chunks":["8392e5f"]},{"name":"./src/api/formats/json/json.ts","size":2550,"chunks":["8392e5f"]},{"name":"./src/api/formats/markdown-blocks/tools/rebaseTool.ts","size":633,"chunks":["8392e5f"]},{"name":"./src/api/formats/markdown-blocks/tools/validate.ts","size":202,"chunks":["8392e5f"]},{"name":"./src/api/formats/markdown-blocks/tools/index.ts","size":1505,"chunks":["8392e5f"]},{"name":"./src/api/formats/markdown-blocks/markdownBlocks.ts","size":2563,"chunks":["8392e5f"]},{"name":"./src/api/formats/formats.ts","size":149,"chunks":["8392e5f"]},{"name":"./src/api/promptHelpers/index.ts","size":112,"chunks":["8392e5f"]},{"name":"./src/i18n/dictionary.ts","size":150,"chunks":["8392e5f"]},{"name":"./src/blocknoteAIClient/client.ts","size":533,"chunks":["8392e5f"]}]}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/xl-ai"
|
|
12
12
|
},
|
|
13
13
|
"license": "GPL-3.0 OR PROPRIETARY",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.47.0",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"types",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@ai-sdk/provider-utils": "^4.0.2",
|
|
65
65
|
"@ai-sdk/react": "^3.0.5",
|
|
66
|
-
"@blocknote/core": "0.
|
|
67
|
-
"@blocknote/mantine": "0.
|
|
68
|
-
"@blocknote/react": "0.
|
|
66
|
+
"@blocknote/core": "0.47.0",
|
|
67
|
+
"@blocknote/mantine": "0.47.0",
|
|
68
|
+
"@blocknote/react": "0.47.0",
|
|
69
69
|
"@floating-ui/react": "^0.26.28",
|
|
70
70
|
"@handlewithcare/prosemirror-suggest-changes": "^0.1.8",
|
|
71
71
|
"@tiptap/core": "^3.13.0",
|
|
@@ -26,71 +26,78 @@ export const AIMenuController = (props: {
|
|
|
26
26
|
const blockId = aiMenuState === "closed" ? undefined : aiMenuState.blockId;
|
|
27
27
|
|
|
28
28
|
const floatingUIOptions = useMemo<FloatingUIOptions>(
|
|
29
|
-
() =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
29
|
+
() =>
|
|
30
|
+
({
|
|
31
|
+
...props.floatingUIOptions,
|
|
32
|
+
useFloatingOptions: {
|
|
33
|
+
open: aiMenuState !== "closed",
|
|
34
|
+
placement: "bottom",
|
|
35
|
+
middleware: [
|
|
36
|
+
offset(10),
|
|
37
|
+
flip(),
|
|
38
|
+
size({
|
|
39
|
+
apply({ rects, elements }) {
|
|
40
|
+
Object.assign(elements.floating.style, {
|
|
41
|
+
width: `${rects.reference.width}px`,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
],
|
|
46
|
+
onOpenChange: (open) => {
|
|
47
|
+
if (open || aiMenuState === "closed") {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
ai.closeAIMenu();
|
|
52
|
-
} else if (
|
|
53
|
-
aiMenuState.status === "user-reviewing" ||
|
|
54
|
-
aiMenuState.status === "error"
|
|
55
|
-
) {
|
|
56
|
-
ai.rejectChanges();
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
whileElementsMounted(reference, floating, update) {
|
|
60
|
-
return autoUpdate(reference, floating, update, {
|
|
61
|
-
animationFrame: true,
|
|
62
|
-
});
|
|
63
|
-
},
|
|
64
|
-
...props.floatingUIOptions?.useFloatingOptions,
|
|
65
|
-
},
|
|
66
|
-
useDismissProps: {
|
|
67
|
-
enabled:
|
|
68
|
-
aiMenuState === "closed" || aiMenuState.status === "user-input",
|
|
69
|
-
// We should just be able to set `referencePress: true` instead of
|
|
70
|
-
// using this listener, but this doesn't seem to trigger.
|
|
71
|
-
// (probably because we don't assign the referenceProps to the reference element)
|
|
72
|
-
outsidePress: (event) => {
|
|
73
|
-
if (event.target instanceof Element) {
|
|
74
|
-
const blockElement = event.target.closest(".bn-block");
|
|
75
|
-
if (
|
|
76
|
-
blockElement &&
|
|
77
|
-
blockElement.getAttribute("data-id") === blockId
|
|
78
|
-
) {
|
|
51
|
+
if (aiMenuState.status === "user-input") {
|
|
79
52
|
ai.closeAIMenu();
|
|
53
|
+
} else if (
|
|
54
|
+
aiMenuState.status === "user-reviewing" ||
|
|
55
|
+
aiMenuState.status === "error"
|
|
56
|
+
) {
|
|
57
|
+
ai.rejectChanges();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
whileElementsMounted(reference, floating, update) {
|
|
61
|
+
return autoUpdate(reference, floating, update, {
|
|
62
|
+
animationFrame: true,
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
...props.floatingUIOptions?.useFloatingOptions,
|
|
66
|
+
},
|
|
67
|
+
useDismissProps: {
|
|
68
|
+
enabled:
|
|
69
|
+
aiMenuState === "closed" || aiMenuState.status === "user-input",
|
|
70
|
+
// We should just be able to set `referencePress: true` instead of
|
|
71
|
+
// using this listener, but this doesn't seem to trigger.
|
|
72
|
+
// (probably because we don't assign the referenceProps to the reference element)
|
|
73
|
+
outsidePress: (event) => {
|
|
74
|
+
if (event.target instanceof Element) {
|
|
75
|
+
const blockElement = event.target.closest(".bn-block");
|
|
76
|
+
if (
|
|
77
|
+
blockElement &&
|
|
78
|
+
blockElement.getAttribute("data-id") === blockId
|
|
79
|
+
) {
|
|
80
|
+
ai.closeAIMenu();
|
|
81
|
+
}
|
|
80
82
|
}
|
|
81
|
-
}
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
return true;
|
|
85
|
+
},
|
|
86
|
+
...props.floatingUIOptions?.useDismissProps,
|
|
87
|
+
},
|
|
88
|
+
elementProps: {
|
|
89
|
+
style: {
|
|
90
|
+
zIndex: 100,
|
|
91
|
+
},
|
|
92
|
+
...props.floatingUIOptions?.elementProps,
|
|
84
93
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
// we use the focus manager instead of `autoFocus={true}` to prevent "page-scrolls-to-top-when-opening-the-floating-element"
|
|
95
|
+
// see https://floating-ui.com/docs/floatingfocusmanager#page-scrolls-to-top-when-opening-the-floating-element
|
|
96
|
+
focusManagerProps: {
|
|
97
|
+
disabled: false,
|
|
98
|
+
...props.floatingUIOptions?.focusManagerProps,
|
|
90
99
|
},
|
|
91
|
-
|
|
92
|
-
},
|
|
93
|
-
}),
|
|
100
|
+
}) satisfies FloatingUIOptions,
|
|
94
101
|
[ai, aiMenuState, blockId, props.floatingUIOptions],
|
|
95
102
|
);
|
|
96
103
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
useCallback,
|
|
13
13
|
useEffect,
|
|
14
14
|
useMemo,
|
|
15
|
+
useRef,
|
|
15
16
|
useState,
|
|
16
17
|
} from "react";
|
|
17
18
|
|
|
@@ -30,7 +31,8 @@ export const PromptSuggestionMenu = (props: PromptSuggestionMenuProps) => {
|
|
|
30
31
|
// const dict = useAIDictionary();
|
|
31
32
|
const Components = useComponentsContext()!;
|
|
32
33
|
|
|
33
|
-
const { onManualPromptSubmit, promptText, onPromptTextChange } =
|
|
34
|
+
const { onManualPromptSubmit, promptText, onPromptTextChange, disabled } =
|
|
35
|
+
props;
|
|
34
36
|
|
|
35
37
|
// Only used internal state when `props.prompText` is undefined (i.e., uncontrolled mode)
|
|
36
38
|
const [internalPromptText, setInternalPromptText] = useState<string>("");
|
|
@@ -68,6 +70,11 @@ export const PromptSuggestionMenu = (props: PromptSuggestionMenuProps) => {
|
|
|
68
70
|
const { selectedIndex, setSelectedIndex, handler } =
|
|
69
71
|
useSuggestionMenuKeyboardHandler(items, (item) => item.onItemClick());
|
|
70
72
|
|
|
73
|
+
const activeDescendantId =
|
|
74
|
+
items.length > 0 && selectedIndex >= 0 && selectedIndex < items.length
|
|
75
|
+
? `bn-suggestion-menu-item-${selectedIndex}`
|
|
76
|
+
: undefined;
|
|
77
|
+
|
|
71
78
|
const handleKeyDown = useCallback(
|
|
72
79
|
(event: KeyboardEvent) => {
|
|
73
80
|
// TODO: handle backspace to close
|
|
@@ -90,24 +97,38 @@ export const PromptSuggestionMenu = (props: PromptSuggestionMenuProps) => {
|
|
|
90
97
|
setSelectedIndex(0);
|
|
91
98
|
}, [promptTextToUse, setSelectedIndex]);
|
|
92
99
|
|
|
100
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
101
|
+
const hasBeenDisabled = useRef(disabled);
|
|
102
|
+
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
// This effect is used so that after the input has been disabled (for example, when AI results are loaded),
|
|
105
|
+
// the input is focused again.
|
|
106
|
+
if (inputRef.current && hasBeenDisabled.current && !disabled) {
|
|
107
|
+
inputRef.current.focus();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (disabled) {
|
|
111
|
+
hasBeenDisabled.current = true;
|
|
112
|
+
}
|
|
113
|
+
}, [disabled]);
|
|
114
|
+
|
|
93
115
|
return (
|
|
94
116
|
<div className={"bn-combobox"}>
|
|
95
117
|
<Components.Generic.Form.Root>
|
|
96
118
|
<Components.Generic.Form.TextInput
|
|
97
|
-
|
|
98
|
-
key={"input-" + props.disabled}
|
|
119
|
+
ref={inputRef}
|
|
99
120
|
className={"bn-combobox-input"}
|
|
100
121
|
name={"ai-prompt"}
|
|
101
122
|
variant={"large"}
|
|
102
123
|
icon={props.icon}
|
|
103
124
|
value={promptTextToUse || ""}
|
|
104
|
-
autoFocus={true}
|
|
105
125
|
placeholder={props.placeholder}
|
|
106
126
|
disabled={props.disabled}
|
|
107
127
|
onKeyDown={handleKeyDown}
|
|
108
128
|
onChange={handleChange}
|
|
109
129
|
autoComplete={"off"}
|
|
110
130
|
rightSection={props.rightSection}
|
|
131
|
+
aria-activedescendant={activeDescendantId}
|
|
111
132
|
/>
|
|
112
133
|
</Components.Generic.Form.Root>
|
|
113
134
|
{items.length > 0 && (
|