@aws-amplify/ui-react-ai 1.0.0 → 1.2.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.
Files changed (43) hide show
  1. package/dist/esm/components/AIConversation/AIConversationProvider.mjs +2 -2
  2. package/dist/esm/components/AIConversation/context/AttachmentContext.mjs +12 -3
  3. package/dist/esm/components/AIConversation/context/ConversationInputContext.mjs +2 -1
  4. package/dist/esm/components/AIConversation/context/elements/IconElement.mjs +2 -2
  5. package/dist/esm/components/AIConversation/context/elements/definitions.mjs +12 -12
  6. package/dist/esm/components/AIConversation/displayText.mjs +6 -0
  7. package/dist/esm/components/AIConversation/utils.mjs +42 -13
  8. package/dist/esm/components/AIConversation/views/Controls/FormControl.mjs +35 -6
  9. package/dist/esm/components/AIConversation/views/Controls/MessagesControl.mjs +3 -1
  10. package/dist/esm/components/AIConversation/views/default/Form.mjs +10 -16
  11. package/dist/esm/hooks/useAIConversation.mjs +1 -1
  12. package/dist/esm/version.mjs +1 -1
  13. package/dist/index.js +121 -51
  14. package/dist/types/components/AIConversation/AIConversationProvider.d.ts +1 -1
  15. package/dist/types/components/AIConversation/context/AIContextContext.d.ts +1 -1
  16. package/dist/types/components/AIConversation/context/ActionsContext.d.ts +1 -1
  17. package/dist/types/components/AIConversation/context/AttachmentContext.d.ts +5 -5
  18. package/dist/types/components/AIConversation/context/AvatarsContext.d.ts +1 -1
  19. package/dist/types/components/AIConversation/context/ControlsContext.d.ts +5 -4
  20. package/dist/types/components/AIConversation/context/ConversationInputContext.d.ts +5 -3
  21. package/dist/types/components/AIConversation/context/DisplayTextContext.d.ts +1 -2
  22. package/dist/types/components/AIConversation/context/FallbackComponentContext.d.ts +1 -1
  23. package/dist/types/components/AIConversation/context/LoadingContext.d.ts +1 -1
  24. package/dist/types/components/AIConversation/context/MessageRenderContext.d.ts +1 -2
  25. package/dist/types/components/AIConversation/context/MessageVariantContext.d.ts +1 -1
  26. package/dist/types/components/AIConversation/context/MessagesContext.d.ts +1 -1
  27. package/dist/types/components/AIConversation/context/ResponseComponentsContext.d.ts +1 -1
  28. package/dist/types/components/AIConversation/context/SendMessageContext.d.ts +1 -1
  29. package/dist/types/components/AIConversation/context/SuggestedPromptsContext.d.ts +1 -1
  30. package/dist/types/components/AIConversation/context/WelcomeMessageContext.d.ts +1 -1
  31. package/dist/types/components/AIConversation/context/elements/IconElement.d.ts +2 -2
  32. package/dist/types/components/AIConversation/context/elements/definitions.d.ts +11 -12
  33. package/dist/types/components/AIConversation/context/index.d.ts +2 -2
  34. package/dist/types/components/AIConversation/displayText.d.ts +2 -0
  35. package/dist/types/components/AIConversation/types.d.ts +6 -4
  36. package/dist/types/components/AIConversation/utils.d.ts +10 -0
  37. package/dist/types/components/AIConversation/views/Controls/AttachmentListControl.d.ts +5 -5
  38. package/dist/types/components/AIConversation/views/Controls/DefaultMessageControl.d.ts +2 -2
  39. package/dist/types/components/AIConversation/views/Controls/MessagesControl.d.ts +3 -3
  40. package/dist/types/components/AIConversation/views/default/Attachments.d.ts +4 -4
  41. package/dist/types/types.d.ts +0 -1
  42. package/dist/types/version.d.ts +1 -1
  43. package/package.json +8 -8
@@ -18,7 +18,7 @@ import { WelcomeMessageProvider } from './context/WelcomeMessageContext.mjs';
18
18
  import { FallbackComponentProvider } from './context/FallbackComponentContext.mjs';
19
19
  import './context/elements/definitions.mjs';
20
20
 
21
- const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }) => {
21
+ const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, maxAttachmentSize, maxAttachments, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }) => {
22
22
  const _displayText = {
23
23
  ...defaultAIConversationDisplayTextEn,
24
24
  ...displayText,
@@ -29,7 +29,7 @@ const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars,
29
29
  React__default.createElement(FallbackComponentProvider, { FallbackComponent: FallbackResponseComponent },
30
30
  React__default.createElement(MessageRendererProvider, { ...messageRenderer },
31
31
  React__default.createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
32
- React__default.createElement(AttachmentProvider, { allowAttachments: allowAttachments },
32
+ React__default.createElement(AttachmentProvider, { allowAttachments: allowAttachments, maxAttachmentSize: maxAttachmentSize, maxAttachments: maxAttachments },
33
33
  React__default.createElement(ConversationDisplayTextProvider, { ..._displayText },
34
34
  React__default.createElement(ConversationInputContextProvider, null,
35
35
  React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
@@ -1,8 +1,17 @@
1
1
  import * as React from 'react';
2
2
 
3
- const AttachmentContext = React.createContext(false);
4
- const AttachmentProvider = ({ children, allowAttachments, }) => {
5
- return (React.createElement(AttachmentContext.Provider, { value: allowAttachments ?? false }, children));
3
+ const AttachmentContext = React.createContext({
4
+ allowAttachments: false,
5
+ // We save attachments as base64 strings into dynamodb for conversation history
6
+ // DynamoDB has a max size of 400kb for records
7
+ // This can be overridden so cutsomers could provide a lower number
8
+ // or a higher number if in the future we support larger sizes.
9
+ maxAttachmentSize: 400000,
10
+ maxAttachments: 20,
11
+ });
12
+ const AttachmentProvider = ({ children, allowAttachments = false, maxAttachmentSize = 400000, maxAttachments = 20, }) => {
13
+ const providerValue = React.useMemo(() => ({ maxAttachmentSize, maxAttachments, allowAttachments }), [maxAttachmentSize, maxAttachments, allowAttachments]);
14
+ return (React.createElement(AttachmentContext.Provider, { value: providerValue }, children));
6
15
  };
7
16
 
8
17
  export { AttachmentContext, AttachmentProvider };
@@ -3,7 +3,8 @@ import React__default from 'react';
3
3
  const ConversationInputContext = React__default.createContext({});
4
4
  const ConversationInputContextProvider = ({ children, }) => {
5
5
  const [input, setInput] = React__default.useState();
6
- const providerValue = React__default.useMemo(() => ({ input, setInput }), [input, setInput]);
6
+ const [error, setError] = React__default.useState();
7
+ const providerValue = React__default.useMemo(() => ({ input, setInput, error, setError }), [input, setInput, error, setError]);
7
8
  return (React__default.createElement(ConversationInputContext.Provider, { value: providerValue }, children));
8
9
  };
9
10
 
@@ -1,4 +1,4 @@
1
- import { defineBaseElement, withBaseElementProps } from '@aws-amplify/ui-react-core/elements';
1
+ import { defineBaseElementWithRef, withBaseElementProps } from '@aws-amplify/ui-react-core/elements';
2
2
  import React__default from 'react';
3
3
 
4
4
  const DEFAULT_ICON_PATHS = {
@@ -17,7 +17,7 @@ const DEFAULT_ICON_ATTRIBUTES = {
17
17
  fill: 'none',
18
18
  xmlns: 'http://www.w3.org/2000/svg',
19
19
  };
20
- const BaseIconElement = defineBaseElement({
20
+ const BaseIconElement = defineBaseElementWithRef({
21
21
  type: 'svg',
22
22
  displayName: 'Icon',
23
23
  });
@@ -1,44 +1,44 @@
1
- import { defineBaseElement } from '@aws-amplify/ui-react-core/elements';
1
+ import { defineBaseElementWithRef } from '@aws-amplify/ui-react-core/elements';
2
2
  import { IconElement } from './IconElement.mjs';
3
3
 
4
- const LabelElement = defineBaseElement({
4
+ const LabelElement = defineBaseElementWithRef({
5
5
  type: 'label',
6
6
  displayName: 'Label',
7
7
  });
8
- const TextElement = defineBaseElement({
8
+ const TextElement = defineBaseElementWithRef({
9
9
  type: 'p',
10
10
  displayName: 'Text',
11
11
  });
12
- const UnorderedListElement = defineBaseElement({
12
+ const UnorderedListElement = defineBaseElementWithRef({
13
13
  type: 'ul',
14
14
  displayName: 'UnorderedList',
15
15
  });
16
- const ListItemElement = defineBaseElement({
16
+ const ListItemElement = defineBaseElementWithRef({
17
17
  type: 'li',
18
18
  displayName: 'ListItem',
19
19
  });
20
- const HeadingElement = defineBaseElement({
20
+ const HeadingElement = defineBaseElementWithRef({
21
21
  type: 'h2',
22
22
  displayName: 'Title',
23
23
  });
24
- const ImageElement = defineBaseElement({
24
+ const ImageElement = defineBaseElementWithRef({
25
25
  type: 'img',
26
26
  displayName: 'Image',
27
27
  });
28
- const InputElement = defineBaseElement({
28
+ const InputElement = defineBaseElementWithRef({
29
29
  type: 'input',
30
30
  displayName: 'Input',
31
31
  });
32
- const ButtonElement = defineBaseElement({ type: 'button', displayName: 'Button' });
33
- const ViewElement = defineBaseElement({
32
+ const ButtonElement = defineBaseElementWithRef({ type: 'button', displayName: 'Button' });
33
+ const ViewElement = defineBaseElementWithRef({
34
34
  type: 'div',
35
35
  displayName: 'View',
36
36
  });
37
- const SpanElement = defineBaseElement({
37
+ const SpanElement = defineBaseElementWithRef({
38
38
  type: 'span',
39
39
  displayName: 'Span',
40
40
  });
41
- const TextAreaElement = defineBaseElement({
41
+ const TextAreaElement = defineBaseElementWithRef({
42
42
  type: 'textarea',
43
43
  displayName: 'TextArea',
44
44
  });
@@ -2,6 +2,12 @@ import { formatDate } from './utils.mjs';
2
2
 
3
3
  const defaultAIConversationDisplayTextEn = {
4
4
  getMessageTimestampText: (date) => formatDate(date),
5
+ getMaxAttachmentErrorText(count) {
6
+ return `Cannot choose more than ${count} ${count === 1 ? 'file' : 'files'}. `;
7
+ },
8
+ getAttachmentSizeErrorText(sizeText) {
9
+ return `File size must be below ${sizeText}.`;
10
+ },
5
11
  };
6
12
 
7
13
  export { defaultAIConversationDisplayTextEn };
@@ -12,28 +12,57 @@ function formatDate(date) {
12
12
  return `${dateString} at ${timeString}`;
13
13
  }
14
14
  function arrayBufferToBase64(buffer) {
15
- let binary = '';
16
- const bytes = new Uint8Array(buffer);
17
- const len = bytes.byteLength;
18
- for (let i = 0; i < len; i++) {
19
- binary += String.fromCharCode(bytes[i]);
20
- }
21
- return window.btoa(binary);
22
- }
23
- function convertBufferToBase64(buffer, format) {
24
- let base64string = '';
25
15
  // Use node-based buffer if available
26
16
  // fall back on browser if not
27
17
  if (typeof Buffer !== 'undefined') {
28
- base64string = Buffer.from(new Uint8Array(buffer)).toString('base64');
18
+ return Buffer.from(new Uint8Array(buffer)).toString('base64');
29
19
  }
30
20
  else {
31
- base64string = arrayBufferToBase64(buffer);
21
+ let binary = '';
22
+ const bytes = new Uint8Array(buffer);
23
+ const len = bytes.byteLength;
24
+ for (let i = 0; i < len; i++) {
25
+ binary += String.fromCharCode(bytes[i]);
26
+ }
27
+ return window.btoa(binary);
32
28
  }
29
+ }
30
+ function convertBufferToBase64(buffer, format) {
31
+ const base64string = arrayBufferToBase64(buffer);
33
32
  return `data:image/${format};base64,${base64string}`;
34
33
  }
35
34
  function getImageTypeFromMimeType(mimeType) {
36
35
  return mimeType.split('/')[1];
37
36
  }
37
+ async function attachmentsValidator({ files, maxAttachments, maxAttachmentSize, }) {
38
+ const acceptedFiles = [];
39
+ const rejectedFiles = [];
40
+ let hasMaxSizeError = false;
41
+ for (const file of files) {
42
+ const arrayBuffer = await file.arrayBuffer();
43
+ const base64 = arrayBufferToBase64(arrayBuffer);
44
+ if (base64.length < maxAttachmentSize) {
45
+ acceptedFiles.push(file);
46
+ }
47
+ else {
48
+ rejectedFiles.push(file);
49
+ hasMaxSizeError = true;
50
+ }
51
+ }
52
+ if (acceptedFiles.length > maxAttachments) {
53
+ return {
54
+ acceptedFiles: acceptedFiles.slice(0, maxAttachments),
55
+ rejectedFiles: [...acceptedFiles.slice(maxAttachments), ...rejectedFiles],
56
+ hasMaxAttachmentsError: true,
57
+ hasMaxAttachmentSizeError: hasMaxSizeError,
58
+ };
59
+ }
60
+ return {
61
+ acceptedFiles,
62
+ rejectedFiles,
63
+ hasMaxAttachmentsError: false,
64
+ hasMaxAttachmentSizeError: hasMaxSizeError,
65
+ };
66
+ }
38
67
 
39
- export { convertBufferToBase64, formatDate, getImageTypeFromMimeType };
68
+ export { attachmentsValidator, convertBufferToBase64, formatDate, getImageTypeFromMimeType };
@@ -7,7 +7,7 @@ import { ConversationInputContext } from '../../context/ConversationInputContext
7
7
  import { MessagesContext } from '../../context/MessagesContext.mjs';
8
8
  import '../../context/SuggestedPromptsContext.mjs';
9
9
  import '../../context/MessageVariantContext.mjs';
10
- import '../../context/DisplayTextContext.mjs';
10
+ import { useConversationDisplayText } from '../../context/DisplayTextContext.mjs';
11
11
  import { ControlsContext } from '../../context/ControlsContext.mjs';
12
12
  import { LoadingContext } from '../../context/LoadingContext.mjs';
13
13
  import { ResponseComponentsContext, convertResponseComponentsToToolConfiguration } from '../../context/ResponseComponentsContext.mjs';
@@ -19,8 +19,8 @@ import '../../context/FallbackComponentContext.mjs';
19
19
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
20
20
  import { AttachFileControl } from './AttachFileControl.mjs';
21
21
  import { AttachmentListControl } from './AttachmentListControl.mjs';
22
- import { getImageTypeFromMimeType } from '../../utils.mjs';
23
- import { isFunction } from '@aws-amplify/ui';
22
+ import { attachmentsValidator, getImageTypeFromMimeType } from '../../utils.mjs';
23
+ import { humanFileSize, isFunction } from '@aws-amplify/ui';
24
24
 
25
25
  const { Button, Icon, Label: LabelElement, TextArea, View, } = AIConversationElements;
26
26
  const FIELD_BLOCK = 'ai-field';
@@ -103,9 +103,10 @@ const InputContainer = withBaseElementProps(View, {
103
103
  className: `${FIELD_BLOCK}__input-container`,
104
104
  });
105
105
  const FormControl = () => {
106
- const { input, setInput } = React__default.useContext(ConversationInputContext);
106
+ const { input, setInput, error, setError } = React__default.useContext(ConversationInputContext);
107
107
  const handleSendMessage = React__default.useContext(SendMessageContext);
108
- const allowAttachments = React__default.useContext(AttachmentContext);
108
+ const { allowAttachments, maxAttachmentSize, maxAttachments } = React__default.useContext(AttachmentContext);
109
+ const displayText = useConversationDisplayText();
109
110
  const responseComponents = React__default.useContext(ResponseComponentsContext);
110
111
  const isLoading = React__default.useContext(LoadingContext);
111
112
  const aiContext = React__default.useContext(AIContextContext);
@@ -157,8 +158,36 @@ const FormControl = () => {
157
158
  }
158
159
  }
159
160
  };
161
+ const onValidate = React__default.useCallback(async (files) => {
162
+ const previousFiles = input?.files ?? [];
163
+ const { acceptedFiles, hasMaxAttachmentsError, hasMaxAttachmentSizeError, } = await attachmentsValidator({
164
+ files: [...files, ...previousFiles],
165
+ maxAttachments,
166
+ maxAttachmentSize,
167
+ });
168
+ if (hasMaxAttachmentsError || hasMaxAttachmentSizeError) {
169
+ const errors = [];
170
+ if (hasMaxAttachmentsError) {
171
+ errors.push(displayText.getMaxAttachmentErrorText(maxAttachments));
172
+ }
173
+ if (hasMaxAttachmentSizeError) {
174
+ errors.push(displayText.getAttachmentSizeErrorText(
175
+ // base64 size is about 137% that of the file size
176
+ // https://en.wikipedia.org/wiki/Base64#MIME
177
+ humanFileSize((maxAttachmentSize - 814) / 1.37, true)));
178
+ }
179
+ setError?.(errors.join(' '));
180
+ }
181
+ else {
182
+ setError?.(undefined);
183
+ }
184
+ setInput?.((prevValue) => ({
185
+ ...prevValue,
186
+ files: acceptedFiles,
187
+ }));
188
+ }, [setInput, input, displayText, maxAttachmentSize, maxAttachments, setError]);
160
189
  if (controls?.Form) {
161
- return (React__default.createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, allowAttachments: allowAttachments, isLoading: isLoading }));
190
+ return (React__default.createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, onValidate: onValidate, allowAttachments: allowAttachments, isLoading: isLoading, error: error, setError: setError }));
162
191
  }
163
192
  return (React__default.createElement("form", { className: `${FIELD_BLOCK}__form`, onSubmit: handleSubmit, method: "post", ref: ref },
164
193
  allowAttachments ? React__default.createElement(AttachFileControl, null) : null,
@@ -126,7 +126,9 @@ const MessagesControl = () => {
126
126
  content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
127
127
  return (React__default.createElement(Layout, null, messagesWithRenderableContent?.map((message, index) => {
128
128
  return (React__default.createElement(RoleContext.Provider, { value: message.role, key: `message-${index}` },
129
- React__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) },
129
+ React__default.createElement(MessageContainer, { "data-testid": `message`, key: `message-${index}`, tabIndex: focusedItemIndex === index ? 0 : -1, onFocus: () => handleFocus(index), onKeyDown: (event) => onKeyDown(index, event), ref: (el) => {
130
+ messagesRef.current[index] = el;
131
+ } },
130
132
  React__default.createElement(HeaderContainer, null,
131
133
  React__default.createElement(AvatarControl, null),
132
134
  React__default.createElement(Timestamp, null, getMessageTimestampText(new Date(message.createdAt)))),
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { View, Button, VisuallyHidden, TextAreaField, DropZone } from '@aws-amplify/ui-react';
2
+ import { View, Button, VisuallyHidden, TextAreaField, Message, 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';
@@ -11,27 +11,24 @@ function isHTMLFormElement(target) {
11
11
  * Will conditionally render the DropZone if allowAttachments
12
12
  * is true
13
13
  */
14
- const FormWrapper = ({ children, allowAttachments, setInput, }) => {
14
+ const FormWrapper = ({ children, allowAttachments, onValidate, }) => {
15
15
  if (allowAttachments) {
16
16
  return (React.createElement(DropZone, { className: ComponentClassName.AIConversationFormDropzone, onDropComplete: ({ acceptedFiles }) => {
17
- setInput?.((prevInput) => ({
18
- ...prevInput,
19
- files: [...(prevInput?.files ?? []), ...acceptedFiles],
20
- }));
17
+ onValidate(acceptedFiles);
21
18
  } }, children));
22
19
  }
23
20
  else {
24
21
  return children;
25
22
  }
26
23
  };
27
- const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) => {
24
+ const Form = ({ setInput, input, handleSubmit, allowAttachments, onValidate, isLoading, error, }) => {
28
25
  const icons = useIcons('aiConversation');
29
26
  const sendIcon = icons?.send ?? React.createElement(IconSend, null);
30
27
  const attachIcon = icons?.attach ?? React.createElement(IconAttach, null);
31
28
  const hiddenInput = React.useRef(null);
32
29
  const [composing, setComposing] = React.useState(false);
33
30
  const isInputEmpty = !input?.text?.length && !input?.files?.length;
34
- return (React.createElement(FormWrapper, { allowAttachments: allowAttachments, setInput: setInput },
31
+ return (React.createElement(FormWrapper, { onValidate: onValidate, allowAttachments: allowAttachments },
35
32
  React.createElement(View, { as: "form", className: ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
36
33
  allowAttachments ? (React.createElement(Button, { className: ComponentClassName.AIConversationFormAttach, onClick: () => {
37
34
  hiddenInput?.current?.click();
@@ -42,15 +39,11 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
42
39
  React.createElement("span", null, attachIcon),
43
40
  React.createElement(VisuallyHidden, null,
44
41
  React.createElement("input", { type: "file", tabIndex: -1, ref: hiddenInput, onChange: (e) => {
45
- const { files } = e.target;
46
- if (!files || files.length === 0) {
42
+ if (!e.target.files || e.target.files.length === 0) {
47
43
  return;
48
44
  }
49
- setInput((prevValue) => ({
50
- ...prevValue,
51
- files: [...(prevValue?.files ?? []), ...Array.from(files)],
52
- }));
53
- }, multiple: true, accept: "*", "data-testid": "hidden-file-input" })))) : null,
45
+ onValidate(Array.from(e.target.files));
46
+ }, multiple: true, accept: ".jpeg,.png,.webp,.gif", "data-testid": "hidden-file-input" })))) : null,
54
47
  React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onCompositionStart: () => setComposing(true), onCompositionEnd: () => setComposing(false), onKeyDown: (e) => {
55
48
  // Submit on enter key if shift is not pressed also
56
49
  const shouldSubmit = !e.shiftKey && e.key === 'Enter' && !composing;
@@ -59,7 +52,7 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
59
52
  e.preventDefault();
60
53
  }
61
54
  }, onChange: (e) => {
62
- setInput((prevValue) => ({
55
+ setInput?.((prevValue) => ({
63
56
  ...prevValue,
64
57
  text: e.target.value,
65
58
  }));
@@ -69,6 +62,7 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
69
62
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
70
63
  isDisabled: isLoading || isInputEmpty },
71
64
  React.createElement("span", null, sendIcon))),
65
+ error ? (React.createElement(Message, { className: ComponentClassName.AIConversationFormError, variation: "plain", colorTheme: "warning" }, error)) : null,
72
66
  React.createElement(Attachments, { setInput: setInput, files: input?.files })));
73
67
  };
74
68
 
@@ -22,7 +22,7 @@ function createUseAIConversation(client) {
22
22
  const clientRoute = client.conversations[routeName];
23
23
  // We need to keep track of the stream events as the come in
24
24
  // for an assistant message, but don't need to keep them in state
25
- const contentBlocksRef = React__default.useRef();
25
+ const contentBlocksRef = React__default.useRef(undefined);
26
26
  // Using this hook without an existing conversation id means
27
27
  // it will create a new conversation when it is executed
28
28
  // we don't want to create 2 conversations
@@ -1,3 +1,3 @@
1
- const VERSION = '1.0.0';
1
+ const VERSION = '1.2.0';
2
2
 
3
3
  export { VERSION };
package/dist/index.js CHANGED
@@ -47,7 +47,8 @@ const AvatarsProvider = ({ children, avatars, }) => {
47
47
  const ConversationInputContext = React__namespace["default"].createContext({});
48
48
  const ConversationInputContextProvider = ({ children, }) => {
49
49
  const [input, setInput] = React__namespace["default"].useState();
50
- const providerValue = React__namespace["default"].useMemo(() => ({ input, setInput }), [input, setInput]);
50
+ const [error, setError] = React__namespace["default"].useState();
51
+ const providerValue = React__namespace["default"].useMemo(() => ({ input, setInput, error, setError }), [input, setInput, error, setError]);
51
52
  return (React__namespace["default"].createElement(ConversationInputContext.Provider, { value: providerValue }, children));
52
53
  };
53
54
 
@@ -82,32 +83,67 @@ function formatDate(date) {
82
83
  return `${dateString} at ${timeString}`;
83
84
  }
84
85
  function arrayBufferToBase64(buffer) {
85
- let binary = '';
86
- const bytes = new Uint8Array(buffer);
87
- const len = bytes.byteLength;
88
- for (let i = 0; i < len; i++) {
89
- binary += String.fromCharCode(bytes[i]);
90
- }
91
- return window.btoa(binary);
92
- }
93
- function convertBufferToBase64(buffer, format) {
94
- let base64string = '';
95
86
  // Use node-based buffer if available
96
87
  // fall back on browser if not
97
88
  if (typeof Buffer !== 'undefined') {
98
- base64string = Buffer.from(new Uint8Array(buffer)).toString('base64');
89
+ return Buffer.from(new Uint8Array(buffer)).toString('base64');
99
90
  }
100
91
  else {
101
- base64string = arrayBufferToBase64(buffer);
92
+ let binary = '';
93
+ const bytes = new Uint8Array(buffer);
94
+ const len = bytes.byteLength;
95
+ for (let i = 0; i < len; i++) {
96
+ binary += String.fromCharCode(bytes[i]);
97
+ }
98
+ return window.btoa(binary);
102
99
  }
100
+ }
101
+ function convertBufferToBase64(buffer, format) {
102
+ const base64string = arrayBufferToBase64(buffer);
103
103
  return `data:image/${format};base64,${base64string}`;
104
104
  }
105
105
  function getImageTypeFromMimeType(mimeType) {
106
106
  return mimeType.split('/')[1];
107
107
  }
108
+ async function attachmentsValidator({ files, maxAttachments, maxAttachmentSize, }) {
109
+ const acceptedFiles = [];
110
+ const rejectedFiles = [];
111
+ let hasMaxSizeError = false;
112
+ for (const file of files) {
113
+ const arrayBuffer = await file.arrayBuffer();
114
+ const base64 = arrayBufferToBase64(arrayBuffer);
115
+ if (base64.length < maxAttachmentSize) {
116
+ acceptedFiles.push(file);
117
+ }
118
+ else {
119
+ rejectedFiles.push(file);
120
+ hasMaxSizeError = true;
121
+ }
122
+ }
123
+ if (acceptedFiles.length > maxAttachments) {
124
+ return {
125
+ acceptedFiles: acceptedFiles.slice(0, maxAttachments),
126
+ rejectedFiles: [...acceptedFiles.slice(maxAttachments), ...rejectedFiles],
127
+ hasMaxAttachmentsError: true,
128
+ hasMaxAttachmentSizeError: hasMaxSizeError,
129
+ };
130
+ }
131
+ return {
132
+ acceptedFiles,
133
+ rejectedFiles,
134
+ hasMaxAttachmentsError: false,
135
+ hasMaxAttachmentSizeError: hasMaxSizeError,
136
+ };
137
+ }
108
138
 
109
139
  const defaultAIConversationDisplayTextEn = {
110
140
  getMessageTimestampText: (date) => formatDate(date),
141
+ getMaxAttachmentErrorText(count) {
142
+ return `Cannot choose more than ${count} ${count === 1 ? 'file' : 'files'}. `;
143
+ },
144
+ getAttachmentSizeErrorText(sizeText) {
145
+ return `File size must be below ${sizeText}.`;
146
+ },
111
147
  };
112
148
 
113
149
  const { ConversationDisplayTextContext, ConversationDisplayTextProvider, useConversationDisplayText, } = uiReactCore.createContextUtilities({
@@ -180,9 +216,18 @@ const { MessageRendererContext, MessageRendererProvider, useMessageRenderer, } =
180
216
  errorMessage: '`useMessageRenderer` must be used with an AIConversation component',
181
217
  });
182
218
 
183
- const AttachmentContext = React__namespace.createContext(false);
184
- const AttachmentProvider = ({ children, allowAttachments, }) => {
185
- return (React__namespace.createElement(AttachmentContext.Provider, { value: allowAttachments ?? false }, children));
219
+ const AttachmentContext = React__namespace.createContext({
220
+ allowAttachments: false,
221
+ // We save attachments as base64 strings into dynamodb for conversation history
222
+ // DynamoDB has a max size of 400kb for records
223
+ // This can be overridden so cutsomers could provide a lower number
224
+ // or a higher number if in the future we support larger sizes.
225
+ maxAttachmentSize: 400000,
226
+ maxAttachments: 20,
227
+ });
228
+ const AttachmentProvider = ({ children, allowAttachments = false, maxAttachmentSize = 400000, maxAttachments = 20, }) => {
229
+ const providerValue = React__namespace.useMemo(() => ({ maxAttachmentSize, maxAttachments, allowAttachments }), [maxAttachmentSize, maxAttachments, allowAttachments]);
230
+ return (React__namespace.createElement(AttachmentContext.Provider, { value: providerValue }, children));
186
231
  };
187
232
 
188
233
  const WelcomeMessageContext = React__namespace.createContext(undefined);
@@ -211,7 +256,7 @@ const DEFAULT_ICON_ATTRIBUTES = {
211
256
  fill: 'none',
212
257
  xmlns: 'http://www.w3.org/2000/svg',
213
258
  };
214
- const BaseIconElement = elements.defineBaseElement({
259
+ const BaseIconElement = elements.defineBaseElementWithRef({
215
260
  type: 'svg',
216
261
  displayName: 'Icon',
217
262
  });
@@ -227,44 +272,44 @@ const getIconProps = ({ variant, ...props }) => {
227
272
  };
228
273
  const IconElement = elements.withBaseElementProps(BaseIconElement, getIconProps);
229
274
 
230
- const LabelElement$1 = elements.defineBaseElement({
275
+ const LabelElement$1 = elements.defineBaseElementWithRef({
231
276
  type: 'label',
232
277
  displayName: 'Label',
233
278
  });
234
- const TextElement = elements.defineBaseElement({
279
+ const TextElement = elements.defineBaseElementWithRef({
235
280
  type: 'p',
236
281
  displayName: 'Text',
237
282
  });
238
- const UnorderedListElement = elements.defineBaseElement({
283
+ const UnorderedListElement = elements.defineBaseElementWithRef({
239
284
  type: 'ul',
240
285
  displayName: 'UnorderedList',
241
286
  });
242
- const ListItemElement = elements.defineBaseElement({
287
+ const ListItemElement = elements.defineBaseElementWithRef({
243
288
  type: 'li',
244
289
  displayName: 'ListItem',
245
290
  });
246
- const HeadingElement = elements.defineBaseElement({
291
+ const HeadingElement = elements.defineBaseElementWithRef({
247
292
  type: 'h2',
248
293
  displayName: 'Title',
249
294
  });
250
- const ImageElement = elements.defineBaseElement({
295
+ const ImageElement = elements.defineBaseElementWithRef({
251
296
  type: 'img',
252
297
  displayName: 'Image',
253
298
  });
254
- const InputElement = elements.defineBaseElement({
299
+ const InputElement = elements.defineBaseElementWithRef({
255
300
  type: 'input',
256
301
  displayName: 'Input',
257
302
  });
258
- const ButtonElement = elements.defineBaseElement({ type: 'button', displayName: 'Button' });
259
- const ViewElement = elements.defineBaseElement({
303
+ const ButtonElement = elements.defineBaseElementWithRef({ type: 'button', displayName: 'Button' });
304
+ const ViewElement = elements.defineBaseElementWithRef({
260
305
  type: 'div',
261
306
  displayName: 'View',
262
307
  });
263
- const SpanElement = elements.defineBaseElement({
308
+ const SpanElement = elements.defineBaseElementWithRef({
264
309
  type: 'span',
265
310
  displayName: 'Span',
266
311
  });
267
- const TextAreaElement = elements.defineBaseElement({
312
+ const TextAreaElement = elements.defineBaseElementWithRef({
268
313
  type: 'textarea',
269
314
  displayName: 'TextArea',
270
315
  });
@@ -561,9 +606,10 @@ const InputContainer = elements.withBaseElementProps(View$2, {
561
606
  className: `${FIELD_BLOCK}__input-container`,
562
607
  });
563
608
  const FormControl = () => {
564
- const { input, setInput } = React__namespace["default"].useContext(ConversationInputContext);
609
+ const { input, setInput, error, setError } = React__namespace["default"].useContext(ConversationInputContext);
565
610
  const handleSendMessage = React__namespace["default"].useContext(SendMessageContext);
566
- const allowAttachments = React__namespace["default"].useContext(AttachmentContext);
611
+ const { allowAttachments, maxAttachmentSize, maxAttachments } = React__namespace["default"].useContext(AttachmentContext);
612
+ const displayText = useConversationDisplayText();
567
613
  const responseComponents = React__namespace["default"].useContext(ResponseComponentsContext);
568
614
  const isLoading = React__namespace["default"].useContext(LoadingContext);
569
615
  const aiContext = React__namespace["default"].useContext(AIContextContext);
@@ -615,8 +661,36 @@ const FormControl = () => {
615
661
  }
616
662
  }
617
663
  };
664
+ const onValidate = React__namespace["default"].useCallback(async (files) => {
665
+ const previousFiles = input?.files ?? [];
666
+ const { acceptedFiles, hasMaxAttachmentsError, hasMaxAttachmentSizeError, } = await attachmentsValidator({
667
+ files: [...files, ...previousFiles],
668
+ maxAttachments,
669
+ maxAttachmentSize,
670
+ });
671
+ if (hasMaxAttachmentsError || hasMaxAttachmentSizeError) {
672
+ const errors = [];
673
+ if (hasMaxAttachmentsError) {
674
+ errors.push(displayText.getMaxAttachmentErrorText(maxAttachments));
675
+ }
676
+ if (hasMaxAttachmentSizeError) {
677
+ errors.push(displayText.getAttachmentSizeErrorText(
678
+ // base64 size is about 137% that of the file size
679
+ // https://en.wikipedia.org/wiki/Base64#MIME
680
+ ui.humanFileSize((maxAttachmentSize - 814) / 1.37, true)));
681
+ }
682
+ setError?.(errors.join(' '));
683
+ }
684
+ else {
685
+ setError?.(undefined);
686
+ }
687
+ setInput?.((prevValue) => ({
688
+ ...prevValue,
689
+ files: acceptedFiles,
690
+ }));
691
+ }, [setInput, input, displayText, maxAttachmentSize, maxAttachments, setError]);
618
692
  if (controls?.Form) {
619
- return (React__namespace["default"].createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, allowAttachments: allowAttachments, isLoading: isLoading }));
693
+ return (React__namespace["default"].createElement(controls.Form, { handleSubmit: handleSubmit, input: input, setInput: setInput, onValidate: onValidate, allowAttachments: allowAttachments, isLoading: isLoading, error: error, setError: setError }));
620
694
  }
621
695
  return (React__namespace["default"].createElement("form", { className: `${FIELD_BLOCK}__form`, onSubmit: handleSubmit, method: "post", ref: ref },
622
696
  allowAttachments ? React__namespace["default"].createElement(AttachFileControl, null) : null,
@@ -738,7 +812,9 @@ const MessagesControl = () => {
738
812
  content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
739
813
  return (React__namespace["default"].createElement(Layout, null, messagesWithRenderableContent?.map((message, index) => {
740
814
  return (React__namespace["default"].createElement(RoleContext.Provider, { value: message.role, key: `message-${index}` },
741
- 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) },
815
+ 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) => {
816
+ messagesRef.current[index] = el;
817
+ } },
742
818
  React__namespace["default"].createElement(HeaderContainer, null,
743
819
  React__namespace["default"].createElement(AvatarControl, null),
744
820
  React__namespace["default"].createElement(Timestamp, null, getMessageTimestampText(new Date(message.createdAt)))),
@@ -795,7 +871,7 @@ PromptControl.Container = Container;
795
871
  PromptControl.PromptGroup = PromptGroup;
796
872
  PromptControl.PromptCard = PromptCard;
797
873
 
798
- const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }) => {
874
+ const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, maxAttachmentSize, maxAttachments, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }) => {
799
875
  const _displayText = {
800
876
  ...defaultAIConversationDisplayTextEn,
801
877
  ...displayText,
@@ -806,7 +882,7 @@ const AIConversationProvider = ({ aiContext, actions, allowAttachments, avatars,
806
882
  React__namespace["default"].createElement(FallbackComponentProvider, { FallbackComponent: FallbackResponseComponent },
807
883
  React__namespace["default"].createElement(MessageRendererProvider, { ...messageRenderer },
808
884
  React__namespace["default"].createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
809
- React__namespace["default"].createElement(AttachmentProvider, { allowAttachments: allowAttachments },
885
+ React__namespace["default"].createElement(AttachmentProvider, { allowAttachments: allowAttachments, maxAttachmentSize: maxAttachmentSize, maxAttachments: maxAttachments },
810
886
  React__namespace["default"].createElement(ConversationDisplayTextProvider, { ..._displayText },
811
887
  React__namespace["default"].createElement(ConversationInputContextProvider, null,
812
888
  React__namespace["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
@@ -950,27 +1026,24 @@ function isHTMLFormElement(target) {
950
1026
  * Will conditionally render the DropZone if allowAttachments
951
1027
  * is true
952
1028
  */
953
- const FormWrapper = ({ children, allowAttachments, setInput, }) => {
1029
+ const FormWrapper = ({ children, allowAttachments, onValidate, }) => {
954
1030
  if (allowAttachments) {
955
1031
  return (React__namespace.createElement(uiReact.DropZone, { className: ui.ComponentClassName.AIConversationFormDropzone, onDropComplete: ({ acceptedFiles }) => {
956
- setInput?.((prevInput) => ({
957
- ...prevInput,
958
- files: [...(prevInput?.files ?? []), ...acceptedFiles],
959
- }));
1032
+ onValidate(acceptedFiles);
960
1033
  } }, children));
961
1034
  }
962
1035
  else {
963
1036
  return children;
964
1037
  }
965
1038
  };
966
- const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) => {
1039
+ const Form = ({ setInput, input, handleSubmit, allowAttachments, onValidate, isLoading, error, }) => {
967
1040
  const icons = internal.useIcons('aiConversation');
968
1041
  const sendIcon = icons?.send ?? React__namespace.createElement(internal.IconSend, null);
969
1042
  const attachIcon = icons?.attach ?? React__namespace.createElement(internal.IconAttach, null);
970
1043
  const hiddenInput = React__namespace.useRef(null);
971
1044
  const [composing, setComposing] = React__namespace.useState(false);
972
1045
  const isInputEmpty = !input?.text?.length && !input?.files?.length;
973
- return (React__namespace.createElement(FormWrapper, { allowAttachments: allowAttachments, setInput: setInput },
1046
+ return (React__namespace.createElement(FormWrapper, { onValidate: onValidate, allowAttachments: allowAttachments },
974
1047
  React__namespace.createElement(uiReact.View, { as: "form", className: ui.ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
975
1048
  allowAttachments ? (React__namespace.createElement(uiReact.Button, { className: ui.ComponentClassName.AIConversationFormAttach, onClick: () => {
976
1049
  hiddenInput?.current?.click();
@@ -981,15 +1054,11 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
981
1054
  React__namespace.createElement("span", null, attachIcon),
982
1055
  React__namespace.createElement(uiReact.VisuallyHidden, null,
983
1056
  React__namespace.createElement("input", { type: "file", tabIndex: -1, ref: hiddenInput, onChange: (e) => {
984
- const { files } = e.target;
985
- if (!files || files.length === 0) {
1057
+ if (!e.target.files || e.target.files.length === 0) {
986
1058
  return;
987
1059
  }
988
- setInput((prevValue) => ({
989
- ...prevValue,
990
- files: [...(prevValue?.files ?? []), ...Array.from(files)],
991
- }));
992
- }, multiple: true, accept: "*", "data-testid": "hidden-file-input" })))) : null,
1060
+ onValidate(Array.from(e.target.files));
1061
+ }, multiple: true, accept: ".jpeg,.png,.webp,.gif", "data-testid": "hidden-file-input" })))) : null,
993
1062
  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", onCompositionStart: () => setComposing(true), onCompositionEnd: () => setComposing(false), onKeyDown: (e) => {
994
1063
  // Submit on enter key if shift is not pressed also
995
1064
  const shouldSubmit = !e.shiftKey && e.key === 'Enter' && !composing;
@@ -998,7 +1067,7 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
998
1067
  e.preventDefault();
999
1068
  }
1000
1069
  }, onChange: (e) => {
1001
- setInput((prevValue) => ({
1070
+ setInput?.((prevValue) => ({
1002
1071
  ...prevValue,
1003
1072
  text: e.target.value,
1004
1073
  }));
@@ -1008,6 +1077,7 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, isLoading, }) =
1008
1077
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
1009
1078
  isDisabled: isLoading || isInputEmpty },
1010
1079
  React__namespace.createElement("span", null, sendIcon))),
1080
+ error ? (React__namespace.createElement(uiReact.Message, { className: ui.ComponentClassName.AIConversationFormError, variation: "plain", colorTheme: "warning" }, error)) : null,
1011
1081
  React__namespace.createElement(Attachments, { setInput: setInput, files: input?.files })));
1012
1082
  };
1013
1083
 
@@ -1022,7 +1092,7 @@ const PromptList = ({ setInput, suggestedPrompts = [], }) => {
1022
1092
  })));
1023
1093
  };
1024
1094
 
1025
- const VERSION = '1.0.0';
1095
+ const VERSION = '1.2.0';
1026
1096
 
1027
1097
  function AIConversationBase({ avatars, controls, ...rest }) {
1028
1098
  uiReactCore.useSetUserAgent({
@@ -1164,7 +1234,7 @@ function createUseAIConversation(client) {
1164
1234
  const clientRoute = client.conversations[routeName];
1165
1235
  // We need to keep track of the stream events as the come in
1166
1236
  // for an assistant message, but don't need to keep them in state
1167
- const contentBlocksRef = React__namespace["default"].useRef();
1237
+ const contentBlocksRef = React__namespace["default"].useRef(undefined);
1168
1238
  // Using this hook without an existing conversation id means
1169
1239
  // it will create a new conversation when it is executed
1170
1240
  // we don't want to create 2 conversations
@@ -3,4 +3,4 @@ import { AIConversationInput, AIConversationProps } from './types';
3
3
  export interface AIConversationProviderProps extends AIConversationInput, AIConversationProps {
4
4
  children?: React.ReactNode;
5
5
  }
6
- export declare const AIConversationProvider: ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }: AIConversationProviderProps) => React.JSX.Element;
6
+ export declare const AIConversationProvider: ({ aiContext, actions, allowAttachments, avatars, children, controls, displayText, handleSendMessage, isLoading, maxAttachmentSize, maxAttachments, messages, messageRenderer, responseComponents, suggestedPrompts, variant, welcomeMessage, FallbackResponseComponent, }: AIConversationProviderProps) => React.JSX.Element;
@@ -3,4 +3,4 @@ export declare const AIContextContext: React.Context<(() => object) | undefined>
3
3
  export declare const AIContextProvider: ({ children, aiContext, }: {
4
4
  children?: React.ReactNode;
5
5
  aiContext?: (() => object) | undefined;
6
- }) => JSX.Element;
6
+ }) => React.JSX.Element;
@@ -4,4 +4,4 @@ export declare const ActionsContext: React.Context<CustomAction[] | undefined>;
4
4
  export declare const ActionsProvider: ({ children, actions, }: {
5
5
  children?: React.ReactNode;
6
6
  actions?: CustomAction[] | undefined;
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- export declare const AttachmentContext: React.Context<boolean>;
3
- export declare const AttachmentProvider: ({ children, allowAttachments, }: {
4
- children?: React.ReactNode;
5
- allowAttachments?: boolean | undefined;
6
- }) => JSX.Element;
2
+ import { AIConversationInput } from '../types';
3
+ export interface AttachmentContextProps extends Pick<AIConversationInput, 'allowAttachments' | 'maxAttachments' | 'maxAttachmentSize'> {
4
+ }
5
+ export declare const AttachmentContext: React.Context<Required<AttachmentContextProps>>;
6
+ export declare const AttachmentProvider: ({ children, allowAttachments, maxAttachmentSize, maxAttachments, }: React.PropsWithChildren<AttachmentContextProps>) => React.JSX.Element;
@@ -4,4 +4,4 @@ export declare const AvatarsContext: React.Context<Avatars | undefined>;
4
4
  export declare const AvatarsProvider: ({ children, avatars, }: {
5
5
  children?: React.ReactNode;
6
6
  avatars?: Avatars | undefined;
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ConversationInputContext } from './ConversationInputContext';
2
+ import { ConversationInputContextProps } from './ConversationInputContext';
3
3
  import { SuggestedPrompt } from '../types';
4
4
  import { ConversationMessage } from '../../../types';
5
5
  export interface ControlsContextProps {
@@ -7,17 +7,18 @@ export interface ControlsContextProps {
7
7
  handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
8
8
  allowAttachments?: boolean;
9
9
  isLoading?: boolean;
10
- } & Required<ConversationInputContext>>;
10
+ onValidate: (files: File[]) => Promise<void>;
11
+ } & ConversationInputContextProps>;
11
12
  MessageList?: React.ComponentType<{
12
13
  messages: ConversationMessage[];
13
14
  }>;
14
15
  PromptList?: React.ComponentType<{
15
16
  suggestedPrompts?: SuggestedPrompt[];
16
- setInput: ConversationInputContext['setInput'];
17
+ setInput: ConversationInputContextProps['setInput'];
17
18
  }>;
18
19
  }
19
20
  export declare const ControlsContext: React.Context<ControlsContextProps | undefined>;
20
21
  export declare const ControlsProvider: ({ children, controls, }: {
21
22
  children?: React.ReactNode;
22
23
  controls?: ControlsContextProps | undefined;
23
- }) => JSX.Element;
24
+ }) => React.JSX.Element;
@@ -3,11 +3,13 @@ export interface ConversationInput {
3
3
  text?: string;
4
4
  files?: File[];
5
5
  }
6
- export interface ConversationInputContext {
6
+ export interface ConversationInputContextProps {
7
7
  input?: ConversationInput;
8
8
  setInput?: React.Dispatch<React.SetStateAction<ConversationInput | undefined>>;
9
+ error?: string;
10
+ setError?: React.Dispatch<React.SetStateAction<string | undefined>>;
9
11
  }
10
- export declare const ConversationInputContext: React.Context<ConversationInputContext>;
12
+ export declare const ConversationInputContext: React.Context<ConversationInputContextProps>;
11
13
  export declare const ConversationInputContextProvider: ({ children, }: {
12
14
  children?: React.ReactNode;
13
- }) => JSX.Element;
15
+ }) => React.JSX.Element;
@@ -1,5 +1,4 @@
1
- /// <reference types="react" />
2
1
  import { ConversationDisplayText } from '../displayText';
3
- export declare const ConversationDisplayTextContext: import("react").Context<Required<ConversationDisplayText> | undefined>, ConversationDisplayTextProvider: import("react").ComponentType<import("react").PropsWithChildren<Required<ConversationDisplayText>>>, useConversationDisplayText: (params?: {
2
+ export declare const ConversationDisplayTextContext: import("react").Context<Required<ConversationDisplayText>>, ConversationDisplayTextProvider: import("react").ComponentType<import("react").PropsWithChildren<Required<ConversationDisplayText>>>, useConversationDisplayText: (params?: {
4
3
  errorMessage?: string | undefined;
5
4
  } | undefined) => Required<ConversationDisplayText>;
@@ -4,4 +4,4 @@ export declare const FallbackComponentContext: React.Context<React.ComponentType
4
4
  export declare const FallbackComponentProvider: ({ children, FallbackComponent, }: {
5
5
  children?: React.ReactNode;
6
6
  FallbackComponent?: AIConversationInput['FallbackResponseComponent'];
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
@@ -3,4 +3,4 @@ export declare const LoadingContext: React.Context<boolean | undefined>;
3
3
  export declare const LoadingContextProvider: ({ children, isLoading, }: {
4
4
  children?: React.ReactNode;
5
5
  isLoading?: boolean | undefined;
6
- }) => JSX.Element;
6
+ }) => React.JSX.Element;
@@ -1,5 +1,4 @@
1
- /// <reference types="react" />
2
1
  import { MessageRenderer } from '../types';
3
- export declare const MessageRendererContext: import("react").Context<MessageRenderer | undefined>, MessageRendererProvider: import("react").ComponentType<import("react").PropsWithChildren<MessageRenderer>>, useMessageRenderer: (params?: {
2
+ export declare const MessageRendererContext: import("react").Context<MessageRenderer>, MessageRendererProvider: import("react").ComponentType<import("react").PropsWithChildren<MessageRenderer>>, useMessageRenderer: (params?: {
4
3
  errorMessage?: string | undefined;
5
4
  } | undefined) => MessageRenderer;
@@ -4,4 +4,4 @@ export declare const MessageVariantContext: React.Context<MessageVariant | undef
4
4
  export declare const MessageVariantProvider: ({ children, variant, }: {
5
5
  children?: React.ReactNode;
6
6
  variant?: MessageVariant | undefined;
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
@@ -6,5 +6,5 @@ export declare const RoleContext: React.Context<"user" | "assistant" | undefined
6
6
  export declare const MessagesProvider: ({ children, messages, }: {
7
7
  children?: React.ReactNode;
8
8
  messages: ConversationMessage[];
9
- }) => JSX.Element;
9
+ }) => React.JSX.Element;
10
10
  export {};
@@ -7,6 +7,6 @@ export declare const prependResponseComponents: (responseComponents?: ResponseCo
7
7
  export declare const ResponseComponentsProvider: ({ children, responseComponents, }: {
8
8
  children?: React.ReactNode;
9
9
  responseComponents?: ResponseComponents | undefined;
10
- }) => JSX.Element;
10
+ }) => React.JSX.Element;
11
11
  export declare const convertResponseComponentsToToolConfiguration: (responseComponents?: ResponseComponents) => ToolConfiguration | undefined;
12
12
  export {};
@@ -4,4 +4,4 @@ export declare const SendMessageContext: React.Context<SendMessage | undefined>;
4
4
  export declare const SendMessageContextProvider: ({ children, handleSendMessage, }: {
5
5
  children?: React.ReactNode;
6
6
  handleSendMessage: SendMessage;
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
@@ -5,5 +5,5 @@ export declare const SuggestedPromptsContext: React.Context<SuggestedPromptsCont
5
5
  export declare const SuggestedPromptProvider: ({ children, suggestedPrompts, }: {
6
6
  children?: React.ReactNode;
7
7
  suggestedPrompts?: SuggestedPrompt[] | undefined;
8
- }) => JSX.Element;
8
+ }) => React.JSX.Element;
9
9
  export {};
@@ -4,5 +4,5 @@ export declare const WelcomeMessageContext: React.Context<WelcomeMessageContextP
4
4
  export declare const WelcomeMessageProvider: ({ children, welcomeMessage, }: {
5
5
  children?: React.ReactNode;
6
6
  welcomeMessage?: React.ReactNode;
7
- }) => JSX.Element;
7
+ }) => React.JSX.Element;
8
8
  export {};
@@ -2,5 +2,5 @@ import React from 'react';
2
2
  export type IconElementProps = React.ComponentProps<typeof BaseIconElement>;
3
3
  export type IconVariant = 'attach' | 'close' | 'image' | 'send-message' | 'user-avatar';
4
4
  export declare const DEFAULT_ICON_PATHS: Record<IconVariant, string>;
5
- export declare const BaseIconElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, IconVariant, React.SVGProps<SVGSVGElement>>, SVGSVGElement>;
6
- export declare const IconElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<Omit<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, IconVariant, React.SVGProps<SVGSVGElement>>, "ref"> & React.RefAttributes<SVGSVGElement>, SVGSVGElement>;
5
+ export declare const BaseIconElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, IconVariant, React.SVGProps<SVGSVGElement>>, SVGSVGElement>;
6
+ export declare const IconElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<Omit<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, IconVariant, React.SVGProps<SVGSVGElement>>, "ref"> & React.RefAttributes<SVGSVGElement>, SVGSVGElement>;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { IconElement } from './IconElement';
3
2
  export interface AIConversationElements {
4
3
  Button: typeof ButtonElement;
@@ -14,22 +13,22 @@ export interface AIConversationElements {
14
13
  UnorderedList: typeof UnorderedListElement;
15
14
  View: typeof ViewElement;
16
15
  }
17
- export declare const LabelElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<"htmlFor", string, import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>>, HTMLLabelElement>;
18
- export declare const TextElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>>, HTMLParagraphElement>;
19
- export declare const UnorderedListElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLUListElement>, HTMLUListElement>>, HTMLUListElement>;
20
- export declare const ListItemElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, string, import("react").DetailedHTMLProps<import("react").LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>>, HTMLLIElement>;
21
- export declare const HeadingElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>, HTMLHeadingElement>;
16
+ export declare const LabelElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<"htmlFor", string, import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>>, HTMLLabelElement>;
17
+ export declare const TextElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>>, HTMLParagraphElement>;
18
+ export declare const UnorderedListElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLUListElement>, HTMLUListElement>>, HTMLUListElement>;
19
+ export declare const ListItemElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, string, import("react").DetailedHTMLProps<import("react").LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>>, HTMLLIElement>;
20
+ export declare const HeadingElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>, HTMLHeadingElement>;
22
21
  export type IconElementProps = React.ComponentProps<typeof IconElement>;
23
22
  type ImageElementProps = 'src' | 'alt';
24
- export declare const ImageElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<ImageElementProps, string, import("react").DetailedHTMLProps<import("react").ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>>, HTMLImageElement>;
25
- export declare const InputElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<"type", string, import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>>, HTMLInputElement>;
23
+ export declare const ImageElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<ImageElementProps, string, import("react").DetailedHTMLProps<import("react").ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>>, HTMLImageElement>;
24
+ export declare const InputElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<"type", string, import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>>, HTMLInputElement>;
26
25
  type ButtonElementProps = 'disabled' | 'onClick' | 'type' | 'tabIndex';
27
26
  type ButtonElementVariant = 'attach' | 'remove' | 'send-message';
28
- export declare const ButtonElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<ButtonElementProps, ButtonElementVariant, import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>>, HTMLButtonElement>;
27
+ export declare const ButtonElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<ButtonElementProps, ButtonElementVariant, import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>>, HTMLButtonElement>;
29
28
  type ViewElementProps = 'onFocus' | 'tabIndex' | 'onKeyDown';
30
- export declare const ViewElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<ViewElementProps, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>>, HTMLDivElement>;
31
- export declare const SpanElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>>, HTMLSpanElement>;
29
+ export declare const ViewElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<ViewElementProps, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>>, HTMLDivElement>;
30
+ export declare const SpanElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<never, string, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>>, HTMLSpanElement>;
32
31
  type TextAreaElementProps = 'id' | 'name' | 'onChange' | 'placeholder' | 'autoFocus' | 'onCompositionStart' | 'onCompositionEnd' | 'onKeyDown';
33
- export declare const TextAreaElement: import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElement<import("@aws-amplify/ui-react-core/dist/types/elements/types").BaseElementProps<TextAreaElementProps, string, import("react").DetailedHTMLProps<import("react").TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>>, HTMLTextAreaElement>;
32
+ export declare const TextAreaElement: import("@aws-amplify/ui-react-core/elements").BaseElementWithRef<import("@aws-amplify/ui-react-core/elements").BaseElementWithRefProps<TextAreaElementProps, string, import("react").DetailedHTMLProps<import("react").TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>>, HTMLTextAreaElement>;
34
33
  export declare const AIConversationElements: AIConversationElements;
35
34
  export {};
@@ -1,7 +1,7 @@
1
1
  export { AIContextContext, AIContextProvider } from './AIContextContext';
2
2
  export { ActionsContext, ActionsProvider } from './ActionsContext';
3
3
  export { AvatarsContext, AvatarsProvider } from './AvatarsContext';
4
- export { ConversationInputContext, ConversationInput, ConversationInputContextProvider, } from './ConversationInputContext';
4
+ export { ConversationInputContextProps, ConversationInputContext, ConversationInput, ConversationInputContextProvider, } from './ConversationInputContext';
5
5
  export { MessagesContext, RoleContext, MessagesProvider, } from './MessagesContext';
6
6
  export { SuggestedPromptsContext, SuggestedPromptProvider, } from './SuggestedPromptsContext';
7
7
  export { MessageVariantContext, MessageVariantProvider, } from './MessageVariantContext';
@@ -11,7 +11,7 @@ export { LoadingContextProvider } from './LoadingContext';
11
11
  export { ResponseComponentsProvider, RESPONSE_COMPONENT_PREFIX, } from './ResponseComponentsContext';
12
12
  export { SendMessageContextProvider } from './SendMessageContext';
13
13
  export { MessageRendererProvider, MessageRendererContext, useMessageRenderer, } from './MessageRenderContext';
14
- export { AttachmentProvider, AttachmentContext } from './AttachmentContext';
14
+ export { AttachmentProvider, AttachmentContext, AttachmentContextProps, } from './AttachmentContext';
15
15
  export { WelcomeMessageContext, WelcomeMessageProvider, } from './WelcomeMessageContext';
16
16
  export { FallbackComponentContext, FallbackComponentProvider, } from './FallbackComponentContext';
17
17
  export * from './elements';
@@ -1,6 +1,8 @@
1
1
  import { DisplayTextTemplate } from '@aws-amplify/ui';
2
2
  export type ConversationDisplayText = {
3
3
  getMessageTimestampText?: (date: Date) => string;
4
+ getMaxAttachmentErrorText?: (count: number) => string;
5
+ getAttachmentSizeErrorText?: (sizeText: string) => string;
4
6
  };
5
7
  export declare const defaultAIConversationDisplayTextEn: Required<AIConversationDisplayText>;
6
8
  export type AIConversationDisplayText = DisplayTextTemplate<ConversationDisplayText>;
@@ -22,6 +22,8 @@ export interface AIConversationInput {
22
22
  variant?: MessageVariant;
23
23
  controls?: ControlsContextProps;
24
24
  allowAttachments?: boolean;
25
+ maxAttachments?: number;
26
+ maxAttachmentSize?: number;
25
27
  messageRenderer?: MessageRenderer;
26
28
  }
27
29
  export interface AIConversationProps {
@@ -32,10 +34,10 @@ export interface AIConversationProps {
32
34
  aiContext?: () => object;
33
35
  }
34
36
  export interface AIConversation<PropsType extends AIConversationProps = AIConversationProps> {
35
- (props: PropsType): JSX.Element;
36
- DefaultMessage: () => JSX.Element | undefined;
37
- Messages: () => JSX.Element;
38
- Form: () => JSX.Element;
37
+ (props: PropsType): React.JSX.Element;
38
+ DefaultMessage: () => React.JSX.Element | undefined;
39
+ Messages: () => React.JSX.Element;
40
+ Form: () => React.JSX.Element;
39
41
  Provider: (props: AIConversationProviderProps) => React.JSX.Element;
40
42
  }
41
43
  export type MessageVariant = 'bubble' | 'default';
@@ -2,3 +2,13 @@ import { ImageContentBlock } from '../../types';
2
2
  export declare function formatDate(date: Date): string;
3
3
  export declare function convertBufferToBase64(buffer: ArrayBuffer, format: ImageContentBlock['format']): string;
4
4
  export declare function getImageTypeFromMimeType(mimeType: string): 'png' | 'jpeg' | 'gif' | 'webp';
5
+ export declare function attachmentsValidator({ files, maxAttachments, maxAttachmentSize, }: {
6
+ files: File[];
7
+ maxAttachments: number;
8
+ maxAttachmentSize: number;
9
+ }): Promise<{
10
+ acceptedFiles: File[];
11
+ rejectedFiles: File[];
12
+ hasMaxAttachmentSizeError: boolean;
13
+ hasMaxAttachmentsError: boolean;
14
+ }>;
@@ -1,10 +1,10 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import { AIConversationElements } from '../../context/elements';
3
3
  export declare const RemoveButtonControl: RemoveButtonControl;
4
4
  interface RemoveButtonControl<T extends Partial<AIConversationElements> = AIConversationElements> {
5
5
  (props: {
6
6
  onRemove: () => void;
7
- }): JSX.Element;
7
+ }): React.JSX.Element;
8
8
  Button: T['Button'];
9
9
  Icon: T['Icon'];
10
10
  }
@@ -13,7 +13,7 @@ interface TextControl<T extends Partial<AIConversationElements> = AIConversation
13
13
  (props: {
14
14
  fileName: string;
15
15
  fileSize: number;
16
- }): JSX.Element;
16
+ }): React.JSX.Element;
17
17
  Container: T['View'];
18
18
  FileName: T['Text'];
19
19
  FileSize: T['Text'];
@@ -24,7 +24,7 @@ interface AttachmentControl<T extends Partial<AIConversationElements> = AIConver
24
24
  (props: {
25
25
  image: File;
26
26
  onRemove: () => void;
27
- }): JSX.Element;
27
+ }): React.JSX.Element;
28
28
  Container: T['ListItem'];
29
29
  ImageIcon: T['Icon'];
30
30
  RemoveButton: RemoveButtonControl<T>;
@@ -32,7 +32,7 @@ interface AttachmentControl<T extends Partial<AIConversationElements> = AIConver
32
32
  }
33
33
  export declare const AttachmentListControl: AttachmentListControl;
34
34
  export interface AttachmentListControl<T extends Partial<AIConversationElements> = AIConversationElements> {
35
- (): JSX.Element;
35
+ (): React.JSX.Element;
36
36
  List: T['UnorderedList'];
37
37
  Item: AttachmentControl<T>;
38
38
  }
@@ -1,2 +1,2 @@
1
- /// <reference types="react" />
2
- export declare const DefaultMessageControl: () => JSX.Element | undefined;
1
+ import * as React from 'react';
2
+ export declare const DefaultMessageControl: () => React.JSX.Element | undefined;
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import { AIConversationElements } from '../../context/elements';
3
3
  import { ActionsBarControl } from './ActionsBarControl';
4
4
  import { AvatarControl } from './AvatarControl';
@@ -7,11 +7,11 @@ export declare const MessageControl: MessageControl;
7
7
  interface MessageControl {
8
8
  (props: {
9
9
  message: ConversationMessage;
10
- }): JSX.Element;
10
+ }): React.JSX.Element;
11
11
  }
12
12
  export declare const MessagesControl: MessagesControl;
13
13
  export interface MessagesControl {
14
- (): JSX.Element;
14
+ (): React.JSX.Element;
15
15
  ActionsBar: ActionsBarControl;
16
16
  Avatar: AvatarControl;
17
17
  Container: AIConversationElements['View'];
@@ -1,6 +1,6 @@
1
- /// <reference types="react" />
2
- import { ConversationInputContext } from '../../context';
1
+ import * as React from 'react';
2
+ import { ConversationInputContextProps } from '../../context';
3
3
  export declare const Attachments: ({ files, setInput, }: {
4
4
  files?: File[] | undefined;
5
- setInput: ConversationInputContext['setInput'];
6
- }) => JSX.Element | null;
5
+ setInput: ConversationInputContextProps['setInput'];
6
+ }) => React.JSX.Element | null;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { V6Client } from '@aws-amplify/api-graphql';
3
2
  export type ConversationRoute = V6Client<any>['conversations'][string];
4
3
  export type Conversation = NonNullable<Awaited<ReturnType<ConversationRoute['create']>>['data']>;
@@ -1 +1 @@
1
- export declare const VERSION = "1.0.0";
1
+ export declare const VERSION = "1.2.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-ai",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "exports": {
@@ -42,15 +42,15 @@
42
42
  "typecheck": "tsc --noEmit"
43
43
  },
44
44
  "peerDependencies": {
45
- "@aws-amplify/api-graphql": "^4.3.0",
46
- "aws-amplify": "^6.6.5",
47
- "react": "^16.14.0 || ^17.0 || ^18.0",
48
- "react-dom": "^16.14.0 || ^17.0 || ^18.0"
45
+ "@aws-amplify/api-graphql": "unstable",
46
+ "aws-amplify": "^6.9.0",
47
+ "react": "^16.14 || ^17 || ^18 || ^19",
48
+ "react-dom": "^16.14 || ^17 || ^18 || ^19"
49
49
  },
50
50
  "dependencies": {
51
- "@aws-amplify/ui": "^6.6.6",
52
- "@aws-amplify/ui-react": "^6.6.0",
53
- "@aws-amplify/ui-react-core": "^3.0.30"
51
+ "@aws-amplify/ui": "^6.7.1",
52
+ "@aws-amplify/ui-react": "^6.8.0",
53
+ "@aws-amplify/ui-react-core": "^3.2.0"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/jest-when": "^3.5.0",