-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ai-conversation): add allowAttachments prop #5802
Changes from 5 commits
92d95ce
d44827f
f03bd89
54efea0
989063c
0f1062b
f639b55
0d373b5
0f2eb21
e7ed523
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
"@aws-amplify/ui-react-ai": minor | ||
--- | ||
|
||
feat(ai-conversation): add allowAttachments prop | ||
|
||
```jsx | ||
<AIConversation | ||
allowAttachments | ||
messages={messages} | ||
handleSendMessage={handleSendMessage} | ||
/> | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ function AIConversationBase({ | |
variant, | ||
isLoading, | ||
displayText, | ||
allowAttachments, | ||
}: AIConversationBaseProps): JSX.Element { | ||
const icons = useIcons('aiConversation'); | ||
const defaultAvatars: Avatars = { | ||
|
@@ -72,6 +73,7 @@ function AIConversationBase({ | |
...avatars, | ||
}, | ||
isLoading, | ||
allowAttachments, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to add this on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this comment resolved? |
||
}; | ||
|
||
return ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import * as React from 'react'; | ||
|
||
export const AttachmentContext = React.createContext(false); | ||
|
||
export const AttachmentProvider = ({ | ||
children, | ||
allowAttachments, | ||
}: { | ||
children?: React.ReactNode; | ||
allowAttachments?: boolean; | ||
}): JSX.Element => { | ||
return ( | ||
<AttachmentContext.Provider value={allowAttachments ?? false}> | ||
{children} | ||
</AttachmentContext.Provider> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,15 +11,49 @@ import { ComponentClassName } from '@aws-amplify/ui'; | |
import { ControlsContextProps } from '../../context/ControlsContext'; | ||
import { Attachments } from './Attachments'; | ||
import { LoadingContext } from '../../context/LoadingContext'; | ||
import { ConversationInputContext } from '../../context'; | ||
|
||
function isHTMLFormElement(target: EventTarget): target is HTMLFormElement { | ||
return 'form' in target; | ||
} | ||
|
||
/** | ||
* Will conditionally render the DropZone if allowAttachments | ||
* is true | ||
*/ | ||
const FormWrapper = ({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit confused on whether this addition is creating deltas between the behaviors of the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, so the Amplify UI version uses the DropZone component that wraps the form so users can drag and drop a file onto the form and it gets attached (in addition to a button which triggers the file picker). So There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have drop event handlers configured in the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we do now |
||
children, | ||
allowAttachments, | ||
setInput, | ||
}: { | ||
children: React.ReactNode; | ||
allowAttachments?: boolean; | ||
setInput: ConversationInputContext['setInput']; | ||
}) => { | ||
if (allowAttachments) { | ||
return ( | ||
<DropZone | ||
className={ComponentClassName.AIConversationFormDropzone} | ||
onDropComplete={({ acceptedFiles }) => { | ||
setInput?.((prevInput) => ({ | ||
...prevInput, | ||
files: [...(prevInput?.files ?? []), ...acceptedFiles], | ||
})); | ||
}} | ||
> | ||
{children} | ||
</DropZone> | ||
); | ||
} else { | ||
return children; | ||
} | ||
}; | ||
|
||
export const Form: NonNullable<ControlsContextProps['Form']> = ({ | ||
setInput, | ||
input, | ||
handleSubmit, | ||
allowAttachments, | ||
}) => { | ||
const icons = useIcons('aiConversation'); | ||
const sendIcon = icons?.send ?? <IconSend />; | ||
|
@@ -29,51 +63,46 @@ export const Form: NonNullable<ControlsContextProps['Form']> = ({ | |
const isInputEmpty = !input?.text?.length && !input?.files?.length; | ||
|
||
return ( | ||
<DropZone | ||
className={ComponentClassName.AIConversationFormDropzone} | ||
onDropComplete={({ acceptedFiles }) => { | ||
setInput((prevInput) => ({ | ||
...prevInput, | ||
files: [...(prevInput?.files ?? []), ...acceptedFiles], | ||
})); | ||
}} | ||
> | ||
<FormWrapper allowAttachments={allowAttachments} setInput={setInput}> | ||
<View | ||
as="form" | ||
className={ComponentClassName.AIConversationForm} | ||
onSubmit={handleSubmit} | ||
> | ||
<Button | ||
className={ComponentClassName.AIConversationFormAttach} | ||
onClick={() => { | ||
hiddenInput?.current?.click(); | ||
if (hiddenInput?.current) { | ||
hiddenInput.current.value = ''; | ||
} | ||
}} | ||
> | ||
<span>{attachIcon}</span> | ||
<VisuallyHidden> | ||
<input | ||
type="file" | ||
tabIndex={-1} | ||
ref={hiddenInput} | ||
onChange={(e) => { | ||
const { files } = e.target; | ||
if (!files || files.length === 0) { | ||
return; | ||
} | ||
setInput((prevValue) => ({ | ||
...prevValue, | ||
files: [...(prevValue?.files ?? []), ...Array.from(files)], | ||
})); | ||
}} | ||
multiple | ||
accept="*" | ||
data-testid="hidden-file-input" | ||
/> | ||
</VisuallyHidden> | ||
</Button> | ||
{allowAttachments ? ( | ||
<Button | ||
className={ComponentClassName.AIConversationFormAttach} | ||
onClick={() => { | ||
hiddenInput?.current?.click(); | ||
if (hiddenInput?.current) { | ||
hiddenInput.current.value = ''; | ||
} | ||
}} | ||
> | ||
<span>{attachIcon}</span> | ||
<VisuallyHidden> | ||
<input | ||
type="file" | ||
tabIndex={-1} | ||
ref={hiddenInput} | ||
onChange={(e) => { | ||
const { files } = e.target; | ||
if (!files || files.length === 0) { | ||
return; | ||
} | ||
setInput((prevValue) => ({ | ||
...prevValue, | ||
files: [...(prevValue?.files ?? []), ...Array.from(files)], | ||
})); | ||
}} | ||
multiple | ||
accept="*" | ||
data-testid="hidden-file-input" | ||
/> | ||
</VisuallyHidden> | ||
</Button> | ||
) : null} | ||
|
||
<TextAreaField | ||
className={ComponentClassName.AIConversationFormField} | ||
label="input" | ||
|
@@ -111,6 +140,6 @@ export const Form: NonNullable<ControlsContextProps['Form']> = ({ | |
</Button> | ||
</View> | ||
<Attachments setInput={setInput} files={input?.files} /> | ||
</DropZone> | ||
</FormWrapper> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mention that to keep current behavior customers need to add this prop