@aws-amplify/ui-react-ai 0.2.0 → 0.3.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/esm/components/AIConversation/AIConversation.mjs +2 -1
- package/dist/esm/components/AIConversation/context/AttachmentContext.mjs +8 -0
- package/dist/esm/components/AIConversation/createAIConversation.mjs +2 -1
- package/dist/esm/components/AIConversation/createProvider.mjs +11 -9
- package/dist/esm/components/AIConversation/views/Controls/AttachFileControl.mjs +13 -1
- package/dist/esm/components/AIConversation/views/Controls/FieldControl.mjs +4 -2
- package/dist/esm/components/AIConversation/views/default/Form.mjs +22 -10
- package/dist/index.js +236 -207
- package/dist/types/components/AIConversation/AIConversation.d.ts +2 -1
- package/dist/types/components/AIConversation/context/AttachmentContext.d.ts +6 -0
- package/dist/types/components/AIConversation/context/ControlsContext.d.ts +1 -0
- package/dist/types/components/AIConversation/createProvider.d.ts +1 -1
- package/dist/types/components/AIConversation/types.d.ts +1 -0
- package/package.json +7 -7
|
@@ -14,7 +14,7 @@ import { PromptList } from './views/default/PromptList.mjs';
|
|
|
14
14
|
import { ComponentClassName } from '@aws-amplify/ui';
|
|
15
15
|
import createProvider from './createProvider.mjs';
|
|
16
16
|
|
|
17
|
-
function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }) {
|
|
17
|
+
function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, allowAttachments, }) {
|
|
18
18
|
const icons = useIcons('aiConversation');
|
|
19
19
|
const defaultAvatars = {
|
|
20
20
|
ai: {
|
|
@@ -52,6 +52,7 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
|
|
|
52
52
|
...avatars,
|
|
53
53
|
},
|
|
54
54
|
isLoading,
|
|
55
|
+
allowAttachments,
|
|
55
56
|
};
|
|
56
57
|
return (React.createElement(Provider, { ...providerProps },
|
|
57
58
|
React.createElement(Flex, { className: ComponentClassName.AIConversation },
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
const AttachmentContext = React.createContext(false);
|
|
4
|
+
const AttachmentProvider = ({ children, allowAttachments, }) => {
|
|
5
|
+
return (React.createElement(AttachmentContext.Provider, { value: allowAttachments ?? false }, children));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export { AttachmentContext, AttachmentProvider };
|
|
@@ -12,7 +12,7 @@ import createProvider from './createProvider.mjs';
|
|
|
12
12
|
* @experimental
|
|
13
13
|
*/
|
|
14
14
|
function createAIConversation(input = {}) {
|
|
15
|
-
const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, } = input;
|
|
15
|
+
const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, allowAttachments, } = input;
|
|
16
16
|
const Provider = createProvider({
|
|
17
17
|
elements,
|
|
18
18
|
actions,
|
|
@@ -21,6 +21,7 @@ function createAIConversation(input = {}) {
|
|
|
21
21
|
variant,
|
|
22
22
|
controls,
|
|
23
23
|
displayText,
|
|
24
|
+
allowAttachments,
|
|
24
25
|
});
|
|
25
26
|
function AIConversation(props) {
|
|
26
27
|
const { messages, avatars, handleSendMessage, isLoading } = props;
|
|
@@ -13,8 +13,9 @@ import { LoadingContextProvider } from './context/LoadingContext.mjs';
|
|
|
13
13
|
import { ResponseComponentsProvider } from './context/ResponseComponentsContext.mjs';
|
|
14
14
|
import { SendMessageContextProvider } from './context/SendMessageContext.mjs';
|
|
15
15
|
import './context/elements/definitions.mjs';
|
|
16
|
+
import { AttachmentProvider } from './context/AttachmentContext.mjs';
|
|
16
17
|
|
|
17
|
-
function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }) {
|
|
18
|
+
function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }) {
|
|
18
19
|
return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
|
|
19
20
|
const _displayText = {
|
|
20
21
|
...defaultAIConversationDisplayTextEn,
|
|
@@ -24,14 +25,15 @@ function createProvider({ elements, actions, suggestedPrompts, responseComponent
|
|
|
24
25
|
React__default.createElement(ControlsProvider, { controls: controls },
|
|
25
26
|
React__default.createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
|
|
26
27
|
React__default.createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
|
|
27
|
-
React__default.createElement(
|
|
28
|
-
React__default.createElement(
|
|
29
|
-
React__default.createElement(
|
|
30
|
-
React__default.createElement(
|
|
31
|
-
React__default.createElement(
|
|
32
|
-
React__default.createElement(
|
|
33
|
-
React__default.createElement(
|
|
34
|
-
React__default.createElement(
|
|
28
|
+
React__default.createElement(AttachmentProvider, { allowAttachments: allowAttachments },
|
|
29
|
+
React__default.createElement(ConversationDisplayTextProvider, { ..._displayText },
|
|
30
|
+
React__default.createElement(ConversationInputContextProvider, null,
|
|
31
|
+
React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
|
|
32
|
+
React__default.createElement(AvatarsProvider, { avatars: avatars },
|
|
33
|
+
React__default.createElement(ActionsProvider, { actions: actions },
|
|
34
|
+
React__default.createElement(MessageVariantProvider, { variant: variant },
|
|
35
|
+
React__default.createElement(MessagesProvider, { messages: messages },
|
|
36
|
+
React__default.createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -12,6 +12,7 @@ import '../../context/LoadingContext.mjs';
|
|
|
12
12
|
import '../../context/ResponseComponentsContext.mjs';
|
|
13
13
|
import '../../context/SendMessageContext.mjs';
|
|
14
14
|
import { AIConversationElements } from '../../context/elements/definitions.mjs';
|
|
15
|
+
import { useDropZone } from '@aws-amplify/ui-react-core';
|
|
15
16
|
|
|
16
17
|
const { Button, Icon, View } = AIConversationElements;
|
|
17
18
|
const ATTACH_FILE_BLOCK = 'ai-attach-file';
|
|
@@ -35,6 +36,17 @@ const AttachFileButton = withBaseElementProps(Button, {
|
|
|
35
36
|
const AttachFileControl = () => {
|
|
36
37
|
const hiddenInput = React__default.useRef(null);
|
|
37
38
|
const { setInput } = React__default.useContext(ConversationInputContext);
|
|
39
|
+
const { dragState, ...dropHandlers } = useDropZone({
|
|
40
|
+
acceptedFileTypes: ['.jpeg'],
|
|
41
|
+
onDropComplete: ({ acceptedFiles }) => {
|
|
42
|
+
if (acceptedFiles && acceptedFiles?.length > 0 && setInput) {
|
|
43
|
+
setInput((prevInput) => ({
|
|
44
|
+
...prevInput,
|
|
45
|
+
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
});
|
|
38
50
|
function handleButtonClick() {
|
|
39
51
|
if (hiddenInput.current) {
|
|
40
52
|
hiddenInput.current.click();
|
|
@@ -52,7 +64,7 @@ const AttachFileControl = () => {
|
|
|
52
64
|
});
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
|
-
return (React__default.createElement(AttachFileContainer,
|
|
67
|
+
return (React__default.createElement(AttachFileContainer, { ...dropHandlers },
|
|
56
68
|
React__default.createElement(AttachFileButton, { onClick: handleButtonClick },
|
|
57
69
|
React__default.createElement(AttachFileIcon, null)),
|
|
58
70
|
React__default.createElement(VisuallyHidden, null,
|
|
@@ -15,6 +15,7 @@ import { AIConversationElements } from '../../context/elements/definitions.mjs';
|
|
|
15
15
|
import { AttachFileControl } from './AttachFileControl.mjs';
|
|
16
16
|
import { AttachmentListControl } from './AttachmentListControl.mjs';
|
|
17
17
|
import { getImageTypeFromMimeType } from '../../utils.mjs';
|
|
18
|
+
import { AttachmentContext } from '../../context/AttachmentContext.mjs';
|
|
18
19
|
|
|
19
20
|
const { Button, Icon, Label: LabelElement, TextArea, View, } = AIConversationElements;
|
|
20
21
|
const FIELD_BLOCK = 'ai-field';
|
|
@@ -99,6 +100,7 @@ const InputContainer = withBaseElementProps(View, {
|
|
|
99
100
|
const FieldControl = () => {
|
|
100
101
|
const { input, setInput } = React__default.useContext(ConversationInputContext);
|
|
101
102
|
const handleSendMessage = React__default.useContext(SendMessageContext);
|
|
103
|
+
const allowAttachments = React__default.useContext(AttachmentContext);
|
|
102
104
|
const ref = React__default.useRef(null);
|
|
103
105
|
const responseComponents = React__default.useContext(ResponseComponentsContext);
|
|
104
106
|
const controls = React__default.useContext(ControlsContext);
|
|
@@ -147,10 +149,10 @@ const FieldControl = () => {
|
|
|
147
149
|
}
|
|
148
150
|
};
|
|
149
151
|
if (controls?.Form) {
|
|
150
|
-
return (React__default.createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput }));
|
|
152
|
+
return (React__default.createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, allowAttachments: allowAttachments }));
|
|
151
153
|
}
|
|
152
154
|
return (React__default.createElement("form", { className: `${FIELD_BLOCK}__form`, onSubmit: handleSubmit, method: "post", ref: ref },
|
|
153
|
-
React__default.createElement(AttachFileControl, null),
|
|
155
|
+
allowAttachments ? React__default.createElement(AttachFileControl, null) : null,
|
|
154
156
|
React__default.createElement(InputContainer, null,
|
|
155
157
|
React__default.createElement(VisuallyHidden, null,
|
|
156
158
|
React__default.createElement(Label, null)),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { View, Button, VisuallyHidden, TextAreaField, DropZone } from '@aws-amplify/ui-react';
|
|
3
3
|
import { useIcons, IconSend, IconAttach } from '@aws-amplify/ui-react/internal';
|
|
4
4
|
import { ComponentClassName } from '@aws-amplify/ui';
|
|
5
5
|
import { Attachments } from './Attachments.mjs';
|
|
@@ -8,21 +8,33 @@ import { LoadingContext } from '../../context/LoadingContext.mjs';
|
|
|
8
8
|
function isHTMLFormElement(target) {
|
|
9
9
|
return 'form' in target;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Will conditionally render the DropZone if allowAttachments
|
|
13
|
+
* is true
|
|
14
|
+
*/
|
|
15
|
+
const FormWrapper = ({ children, allowAttachments, setInput, }) => {
|
|
16
|
+
if (allowAttachments) {
|
|
17
|
+
return (React.createElement(DropZone, { className: ComponentClassName.AIConversationFormDropzone, onDropComplete: ({ acceptedFiles }) => {
|
|
18
|
+
setInput?.((prevInput) => ({
|
|
19
|
+
...prevInput,
|
|
20
|
+
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
21
|
+
}));
|
|
22
|
+
} }, children));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return children;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const Form = ({ setInput, input, handleSubmit, allowAttachments, }) => {
|
|
12
29
|
const icons = useIcons('aiConversation');
|
|
13
30
|
const sendIcon = icons?.send ?? React.createElement(IconSend, null);
|
|
14
31
|
const attachIcon = icons?.attach ?? React.createElement(IconAttach, null);
|
|
15
32
|
const hiddenInput = React.useRef(null);
|
|
16
33
|
const isLoading = React.useContext(LoadingContext);
|
|
17
34
|
const isInputEmpty = !input?.text?.length && !input?.files?.length;
|
|
18
|
-
return (React.createElement(
|
|
19
|
-
setInput((prevInput) => ({
|
|
20
|
-
...prevInput,
|
|
21
|
-
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
22
|
-
}));
|
|
23
|
-
} },
|
|
35
|
+
return (React.createElement(FormWrapper, { allowAttachments: allowAttachments, setInput: setInput },
|
|
24
36
|
React.createElement(View, { as: "form", className: ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
|
|
25
|
-
React.createElement(Button, { className: ComponentClassName.AIConversationFormAttach, onClick: () => {
|
|
37
|
+
allowAttachments ? (React.createElement(Button, { className: ComponentClassName.AIConversationFormAttach, onClick: () => {
|
|
26
38
|
hiddenInput?.current?.click();
|
|
27
39
|
if (hiddenInput?.current) {
|
|
28
40
|
hiddenInput.current.value = '';
|
|
@@ -39,7 +51,7 @@ const Form = ({ setInput, input, handleSubmit, }) => {
|
|
|
39
51
|
...prevValue,
|
|
40
52
|
files: [...(prevValue?.files ?? []), ...Array.from(files)],
|
|
41
53
|
}));
|
|
42
|
-
}, multiple: true, accept: "*", "data-testid": "hidden-file-input" }))),
|
|
54
|
+
}, multiple: true, accept: "*", "data-testid": "hidden-file-input" })))) : null,
|
|
43
55
|
React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onKeyDown: (e) => {
|
|
44
56
|
// Submit on enter key if shift is not pressed also
|
|
45
57
|
const shouldSubmit = !e.shiftKey && e.key === 'Enter';
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,6 @@ var ui = require('@aws-amplify/ui');
|
|
|
9
9
|
var uiReact = require('@aws-amplify/ui-react');
|
|
10
10
|
var internal = require('@aws-amplify/ui-react/internal');
|
|
11
11
|
|
|
12
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
13
|
-
|
|
14
12
|
function _interopNamespace(e) {
|
|
15
13
|
if (e && e.__esModule) return e;
|
|
16
14
|
var n = Object.create(null);
|
|
@@ -29,7 +27,6 @@ function _interopNamespace(e) {
|
|
|
29
27
|
return Object.freeze(n);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
33
30
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
31
|
|
|
35
32
|
const DEFAULT_ICON_PATHS = {
|
|
@@ -54,7 +51,7 @@ const BaseIconElement = elements.defineBaseElement({
|
|
|
54
51
|
});
|
|
55
52
|
const getIconProps = ({ variant, ...props }) => {
|
|
56
53
|
const pathData = variant ? DEFAULT_ICON_PATHS[variant] : undefined;
|
|
57
|
-
const children = pathData ? (
|
|
54
|
+
const children = pathData ? (React__namespace["default"].createElement("path", { d: pathData, fill: "currentColor" })) : undefined;
|
|
58
55
|
return {
|
|
59
56
|
...DEFAULT_ICON_ATTRIBUTES,
|
|
60
57
|
...props,
|
|
@@ -120,38 +117,38 @@ const AIConversationElements = {
|
|
|
120
117
|
View: ViewElement,
|
|
121
118
|
};
|
|
122
119
|
|
|
123
|
-
const ActionsContext =
|
|
120
|
+
const ActionsContext = React__namespace["default"].createContext(undefined);
|
|
124
121
|
const ActionsProvider = ({ children, actions, }) => {
|
|
125
|
-
return (
|
|
122
|
+
return (React__namespace["default"].createElement(ActionsContext.Provider, { value: actions }, children));
|
|
126
123
|
};
|
|
127
124
|
|
|
128
|
-
const AvatarsContext =
|
|
125
|
+
const AvatarsContext = React__namespace["default"].createContext(undefined);
|
|
129
126
|
const AvatarsProvider = ({ children, avatars, }) => {
|
|
130
|
-
return (
|
|
127
|
+
return (React__namespace["default"].createElement(AvatarsContext.Provider, { value: avatars }, children));
|
|
131
128
|
};
|
|
132
129
|
|
|
133
|
-
const ConversationInputContext =
|
|
130
|
+
const ConversationInputContext = React__namespace["default"].createContext({});
|
|
134
131
|
const ConversationInputContextProvider = ({ children, }) => {
|
|
135
|
-
const [input, setInput] =
|
|
136
|
-
const providerValue =
|
|
137
|
-
return (
|
|
132
|
+
const [input, setInput] = React__namespace["default"].useState();
|
|
133
|
+
const providerValue = React__namespace["default"].useMemo(() => ({ input, setInput }), [input, setInput]);
|
|
134
|
+
return (React__namespace["default"].createElement(ConversationInputContext.Provider, { value: providerValue }, children));
|
|
138
135
|
};
|
|
139
136
|
|
|
140
|
-
const MessagesContext =
|
|
137
|
+
const MessagesContext = React__namespace["default"].createContext(undefined);
|
|
141
138
|
// role of the user sending the message, assistant or user
|
|
142
|
-
const RoleContext =
|
|
139
|
+
const RoleContext = React__namespace["default"].createContext(undefined);
|
|
143
140
|
const MessagesProvider = ({ children, messages, }) => {
|
|
144
|
-
return (
|
|
141
|
+
return (React__namespace["default"].createElement(MessagesContext.Provider, { value: messages }, children));
|
|
145
142
|
};
|
|
146
143
|
|
|
147
|
-
const SuggestedPromptsContext =
|
|
144
|
+
const SuggestedPromptsContext = React__namespace["default"].createContext(undefined);
|
|
148
145
|
const SuggestedPromptProvider = ({ children, suggestedPrompts, }) => {
|
|
149
|
-
return (
|
|
146
|
+
return (React__namespace["default"].createElement(SuggestedPromptsContext.Provider, { value: suggestedPrompts }, children));
|
|
150
147
|
};
|
|
151
148
|
|
|
152
|
-
const MessageVariantContext =
|
|
149
|
+
const MessageVariantContext = React__namespace["default"].createContext(undefined);
|
|
153
150
|
const MessageVariantProvider = ({ children, variant, }) => {
|
|
154
|
-
return (
|
|
151
|
+
return (React__namespace["default"].createElement(MessageVariantContext.Provider, { value: variant }, children));
|
|
155
152
|
};
|
|
156
153
|
|
|
157
154
|
function formatDate(date) {
|
|
@@ -201,18 +198,18 @@ const { ConversationDisplayTextContext, ConversationDisplayTextProvider, useConv
|
|
|
201
198
|
defaultValue: defaultAIConversationDisplayTextEn,
|
|
202
199
|
});
|
|
203
200
|
|
|
204
|
-
const ControlsContext =
|
|
201
|
+
const ControlsContext = React__namespace["default"].createContext(undefined);
|
|
205
202
|
const ControlsProvider = ({ children, controls, }) => {
|
|
206
|
-
return (
|
|
203
|
+
return (React__namespace["default"].createElement(ControlsContext.Provider, { value: controls }, children));
|
|
207
204
|
};
|
|
208
205
|
|
|
209
|
-
const LoadingContext =
|
|
206
|
+
const LoadingContext = React__namespace["default"].createContext(undefined);
|
|
210
207
|
const LoadingContextProvider = ({ children, isLoading, }) => {
|
|
211
|
-
return (
|
|
208
|
+
return (React__namespace["default"].createElement(LoadingContext.Provider, { value: isLoading }, children));
|
|
212
209
|
};
|
|
213
210
|
|
|
214
211
|
const RESPONSE_COMPONENT_PREFIX = 'AMPLIFY_UI_';
|
|
215
|
-
const ResponseComponentsContext =
|
|
212
|
+
const ResponseComponentsContext = React__namespace["default"].createContext(undefined);
|
|
216
213
|
const prependResponseComponents = (responseComponents) => {
|
|
217
214
|
if (!responseComponents)
|
|
218
215
|
return responseComponents;
|
|
@@ -220,8 +217,8 @@ const prependResponseComponents = (responseComponents) => {
|
|
|
220
217
|
prev), {});
|
|
221
218
|
};
|
|
222
219
|
const ResponseComponentsProvider = ({ children, responseComponents, }) => {
|
|
223
|
-
const _responseComponents =
|
|
224
|
-
return (
|
|
220
|
+
const _responseComponents = React__namespace["default"].useMemo(() => prependResponseComponents(responseComponents), [responseComponents]);
|
|
221
|
+
return (React__namespace["default"].createElement(ResponseComponentsContext.Provider, { value: _responseComponents }, children));
|
|
225
222
|
};
|
|
226
223
|
const convertResponseComponentsToToolConfiguration = (responseComponents) => {
|
|
227
224
|
if (!responseComponents) {
|
|
@@ -251,9 +248,9 @@ const convertResponseComponentsToToolConfiguration = (responseComponents) => {
|
|
|
251
248
|
return { tools };
|
|
252
249
|
};
|
|
253
250
|
|
|
254
|
-
const SendMessageContext =
|
|
251
|
+
const SendMessageContext = React__namespace["default"].createContext(undefined);
|
|
255
252
|
const SendMessageContextProvider = ({ children, handleSendMessage, }) => {
|
|
256
|
-
return (
|
|
253
|
+
return (React__namespace["default"].createElement(SendMessageContext.Provider, { value: handleSendMessage }, children));
|
|
257
254
|
};
|
|
258
255
|
|
|
259
256
|
const { Button: Button$5, Span: Span$3, View: View$7 } = AIConversationElements;
|
|
@@ -265,16 +262,16 @@ const ActionIcon = elements.withBaseElementProps(Span$3, {
|
|
|
265
262
|
const ActionButtonBase = elements.withBaseElementProps(Button$5, {
|
|
266
263
|
className: `${ACTIONS_BAR_BLOCK}__button`,
|
|
267
264
|
});
|
|
268
|
-
const ActionButton =
|
|
269
|
-
return
|
|
265
|
+
const ActionButton = React__namespace["default"].forwardRef(function ActionButton(props, ref) {
|
|
266
|
+
return React__namespace["default"].createElement(ActionButtonBase, { ...props, ref: ref });
|
|
270
267
|
});
|
|
271
268
|
const Container$4 = elements.withBaseElementProps(View$7, {
|
|
272
269
|
className: `${ACTIONS_BAR_BLOCK}__container`,
|
|
273
270
|
});
|
|
274
271
|
const ActionsBarControl = ({ message, focusable, }) => {
|
|
275
|
-
const actions =
|
|
276
|
-
return (
|
|
277
|
-
|
|
272
|
+
const actions = React__namespace["default"].useContext(ActionsContext);
|
|
273
|
+
return (React__namespace["default"].createElement(Container$4, null, actions?.map((action, index) => (React__namespace["default"].createElement(ActionButton, { "aria-label": action.displayName, key: index, onClick: () => action.handler(message), tabIndex: focusable ? 0 : -1 },
|
|
274
|
+
React__namespace["default"].createElement(ActionIcon, { "data-testid": `action-icon-${action.displayName}` }, action.icon))))));
|
|
278
275
|
};
|
|
279
276
|
ActionsBarControl.Button = ActionButton;
|
|
280
277
|
ActionsBarControl.Container = Container$4;
|
|
@@ -285,9 +282,9 @@ const AVATAR_BLOCK = 'ai-avatar';
|
|
|
285
282
|
const DEFAULT_USER_ICON = elements.withBaseElementProps(Icon$5, {
|
|
286
283
|
variant: 'user-avatar',
|
|
287
284
|
});
|
|
288
|
-
const DEFAULT_AI_ICON = () => (
|
|
289
|
-
|
|
290
|
-
|
|
285
|
+
const DEFAULT_AI_ICON = () => (React__namespace["default"].createElement("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
|
|
286
|
+
React__namespace["default"].createElement("g", { id: "raven-logo" },
|
|
287
|
+
React__namespace["default"].createElement("path", { id: "Subtract", fillRule: "evenodd", clipRule: "evenodd", d: "M16 1.29833C14.7624 0.583803 13.2376 0.583804 12 1.29833L4.00006 5.91711C2.76246 6.63165 2.00006 7.95216 2.00006 9.38122V18.6188C2.00006 20.0478 2.76246 21.3684 4.00006 22.0829L12 26.7017C13.2376 27.4162 14.7624 27.4162 16 26.7017L24 22.0829C25.2376 21.3684 26 20.0478 26 18.6188V9.38122C26 7.95215 25.2376 6.63164 24 5.91711L16 1.29833ZM14.9379 6.37317C14.6157 5.50255 13.3843 5.50255 13.0622 6.37317L11.4151 10.8243C11.3138 11.098 11.098 11.3138 10.8243 11.4151L6.37317 13.0621C5.50256 13.3843 5.50256 14.6157 6.37317 14.9378L10.8243 16.5849C11.098 16.6862 11.3138 16.902 11.4151 17.1757L13.0622 21.6268C13.3843 22.4974 14.6157 22.4974 14.9379 21.6268L16.5849 17.1757C16.6862 16.902 16.902 16.6862 17.1757 16.5849L21.6268 14.9378C22.4974 14.6157 22.4974 13.3843 21.6268 13.0621L17.1757 11.4151C16.902 11.3138 16.6862 11.098 16.5849 10.8243L14.9379 6.37317Z", fill: "#0D1A26" }))));
|
|
291
288
|
const AvatarDisplayName = elements.withBaseElementProps(Text$4, {
|
|
292
289
|
className: `${AVATAR_BLOCK}__display-name`,
|
|
293
290
|
});
|
|
@@ -299,14 +296,14 @@ const Container$3 = elements.withBaseElementProps(View$6, {
|
|
|
299
296
|
className: `${AVATAR_BLOCK}__container`,
|
|
300
297
|
});
|
|
301
298
|
const AvatarControl = () => {
|
|
302
|
-
const avatars =
|
|
303
|
-
const role =
|
|
299
|
+
const avatars = React__namespace["default"].useContext(AvatarsContext);
|
|
300
|
+
const role = React__namespace["default"].useContext(RoleContext);
|
|
304
301
|
const avatar = role === 'assistant' ? avatars?.ai : avatars?.user;
|
|
305
|
-
const defaultIcon = role === 'assistant' ?
|
|
302
|
+
const defaultIcon = role === 'assistant' ? React__namespace["default"].createElement(DEFAULT_AI_ICON, null) : React__namespace["default"].createElement(DEFAULT_USER_ICON, null);
|
|
306
303
|
const defaultDisplayName = role === 'user' ? 'User' : 'Assistant';
|
|
307
|
-
return (
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
return (React__namespace["default"].createElement(Container$3, { "data-testid": 'avatar' },
|
|
305
|
+
React__namespace["default"].createElement(AvatarIcon, { "data-testid": `avatar-icon-${role}` }, avatar?.avatar ?? defaultIcon),
|
|
306
|
+
React__namespace["default"].createElement(AvatarDisplayName, null, avatar?.username ?? defaultDisplayName)));
|
|
310
307
|
};
|
|
311
308
|
AvatarControl.Container = Container$3;
|
|
312
309
|
AvatarControl.DisplayName = AvatarDisplayName;
|
|
@@ -317,8 +314,8 @@ const HEADER_BLOCK = 'ai-header';
|
|
|
317
314
|
const HeaderTextBase = elements.withBaseElementProps(Text$3, {
|
|
318
315
|
className: `${HEADER_BLOCK}__text`,
|
|
319
316
|
});
|
|
320
|
-
const HeaderText$1 =
|
|
321
|
-
return
|
|
317
|
+
const HeaderText$1 = React__namespace["default"].forwardRef(function HeaderText(props, ref) {
|
|
318
|
+
return React__namespace["default"].createElement(HeaderTextBase, { ...props, ref: ref });
|
|
322
319
|
});
|
|
323
320
|
const CloseIcon = elements.withBaseElementProps(Icon$4, {
|
|
324
321
|
className: `${HEADER_BLOCK}__icon`,
|
|
@@ -327,16 +324,16 @@ const CloseIcon = elements.withBaseElementProps(Icon$4, {
|
|
|
327
324
|
const CloseButtonBase = elements.withBaseElementProps(Button$4, {
|
|
328
325
|
className: `${HEADER_BLOCK}__button`,
|
|
329
326
|
});
|
|
330
|
-
const CloseButton =
|
|
331
|
-
return
|
|
327
|
+
const CloseButton = React__namespace["default"].forwardRef(function CloseButton(props, ref) {
|
|
328
|
+
return React__namespace["default"].createElement(CloseButtonBase, { ...props, ref: ref });
|
|
332
329
|
});
|
|
333
330
|
const Container$2 = elements.withBaseElementProps(View$5, {
|
|
334
331
|
className: `${HEADER_BLOCK}__container`,
|
|
335
332
|
});
|
|
336
|
-
const HeaderControl = () => (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
333
|
+
const HeaderControl = () => (React__namespace["default"].createElement(Container$2, null,
|
|
334
|
+
React__namespace["default"].createElement(HeaderText$1, null, "Raven Chat"),
|
|
335
|
+
React__namespace["default"].createElement(CloseButton, null,
|
|
336
|
+
React__namespace["default"].createElement(CloseIcon, null))));
|
|
340
337
|
HeaderControl.Container = Container$2;
|
|
341
338
|
HeaderControl.Text = HeaderText$1;
|
|
342
339
|
HeaderControl.Button = CloseButton;
|
|
@@ -361,8 +358,19 @@ const AttachFileButton = elements.withBaseElementProps(Button$3, {
|
|
|
361
358
|
variant: 'attach',
|
|
362
359
|
});
|
|
363
360
|
const AttachFileControl = () => {
|
|
364
|
-
const hiddenInput =
|
|
365
|
-
const { setInput } =
|
|
361
|
+
const hiddenInput = React__namespace["default"].useRef(null);
|
|
362
|
+
const { setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
363
|
+
const { dragState, ...dropHandlers } = uiReactCore.useDropZone({
|
|
364
|
+
acceptedFileTypes: ['.jpeg'],
|
|
365
|
+
onDropComplete: ({ acceptedFiles }) => {
|
|
366
|
+
if (acceptedFiles && acceptedFiles?.length > 0 && setInput) {
|
|
367
|
+
setInput((prevInput) => ({
|
|
368
|
+
...prevInput,
|
|
369
|
+
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
370
|
+
}));
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
});
|
|
366
374
|
function handleButtonClick() {
|
|
367
375
|
if (hiddenInput.current) {
|
|
368
376
|
hiddenInput.current.click();
|
|
@@ -380,11 +388,11 @@ const AttachFileControl = () => {
|
|
|
380
388
|
});
|
|
381
389
|
}
|
|
382
390
|
}
|
|
383
|
-
return (
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
return (React__namespace["default"].createElement(AttachFileContainer, { ...dropHandlers },
|
|
392
|
+
React__namespace["default"].createElement(AttachFileButton, { onClick: handleButtonClick },
|
|
393
|
+
React__namespace["default"].createElement(AttachFileIcon, null)),
|
|
394
|
+
React__namespace["default"].createElement(VisuallyHidden$1, null,
|
|
395
|
+
React__namespace["default"].createElement("input", { accept: ".jpeg,.png,.webp,.gif", "data-testid": "hidden-file-input", onChange: handleFileChange, ref: hiddenInput, type: "file", multiple: true }))));
|
|
388
396
|
};
|
|
389
397
|
AttachFileControl.Icon = AttachFileIcon;
|
|
390
398
|
AttachFileControl.Button = AttachFileButton;
|
|
@@ -406,8 +414,8 @@ const RemoveButton = elements.withBaseElementProps(Button$2, {
|
|
|
406
414
|
type: 'button',
|
|
407
415
|
});
|
|
408
416
|
const RemoveButtonControl = ({ onRemove }) => {
|
|
409
|
-
return (
|
|
410
|
-
|
|
417
|
+
return (React__namespace["default"].createElement(RemoveButton, { onClick: onRemove },
|
|
418
|
+
React__namespace["default"].createElement(RemoveIcon, null)));
|
|
411
419
|
};
|
|
412
420
|
RemoveButtonControl.Icon = RemoveIcon;
|
|
413
421
|
RemoveButtonControl.Button = RemoveButton;
|
|
@@ -430,10 +438,10 @@ const TextContainer = elements.withBaseElementProps(View$3, {
|
|
|
430
438
|
className: `${IMAGE_TEXT_BLOCK}__container`,
|
|
431
439
|
});
|
|
432
440
|
const TextControl = ({ fileName, fileSize }) => {
|
|
433
|
-
return (
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
441
|
+
return (React__namespace["default"].createElement(TextContainer, null,
|
|
442
|
+
React__namespace["default"].createElement(FileNameText, null, fileName),
|
|
443
|
+
React__namespace["default"].createElement(Separator$1, null),
|
|
444
|
+
React__namespace["default"].createElement(FileSizeText, null, fileSize)));
|
|
437
445
|
};
|
|
438
446
|
TextControl.Container = TextContainer;
|
|
439
447
|
TextControl.FileName = FileNameText;
|
|
@@ -443,10 +451,10 @@ const Container$1 = elements.withBaseElementProps(ListItem, {
|
|
|
443
451
|
className: `${IMAGE_ITEM_BLOCK}__list-item`,
|
|
444
452
|
});
|
|
445
453
|
const AttachmentControl = ({ image, onRemove }) => {
|
|
446
|
-
return (
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
454
|
+
return (React__namespace["default"].createElement(Container$1, null,
|
|
455
|
+
React__namespace["default"].createElement(ImageIcon, null),
|
|
456
|
+
React__namespace["default"].createElement(TextControl, { fileName: image.name, fileSize: image.size }),
|
|
457
|
+
React__namespace["default"].createElement(RemoveButtonControl, { onRemove: onRemove })));
|
|
450
458
|
};
|
|
451
459
|
AttachmentControl.Container = Container$1;
|
|
452
460
|
AttachmentControl.ImageIcon = ImageIcon;
|
|
@@ -456,8 +464,8 @@ const UnorderedList = elements.withBaseElementProps(ListElement, {
|
|
|
456
464
|
className: `${IMAGE_LIST_BLOCK}__unordered-list`,
|
|
457
465
|
});
|
|
458
466
|
const AttachmentListControl = () => {
|
|
459
|
-
const { input, setInput } =
|
|
460
|
-
return (
|
|
467
|
+
const { input, setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
468
|
+
return (React__namespace["default"].createElement(UnorderedList, null, input?.files?.map((file, index) => {
|
|
461
469
|
const onRemove = () => {
|
|
462
470
|
if (setInput) {
|
|
463
471
|
setInput((prevInput) => ({
|
|
@@ -466,12 +474,17 @@ const AttachmentListControl = () => {
|
|
|
466
474
|
}));
|
|
467
475
|
}
|
|
468
476
|
};
|
|
469
|
-
return (
|
|
477
|
+
return (React__namespace["default"].createElement(AttachmentControl, { key: index, image: file, onRemove: onRemove }));
|
|
470
478
|
})));
|
|
471
479
|
};
|
|
472
480
|
AttachmentListControl.List = UnorderedList;
|
|
473
481
|
AttachmentListControl.Item = AttachmentControl;
|
|
474
482
|
|
|
483
|
+
const AttachmentContext = React__namespace.createContext(false);
|
|
484
|
+
const AttachmentProvider = ({ children, allowAttachments, }) => {
|
|
485
|
+
return (React__namespace.createElement(AttachmentContext.Provider, { value: allowAttachments ?? false }, children));
|
|
486
|
+
};
|
|
487
|
+
|
|
475
488
|
const { Button: Button$1, Icon: Icon$1, Label: LabelElement, TextArea, View: View$2, } = AIConversationElements;
|
|
476
489
|
const FIELD_BLOCK = 'ai-field';
|
|
477
490
|
const SendIcon = elements.withBaseElementProps(Icon$1, {
|
|
@@ -482,11 +495,11 @@ const SendButtonBase = elements.withBaseElementProps(Button$1, {
|
|
|
482
495
|
'aria-label': 'Send message',
|
|
483
496
|
className: `${FIELD_BLOCK}__button ${FIELD_BLOCK}__button--send`,
|
|
484
497
|
});
|
|
485
|
-
const SendButton =
|
|
486
|
-
const { input } =
|
|
487
|
-
const isLoading =
|
|
498
|
+
const SendButton = React__namespace["default"].forwardRef(function SendButton(props, ref) {
|
|
499
|
+
const { input } = React__namespace["default"].useContext(ConversationInputContext);
|
|
500
|
+
const isLoading = React__namespace["default"].useContext(LoadingContext);
|
|
488
501
|
const hasInput = !!input?.text || !!input?.files?.length;
|
|
489
|
-
return (
|
|
502
|
+
return (React__namespace["default"].createElement(SendButtonBase, { ...props,
|
|
490
503
|
// we intentionally || in the case where isLoading is false we should use the value of hasInput
|
|
491
504
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
492
505
|
disabled: isLoading || !hasInput, type: "submit", ref: ref, "data-testid": "send-button" }));
|
|
@@ -505,7 +518,7 @@ const Label = elements.withBaseElementProps(LabelElement, {
|
|
|
505
518
|
htmlFor: 'text-input',
|
|
506
519
|
});
|
|
507
520
|
const useHandleResize = (textAreaRef) => {
|
|
508
|
-
|
|
521
|
+
React__namespace["default"].useEffect(() => {
|
|
509
522
|
const { current } = textAreaRef;
|
|
510
523
|
const handleResize = () => {
|
|
511
524
|
if (current) {
|
|
@@ -524,18 +537,18 @@ const useHandleResize = (textAreaRef) => {
|
|
|
524
537
|
};
|
|
525
538
|
}, [textAreaRef]);
|
|
526
539
|
};
|
|
527
|
-
const TextInput =
|
|
528
|
-
const { setInput } =
|
|
529
|
-
const messages =
|
|
530
|
-
const textAreaRef =
|
|
540
|
+
const TextInput = React__namespace["default"].forwardRef(function TextInput(props, ref) {
|
|
541
|
+
const { setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
542
|
+
const messages = React__namespace["default"].useContext(MessagesContext);
|
|
543
|
+
const textAreaRef = React__namespace["default"].useRef(null);
|
|
531
544
|
useHandleResize(textAreaRef);
|
|
532
545
|
const isFirstMessage = !messages || messages.length === 0;
|
|
533
|
-
|
|
546
|
+
React__namespace["default"].useEffect(() => {
|
|
534
547
|
if (textAreaRef && textAreaRef.current) {
|
|
535
548
|
textAreaRef.current.focus();
|
|
536
549
|
}
|
|
537
550
|
}, [textAreaRef]);
|
|
538
|
-
return (
|
|
551
|
+
return (React__namespace["default"].createElement(TextAreaBase, { ...props, "data-testid": "text-input", id: "text-input", onChange: (e) => props.onChange ??
|
|
539
552
|
(setInput &&
|
|
540
553
|
setInput((prevInput) => ({ ...prevInput, text: e.target.value }))), placeholder: props.placeholder ?? isFirstMessage
|
|
541
554
|
? 'Ask anything...'
|
|
@@ -553,11 +566,12 @@ const InputContainer = elements.withBaseElementProps(View$2, {
|
|
|
553
566
|
className: `${FIELD_BLOCK}__input-container`,
|
|
554
567
|
});
|
|
555
568
|
const FieldControl = () => {
|
|
556
|
-
const { input, setInput } =
|
|
557
|
-
const handleSendMessage =
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
const
|
|
569
|
+
const { input, setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
570
|
+
const handleSendMessage = React__namespace["default"].useContext(SendMessageContext);
|
|
571
|
+
const allowAttachments = React__namespace["default"].useContext(AttachmentContext);
|
|
572
|
+
const ref = React__namespace["default"].useRef(null);
|
|
573
|
+
const responseComponents = React__namespace["default"].useContext(ResponseComponentsContext);
|
|
574
|
+
const controls = React__namespace["default"].useContext(ControlsContext);
|
|
561
575
|
const submitMessage = async () => {
|
|
562
576
|
ref.current?.reset();
|
|
563
577
|
const submittedContent = [];
|
|
@@ -603,17 +617,17 @@ const FieldControl = () => {
|
|
|
603
617
|
}
|
|
604
618
|
};
|
|
605
619
|
if (controls?.Form) {
|
|
606
|
-
return (
|
|
620
|
+
return (React__namespace["default"].createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, allowAttachments: allowAttachments }));
|
|
607
621
|
}
|
|
608
|
-
return (
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
622
|
+
return (React__namespace["default"].createElement("form", { className: `${FIELD_BLOCK}__form`, onSubmit: handleSubmit, method: "post", ref: ref },
|
|
623
|
+
allowAttachments ? React__namespace["default"].createElement(AttachFileControl, null) : null,
|
|
624
|
+
React__namespace["default"].createElement(InputContainer, null,
|
|
625
|
+
React__namespace["default"].createElement(VisuallyHidden, null,
|
|
626
|
+
React__namespace["default"].createElement(Label, null)),
|
|
627
|
+
React__namespace["default"].createElement(TextInput, { onKeyDown: handleOnKeyDown }),
|
|
628
|
+
React__namespace["default"].createElement(AttachmentListControl, null)),
|
|
629
|
+
React__namespace["default"].createElement(SendButton, null,
|
|
630
|
+
React__namespace["default"].createElement(SendIcon, null))));
|
|
617
631
|
};
|
|
618
632
|
FieldControl.AttachFile = AttachFileControl;
|
|
619
633
|
FieldControl.InputContainer = InputContainer;
|
|
@@ -628,26 +642,26 @@ const MESSAGE_BLOCK = 'ai-message';
|
|
|
628
642
|
const MediaContentBase = elements.withBaseElementProps(Image, {
|
|
629
643
|
alt: 'Image attachment',
|
|
630
644
|
});
|
|
631
|
-
const MediaContent =
|
|
632
|
-
const variant =
|
|
633
|
-
const role =
|
|
634
|
-
return (
|
|
645
|
+
const MediaContent = React__namespace["default"].forwardRef(function MediaContent(props, ref) {
|
|
646
|
+
const variant = React__namespace["default"].useContext(MessageVariantContext);
|
|
647
|
+
const role = React__namespace["default"].useContext(RoleContext);
|
|
648
|
+
return (React__namespace["default"].createElement(MediaContentBase, { ref: ref, className: `${MESSAGE_BLOCK}__image ${MESSAGE_BLOCK}__image--${variant} ${MESSAGE_BLOCK}__image--${role}`, ...props }));
|
|
635
649
|
});
|
|
636
|
-
const TextContent =
|
|
637
|
-
return
|
|
650
|
+
const TextContent = React__namespace["default"].forwardRef(function TextContent(props, ref) {
|
|
651
|
+
return React__namespace["default"].createElement(Text$1, { ref: ref, className: `${MESSAGE_BLOCK}__text`, ...props });
|
|
638
652
|
});
|
|
639
|
-
const ContentContainer =
|
|
640
|
-
const variant =
|
|
641
|
-
return (
|
|
653
|
+
const ContentContainer = React__namespace["default"].forwardRef(function ContentContainer(props, ref) {
|
|
654
|
+
const variant = React__namespace["default"].useContext(MessageVariantContext);
|
|
655
|
+
return (React__namespace["default"].createElement(View$1, { "data-testid": 'content', className: `${MESSAGE_BLOCK}__content ${MESSAGE_BLOCK}__content--${variant}`, ref: ref, ...props }));
|
|
642
656
|
});
|
|
643
657
|
const MessageControl = ({ message }) => {
|
|
644
|
-
const responseComponents =
|
|
645
|
-
return (
|
|
658
|
+
const responseComponents = React__namespace["default"].useContext(ResponseComponentsContext);
|
|
659
|
+
return (React__namespace["default"].createElement(ContentContainer, null, message.content.map((content, index) => {
|
|
646
660
|
if (content.text) {
|
|
647
|
-
return (
|
|
661
|
+
return (React__namespace["default"].createElement(TextContent, { "data-testid": 'text-content', key: index }, content.text));
|
|
648
662
|
}
|
|
649
663
|
else if (content.image) {
|
|
650
|
-
return (
|
|
664
|
+
return (React__namespace["default"].createElement(MediaContent, { "data-testid": 'image-content', key: index, src: convertBufferToBase64(content.image?.source.bytes, content.image?.format) }));
|
|
651
665
|
}
|
|
652
666
|
else if (content.toolUse) {
|
|
653
667
|
// For now tool use is limited to custom response components
|
|
@@ -660,7 +674,7 @@ const MessageControl = ({ message }) => {
|
|
|
660
674
|
else {
|
|
661
675
|
const response = responseComponents[name];
|
|
662
676
|
const CustomComponent = response.component;
|
|
663
|
-
return
|
|
677
|
+
return React__namespace["default"].createElement(CustomComponent, { ...input, key: index });
|
|
664
678
|
}
|
|
665
679
|
}
|
|
666
680
|
})));
|
|
@@ -676,27 +690,27 @@ const Separator = elements.withBaseElementProps(Span, {
|
|
|
676
690
|
const Timestamp = elements.withBaseElementProps(Text$1, {
|
|
677
691
|
className: `${MESSAGE_BLOCK}__timestamp`,
|
|
678
692
|
});
|
|
679
|
-
const HeaderContainer =
|
|
680
|
-
const variant =
|
|
681
|
-
return (
|
|
693
|
+
const HeaderContainer = React__namespace["default"].forwardRef(function HeaderContainer(props, ref) {
|
|
694
|
+
const variant = React__namespace["default"].useContext(MessageVariantContext);
|
|
695
|
+
return (React__namespace["default"].createElement(View$1, { ref: ref, className: `${MESSAGE_BLOCK}__header__container ${MESSAGE_BLOCK}__header__container--${variant}`, ...props }));
|
|
682
696
|
});
|
|
683
|
-
const MessageContainer =
|
|
684
|
-
const variant =
|
|
685
|
-
const role =
|
|
686
|
-
return (
|
|
697
|
+
const MessageContainer = React__namespace["default"].forwardRef(function MessageContainer(props, ref) {
|
|
698
|
+
const variant = React__namespace["default"].useContext(MessageVariantContext);
|
|
699
|
+
const role = React__namespace["default"].useContext(RoleContext);
|
|
700
|
+
return (React__namespace["default"].createElement(View$1, { ref: ref, className: `${MESSAGE_BLOCK} ${MESSAGE_BLOCK}--${variant} ${MESSAGE_BLOCK}--${role}`, ...props }));
|
|
687
701
|
});
|
|
688
|
-
const Layout =
|
|
689
|
-
const variant =
|
|
690
|
-
return (
|
|
702
|
+
const Layout = React__namespace["default"].forwardRef(function Layout(props, ref) {
|
|
703
|
+
const variant = React__namespace["default"].useContext(MessageVariantContext);
|
|
704
|
+
return (React__namespace["default"].createElement(View$1, { ref: ref, className: `${MESSAGES_BLOCK}__container ${MESSAGES_BLOCK}__container--${variant}`, "aria-live": 'assertive', ...props }));
|
|
691
705
|
});
|
|
692
706
|
const MessagesControl = ({ renderMessage }) => {
|
|
693
|
-
const messages =
|
|
694
|
-
const controls =
|
|
707
|
+
const messages = React__namespace["default"].useContext(MessagesContext);
|
|
708
|
+
const controls = React__namespace["default"].useContext(ControlsContext);
|
|
695
709
|
const { getMessageTimestampText } = useConversationDisplayText();
|
|
696
|
-
const messagesRef =
|
|
697
|
-
const [focusedItemIndex, setFocusedItemIndex] =
|
|
710
|
+
const messagesRef = React__namespace["default"].useRef([]);
|
|
711
|
+
const [focusedItemIndex, setFocusedItemIndex] = React__namespace["default"].useState(messages ? messages.length - 1 : 0);
|
|
698
712
|
const handleFocus = (index) => setFocusedItemIndex(index);
|
|
699
|
-
const onKeyDown =
|
|
713
|
+
const onKeyDown = React__namespace["default"].useCallback((index, { key }) => {
|
|
700
714
|
let newIndex;
|
|
701
715
|
switch (key) {
|
|
702
716
|
case 'ArrowUp':
|
|
@@ -723,20 +737,20 @@ const MessagesControl = ({ renderMessage }) => {
|
|
|
723
737
|
return;
|
|
724
738
|
}, [messages]);
|
|
725
739
|
if (controls?.MessageList) {
|
|
726
|
-
return
|
|
740
|
+
return React__namespace["default"].createElement(controls.MessageList, { messages: messages });
|
|
727
741
|
}
|
|
728
742
|
const messagesWithRenderableContent = messages?.filter((message) => message.content.some((content) => content.image ??
|
|
729
743
|
content.text ??
|
|
730
744
|
content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
|
|
731
|
-
return (
|
|
732
|
-
return renderMessage ? (renderMessage(message)) : (
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
message.role === 'assistant' ? (
|
|
745
|
+
return (React__namespace["default"].createElement(Layout, null, messagesWithRenderableContent?.map((message, index) => {
|
|
746
|
+
return renderMessage ? (renderMessage(message)) : (React__namespace["default"].createElement(RoleContext.Provider, { value: message.role, key: `message-${index}` },
|
|
747
|
+
React__namespace["default"].createElement(MessageContainer, { "data-testid": `message`, key: `message-${index}`, tabIndex: focusedItemIndex === index ? 0 : -1, onFocus: () => handleFocus(index), onKeyDown: (event) => onKeyDown(index, event), ref: (el) => (messagesRef.current[index] = el) },
|
|
748
|
+
React__namespace["default"].createElement(HeaderContainer, null,
|
|
749
|
+
React__namespace["default"].createElement(AvatarControl, null),
|
|
750
|
+
React__namespace["default"].createElement(Separator, null),
|
|
751
|
+
React__namespace["default"].createElement(Timestamp, null, getMessageTimestampText(new Date(message.createdAt)))),
|
|
752
|
+
React__namespace["default"].createElement(MessageControl, { message: message }),
|
|
753
|
+
message.role === 'assistant' ? (React__namespace["default"].createElement(ActionsBarControl, { message: message, focusable: focusedItemIndex === index })) : null)));
|
|
740
754
|
})));
|
|
741
755
|
};
|
|
742
756
|
MessagesControl.ActionsBar = ActionsBarControl;
|
|
@@ -756,13 +770,13 @@ const PromptCard = elements.withBaseElementProps(Button, {
|
|
|
756
770
|
type: 'button',
|
|
757
771
|
});
|
|
758
772
|
const AIIconProps = () => ({
|
|
759
|
-
children: (
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
773
|
+
children: (React__namespace["default"].createElement(React__namespace["default"].Fragment, null,
|
|
774
|
+
React__namespace["default"].createElement("path", { d: "M17.5 1.64858C19.047 0.755412 20.953 0.755412 22.5 1.64858L34.6428 8.65923C36.1898 9.55239 37.1428 11.203 37.1428 12.9894V27.0107C37.1428 28.797 36.1898 30.4476 34.6428 31.3408L22.5 38.3514C20.953 39.2446 19.047 39.2446 17.5 38.3514L5.35718 31.3408C3.81017 30.4476 2.85718 28.797 2.85718 27.0107V12.9894C2.85718 11.203 3.81017 9.55239 5.35718 8.65923L17.5 1.64858Z", fill: "white" }),
|
|
775
|
+
React__namespace["default"].createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M22.5 1.64851C20.953 0.755347 19.047 0.755347 17.5 1.64851L5.35718 8.65916C3.81017 9.55233 2.85718 11.203 2.85718 12.9893V27.0106C2.85718 28.7969 3.81017 30.4476 5.35718 31.3407L17.5 38.3514C19.047 39.2445 20.953 39.2445 22.5 38.3514L34.6428 31.3407C36.1898 30.4476 37.1428 28.7969 37.1428 27.0106V12.9893C37.1428 11.203 36.1898 9.55233 34.6428 8.65916L22.5 1.64851ZM20.9378 8.01826C20.6156 7.14764 19.3843 7.14764 19.0621 8.01825L16.2388 15.648C16.1375 15.9217 15.9217 16.1375 15.648 16.2388L8.01826 19.0621C7.14765 19.3842 7.14765 20.6156 8.01826 20.9378L15.648 23.7611C15.9217 23.8623 16.1375 24.0782 16.2388 24.3519L19.0621 31.9816C19.3843 32.8522 20.6156 32.8522 20.9378 31.9816L23.7611 24.3519C23.8624 24.0782 24.0782 23.8623 24.3519 23.7611L31.9816 20.9378C32.8523 20.6156 32.8523 19.3842 31.9816 19.0621L24.3519 16.2388C24.0782 16.1375 23.8624 15.9217 23.7611 15.648L20.9378 8.01826Z", fill: "url(#paint0_linear_395_1815)" }),
|
|
776
|
+
React__namespace["default"].createElement("defs", null,
|
|
777
|
+
React__namespace["default"].createElement("linearGradient", { id: "paint0_linear_395_1815", x1: "20", y1: "0.978638", x2: "20", y2: "39.0213", gradientUnits: "userSpaceOnUse" },
|
|
778
|
+
React__namespace["default"].createElement("stop", { stopColor: "#7DD6E8" }),
|
|
779
|
+
React__namespace["default"].createElement("stop", { offset: "1", stopColor: "#BF40BF" }))))),
|
|
766
780
|
className: `${PROMPT_CONTROL}__icon`,
|
|
767
781
|
width: '40',
|
|
768
782
|
height: '40',
|
|
@@ -777,41 +791,41 @@ const HeaderText = elements.withBaseElementProps(Heading, {
|
|
|
777
791
|
const PromptGroupBase = elements.withBaseElementProps(View, {
|
|
778
792
|
className: `${PROMPT_CONTROL}__buttongroup`,
|
|
779
793
|
});
|
|
780
|
-
const PromptGroup =
|
|
781
|
-
const suggestedPromptsArray =
|
|
782
|
-
const { setInput } =
|
|
794
|
+
const PromptGroup = React__namespace["default"].forwardRef(function ButtonGroup(props, ref) {
|
|
795
|
+
const suggestedPromptsArray = React__namespace["default"].useContext(SuggestedPromptsContext);
|
|
796
|
+
const { setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
783
797
|
if (!suggestedPromptsArray) {
|
|
784
798
|
return;
|
|
785
799
|
}
|
|
786
|
-
return (
|
|
787
|
-
return (
|
|
800
|
+
return (React__namespace["default"].createElement(PromptGroupBase, { ...props, ref: ref }, suggestedPromptsArray.map((prompt, index) => {
|
|
801
|
+
return (React__namespace["default"].createElement(PromptCard, { key: index, "aria-label": prompt.inputText, onClick: () => setInput &&
|
|
788
802
|
setInput((prevInput) => ({
|
|
789
803
|
...prevInput,
|
|
790
804
|
text: prompt.inputText,
|
|
791
805
|
})) },
|
|
792
|
-
|
|
793
|
-
|
|
806
|
+
React__namespace["default"].createElement(Text, { className: ui.classNames(`${PROMPT_CARD}__header`, `${PROMPT_CARD}__text`) }, prompt.header),
|
|
807
|
+
React__namespace["default"].createElement(Text, { className: `${PROMPT_CARD}__text` }, prompt.inputText)));
|
|
794
808
|
})));
|
|
795
809
|
});
|
|
796
810
|
const Container = elements.withBaseElementProps(View, {
|
|
797
811
|
className: `${PROMPT_BLOCK}__container`,
|
|
798
812
|
});
|
|
799
813
|
const PromptControl = () => {
|
|
800
|
-
const suggestedPromptsArray =
|
|
801
|
-
const controls =
|
|
802
|
-
const { setInput } =
|
|
814
|
+
const suggestedPromptsArray = React__namespace["default"].useContext(SuggestedPromptsContext);
|
|
815
|
+
const controls = React__namespace["default"].useContext(ControlsContext);
|
|
816
|
+
const { setInput } = React__namespace["default"].useContext(ConversationInputContext);
|
|
803
817
|
if (controls?.PromptList) {
|
|
804
|
-
return (
|
|
818
|
+
return (React__namespace["default"].createElement(controls.PromptList, { setInput: setInput, suggestedPrompts: suggestedPromptsArray }));
|
|
805
819
|
}
|
|
806
|
-
return (
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
820
|
+
return (React__namespace["default"].createElement(Container, null,
|
|
821
|
+
React__namespace["default"].createElement(AIIcon, null),
|
|
822
|
+
React__namespace["default"].createElement(HeaderText, null, "How can I help you today?"),
|
|
823
|
+
React__namespace["default"].createElement(PromptGroup, null)));
|
|
810
824
|
};
|
|
811
825
|
const AutoHidablePromptControl = () => {
|
|
812
|
-
const messages =
|
|
826
|
+
const messages = React__namespace["default"].useContext(MessagesContext);
|
|
813
827
|
if (!messages || messages.length === 0) {
|
|
814
|
-
return
|
|
828
|
+
return React__namespace["default"].createElement(PromptControl, null);
|
|
815
829
|
}
|
|
816
830
|
};
|
|
817
831
|
PromptControl.Container = Container;
|
|
@@ -821,33 +835,34 @@ PromptControl.PromptGroup = PromptGroup;
|
|
|
821
835
|
PromptControl.PromptCard = PromptCard;
|
|
822
836
|
|
|
823
837
|
function Conversation() {
|
|
824
|
-
return (
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
838
|
+
return (React__namespace["default"].createElement(ViewElement, null,
|
|
839
|
+
React__namespace["default"].createElement(HeaderControl, null),
|
|
840
|
+
React__namespace["default"].createElement(ViewElement, null,
|
|
841
|
+
React__namespace["default"].createElement(AutoHidablePromptControl, null),
|
|
842
|
+
React__namespace["default"].createElement(MessagesControl, null)),
|
|
843
|
+
React__namespace["default"].createElement(ViewElement, null,
|
|
844
|
+
React__namespace["default"].createElement(FieldControl, null))));
|
|
831
845
|
}
|
|
832
846
|
|
|
833
|
-
function createProvider({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }) {
|
|
847
|
+
function createProvider({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }) {
|
|
834
848
|
return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
|
|
835
849
|
const _displayText = {
|
|
836
850
|
...defaultAIConversationDisplayTextEn,
|
|
837
851
|
...displayText,
|
|
838
852
|
};
|
|
839
|
-
return (
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
853
|
+
return (React__namespace["default"].createElement(elements.ElementsProvider, { elements: elements$1 },
|
|
854
|
+
React__namespace["default"].createElement(ControlsProvider, { controls: controls },
|
|
855
|
+
React__namespace["default"].createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
|
|
856
|
+
React__namespace["default"].createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
|
|
857
|
+
React__namespace["default"].createElement(AttachmentProvider, { allowAttachments: allowAttachments },
|
|
858
|
+
React__namespace["default"].createElement(ConversationDisplayTextProvider, { ..._displayText },
|
|
859
|
+
React__namespace["default"].createElement(ConversationInputContextProvider, null,
|
|
860
|
+
React__namespace["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
|
|
861
|
+
React__namespace["default"].createElement(AvatarsProvider, { avatars: avatars },
|
|
862
|
+
React__namespace["default"].createElement(ActionsProvider, { actions: actions },
|
|
863
|
+
React__namespace["default"].createElement(MessageVariantProvider, { variant: variant },
|
|
864
|
+
React__namespace["default"].createElement(MessagesProvider, { messages: messages },
|
|
865
|
+
React__namespace["default"].createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
|
|
851
866
|
};
|
|
852
867
|
}
|
|
853
868
|
|
|
@@ -855,7 +870,7 @@ function createProvider({ elements: elements$1, actions, suggestedPrompts, respo
|
|
|
855
870
|
* @experimental
|
|
856
871
|
*/
|
|
857
872
|
function createAIConversation(input = {}) {
|
|
858
|
-
const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, } = input;
|
|
873
|
+
const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, allowAttachments, } = input;
|
|
859
874
|
const Provider = createProvider({
|
|
860
875
|
elements,
|
|
861
876
|
actions,
|
|
@@ -864,11 +879,12 @@ function createAIConversation(input = {}) {
|
|
|
864
879
|
variant,
|
|
865
880
|
controls,
|
|
866
881
|
displayText,
|
|
882
|
+
allowAttachments,
|
|
867
883
|
});
|
|
868
884
|
function AIConversation(props) {
|
|
869
885
|
const { messages, avatars, handleSendMessage, isLoading } = props;
|
|
870
|
-
return (
|
|
871
|
-
|
|
886
|
+
return (React__namespace["default"].createElement(Provider, { messages: messages, avatars: avatars, handleSendMessage: handleSendMessage, isLoading: isLoading },
|
|
887
|
+
React__namespace["default"].createElement(Conversation, null)));
|
|
872
888
|
}
|
|
873
889
|
const Controls = {
|
|
874
890
|
ActionsBar: ActionsBarControl,
|
|
@@ -955,21 +971,33 @@ const Attachments = ({ files, setInput, }) => {
|
|
|
955
971
|
function isHTMLFormElement(target) {
|
|
956
972
|
return 'form' in target;
|
|
957
973
|
}
|
|
958
|
-
|
|
974
|
+
/**
|
|
975
|
+
* Will conditionally render the DropZone if allowAttachments
|
|
976
|
+
* is true
|
|
977
|
+
*/
|
|
978
|
+
const FormWrapper = ({ children, allowAttachments, setInput, }) => {
|
|
979
|
+
if (allowAttachments) {
|
|
980
|
+
return (React__namespace.createElement(uiReact.DropZone, { className: ui.ComponentClassName.AIConversationFormDropzone, onDropComplete: ({ acceptedFiles }) => {
|
|
981
|
+
setInput?.((prevInput) => ({
|
|
982
|
+
...prevInput,
|
|
983
|
+
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
984
|
+
}));
|
|
985
|
+
} }, children));
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
return children;
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
const Form = ({ setInput, input, handleSubmit, allowAttachments, }) => {
|
|
959
992
|
const icons = internal.useIcons('aiConversation');
|
|
960
993
|
const sendIcon = icons?.send ?? React__namespace.createElement(internal.IconSend, null);
|
|
961
994
|
const attachIcon = icons?.attach ?? React__namespace.createElement(internal.IconAttach, null);
|
|
962
995
|
const hiddenInput = React__namespace.useRef(null);
|
|
963
996
|
const isLoading = React__namespace.useContext(LoadingContext);
|
|
964
997
|
const isInputEmpty = !input?.text?.length && !input?.files?.length;
|
|
965
|
-
return (React__namespace.createElement(
|
|
966
|
-
setInput((prevInput) => ({
|
|
967
|
-
...prevInput,
|
|
968
|
-
files: [...(prevInput?.files ?? []), ...acceptedFiles],
|
|
969
|
-
}));
|
|
970
|
-
} },
|
|
998
|
+
return (React__namespace.createElement(FormWrapper, { allowAttachments: allowAttachments, setInput: setInput },
|
|
971
999
|
React__namespace.createElement(uiReact.View, { as: "form", className: ui.ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
|
|
972
|
-
React__namespace.createElement(uiReact.Button, { className: ui.ComponentClassName.AIConversationFormAttach, onClick: () => {
|
|
1000
|
+
allowAttachments ? (React__namespace.createElement(uiReact.Button, { className: ui.ComponentClassName.AIConversationFormAttach, onClick: () => {
|
|
973
1001
|
hiddenInput?.current?.click();
|
|
974
1002
|
if (hiddenInput?.current) {
|
|
975
1003
|
hiddenInput.current.value = '';
|
|
@@ -986,7 +1014,7 @@ const Form = ({ setInput, input, handleSubmit, }) => {
|
|
|
986
1014
|
...prevValue,
|
|
987
1015
|
files: [...(prevValue?.files ?? []), ...Array.from(files)],
|
|
988
1016
|
}));
|
|
989
|
-
}, multiple: true, accept: "*", "data-testid": "hidden-file-input" }))),
|
|
1017
|
+
}, multiple: true, accept: "*", "data-testid": "hidden-file-input" })))) : null,
|
|
990
1018
|
React__namespace.createElement(uiReact.TextAreaField, { className: ui.ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onKeyDown: (e) => {
|
|
991
1019
|
// Submit on enter key if shift is not pressed also
|
|
992
1020
|
const shouldSubmit = !e.shiftKey && e.key === 'Enter';
|
|
@@ -1019,7 +1047,7 @@ const PromptList = ({ setInput, suggestedPrompts = [], }) => {
|
|
|
1019
1047
|
})));
|
|
1020
1048
|
};
|
|
1021
1049
|
|
|
1022
|
-
function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }) {
|
|
1050
|
+
function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, allowAttachments, }) {
|
|
1023
1051
|
const icons = internal.useIcons('aiConversation');
|
|
1024
1052
|
const defaultAvatars = {
|
|
1025
1053
|
ai: {
|
|
@@ -1057,6 +1085,7 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
|
|
|
1057
1085
|
...avatars,
|
|
1058
1086
|
},
|
|
1059
1087
|
isLoading,
|
|
1088
|
+
allowAttachments,
|
|
1060
1089
|
};
|
|
1061
1090
|
return (React__namespace.createElement(Provider, { ...providerProps },
|
|
1062
1091
|
React__namespace.createElement(uiReact.Flex, { className: ui.ComponentClassName.AIConversation },
|
|
@@ -1074,10 +1103,10 @@ const AIConversation = Object.assign(AIConversationBase, {
|
|
|
1074
1103
|
Form,
|
|
1075
1104
|
});
|
|
1076
1105
|
|
|
1077
|
-
const AIContext =
|
|
1106
|
+
const AIContext = React__namespace["default"].createContext(undefined);
|
|
1078
1107
|
const useAIContext = () => {
|
|
1079
|
-
const context =
|
|
1080
|
-
const [routeToConversationsMap, setRouteToConversationsMap] =
|
|
1108
|
+
const context = React__namespace["default"].useContext(AIContext);
|
|
1109
|
+
const [routeToConversationsMap, setRouteToConversationsMap] = React__namespace["default"].useState({});
|
|
1081
1110
|
if (context) {
|
|
1082
1111
|
return context;
|
|
1083
1112
|
}
|
|
@@ -1088,7 +1117,7 @@ const useAIContext = () => {
|
|
|
1088
1117
|
*/
|
|
1089
1118
|
const AIContextProvider = ({ children, }) => {
|
|
1090
1119
|
const context = useAIContext();
|
|
1091
|
-
return
|
|
1120
|
+
return React__namespace["default"].createElement(AIContext.Provider, { value: context }, children);
|
|
1092
1121
|
};
|
|
1093
1122
|
|
|
1094
1123
|
function createUseAIGeneration(client) {
|
|
@@ -1127,13 +1156,13 @@ function createUseAIConversation(client) {
|
|
|
1127
1156
|
const messagesFromAIContext = input.id
|
|
1128
1157
|
? routeToConversationsMap[routeName]?.[input.id]
|
|
1129
1158
|
: undefined;
|
|
1130
|
-
const [localMessages, setLocalMessages] =
|
|
1131
|
-
const [conversation, setConversation] =
|
|
1132
|
-
const [waitingForAIResponse, setWaitingForAIResponse] =
|
|
1133
|
-
const [errorMessage, setErrorMessage] =
|
|
1134
|
-
const [hasError, setHasError] =
|
|
1159
|
+
const [localMessages, setLocalMessages] = React__namespace["default"].useState(messagesFromAIContext ?? []);
|
|
1160
|
+
const [conversation, setConversation] = React__namespace["default"].useState(undefined);
|
|
1161
|
+
const [waitingForAIResponse, setWaitingForAIResponse] = React__namespace["default"].useState(false);
|
|
1162
|
+
const [errorMessage, setErrorMessage] = React__namespace["default"].useState();
|
|
1163
|
+
const [hasError, setHasError] = React__namespace["default"].useState(false);
|
|
1135
1164
|
// On hook initialization get conversation and load all messages
|
|
1136
|
-
|
|
1165
|
+
React__namespace["default"].useEffect(() => {
|
|
1137
1166
|
async function initialize() {
|
|
1138
1167
|
const { data: conversation } = input.id
|
|
1139
1168
|
? await clientRoute.get({ id: input.id })
|
|
@@ -1159,11 +1188,11 @@ function createUseAIConversation(client) {
|
|
|
1159
1188
|
initialize();
|
|
1160
1189
|
}, [clientRoute, input.id, routeName, setRouteToConversationsMap]);
|
|
1161
1190
|
// Update messages to match what is in AIContext if they aren't equal
|
|
1162
|
-
|
|
1191
|
+
React__namespace["default"].useEffect(() => {
|
|
1163
1192
|
if (!!messagesFromAIContext && messagesFromAIContext !== localMessages)
|
|
1164
1193
|
setLocalMessages(messagesFromAIContext);
|
|
1165
1194
|
}, [messagesFromAIContext, localMessages]);
|
|
1166
|
-
const sendMessage =
|
|
1195
|
+
const sendMessage = React__namespace["default"].useCallback((input) => {
|
|
1167
1196
|
const { content, aiContext, toolConfiguration } = input;
|
|
1168
1197
|
conversation
|
|
1169
1198
|
?.sendMessage({ content, aiContext, toolConfiguration })
|
|
@@ -1193,7 +1222,7 @@ function createUseAIConversation(client) {
|
|
|
1193
1222
|
setErrorMessage(`error sending message ${reason}`);
|
|
1194
1223
|
});
|
|
1195
1224
|
}, [conversation, routeName, setRouteToConversationsMap]);
|
|
1196
|
-
const subscribe =
|
|
1225
|
+
const subscribe = React__namespace["default"].useCallback((handleStoreChange) => {
|
|
1197
1226
|
const subscription = conversation &&
|
|
1198
1227
|
conversation.onMessage((message) => {
|
|
1199
1228
|
if (input.onResponse)
|
|
@@ -1220,10 +1249,10 @@ function createUseAIConversation(client) {
|
|
|
1220
1249
|
subscription?.unsubscribe();
|
|
1221
1250
|
};
|
|
1222
1251
|
}, [conversation, routeName, setRouteToConversationsMap, input]);
|
|
1223
|
-
const getSnapshot =
|
|
1252
|
+
const getSnapshot = React__namespace["default"].useCallback(() => localMessages, [localMessages]);
|
|
1224
1253
|
// Using useSyncExternalStore to subscribe to external data updates
|
|
1225
1254
|
// Have to provide third optional argument in next - https://github.com/vercel/next.js/issues/54685
|
|
1226
|
-
const messagesFromStore =
|
|
1255
|
+
const messagesFromStore = React__namespace["default"].useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1227
1256
|
return [
|
|
1228
1257
|
{
|
|
1229
1258
|
data: { messages: messagesFromStore },
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { AIConversationInput, AIConversationProps } from './types';
|
|
3
3
|
interface AIConversationBaseProps extends AIConversationProps, AIConversationInput {
|
|
4
4
|
}
|
|
5
|
-
declare function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }: AIConversationBaseProps): JSX.Element;
|
|
5
|
+
declare function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, allowAttachments, }: AIConversationBaseProps): JSX.Element;
|
|
6
6
|
/**
|
|
7
7
|
* @experimental
|
|
8
8
|
*/
|
|
@@ -16,6 +16,7 @@ export declare const AIConversation: typeof AIConversationBase & {
|
|
|
16
16
|
}> | undefined;
|
|
17
17
|
Form: NonNullable<React.ComponentType<{
|
|
18
18
|
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
|
19
|
+
allowAttachments?: boolean | undefined;
|
|
19
20
|
} & Required<import("./context").ConversationInputContext>> | undefined>;
|
|
20
21
|
};
|
|
21
22
|
export {};
|
|
@@ -5,6 +5,7 @@ import { ConversationMessage } from '../../../types';
|
|
|
5
5
|
export interface ControlsContextProps {
|
|
6
6
|
Form?: React.ComponentType<{
|
|
7
7
|
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
|
8
|
+
allowAttachments?: boolean;
|
|
8
9
|
} & Required<ConversationInputContext>>;
|
|
9
10
|
MessageList?: React.ComponentType<{
|
|
10
11
|
messages: ConversationMessage[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AIConversationInput, AIConversationProps } from './types';
|
|
3
|
-
export default function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }: Pick<AIConversationInput, 'elements' | 'actions' | 'suggestedPrompts' | 'responseComponents' | 'variant' | 'controls' | 'displayText'>): ({ children, messages, avatars, handleSendMessage, isLoading, }: {
|
|
3
|
+
export default function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }: Pick<AIConversationInput, 'elements' | 'actions' | 'suggestedPrompts' | 'responseComponents' | 'variant' | 'controls' | 'displayText' | 'allowAttachments'>): ({ children, messages, avatars, handleSendMessage, isLoading, }: {
|
|
4
4
|
children?: React.ReactNode;
|
|
5
5
|
} & Pick<AIConversationProps, "avatars" | "messages" | "isLoading" | "handleSendMessage">) => React.JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-amplify/ui-react-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/esm/index.mjs",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"check:esm": "node --input-type=module --eval 'import \"@aws-amplify/ui-react-ai\"'",
|
|
35
35
|
"clean": "rimraf dist node_modules",
|
|
36
36
|
"dev": "yarn build:rollup --watch",
|
|
37
|
-
"lint": "yarn typecheck && eslint
|
|
37
|
+
"lint": "yarn typecheck && eslint .",
|
|
38
38
|
"prebuild": "rimraf dist",
|
|
39
39
|
"size": "yarn size-limit",
|
|
40
40
|
"test": "jest",
|
|
@@ -42,17 +42,17 @@
|
|
|
42
42
|
"typecheck": "tsc --noEmit"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"aws-amplify": "^
|
|
45
|
+
"@aws-amplify/api-graphql": "^4.3.0",
|
|
46
|
+
"aws-amplify": "^6.6.0",
|
|
46
47
|
"react": "^16.14.0 || ^17.0 || ^18.0",
|
|
47
48
|
"react-dom": "^16.14.0 || ^17.0 || ^18.0"
|
|
48
49
|
},
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@aws-amplify/ui": "^6.
|
|
51
|
-
"@aws-amplify/ui-react": "^6.
|
|
52
|
-
"@aws-amplify/ui-react-core": "^3.0.
|
|
51
|
+
"@aws-amplify/ui": "^6.6.2",
|
|
52
|
+
"@aws-amplify/ui-react": "^6.5.2",
|
|
53
|
+
"@aws-amplify/ui-react-core": "^3.0.26"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@rollup/plugin-commonjs": "^22.0.1",
|
|
56
56
|
"@types/jest-when": "^3.5.0",
|
|
57
57
|
"jest-when": "^3.5.1"
|
|
58
58
|
}
|