diff --git a/.changeset/good-planets-invite.md b/.changeset/good-planets-invite.md new file mode 100644 index 00000000000..fe948afde0c --- /dev/null +++ b/.changeset/good-planets-invite.md @@ -0,0 +1,41 @@ +--- +"@aws-amplify/ui-react-ai": minor +--- + + +The AIConversation component is now composable if you are using the default component or the headless component using `createAIConversation()`. There are 4 parts: + +* Provider: provides all the necessary data/handlers for the composable components +* Messages: the message history for the conversation +* DefaultMessage: contains an optional welcome message and prompt suggestions, only shown if no messages present +* Form: the form for sending messages, includes the text input, submit button, and attachments + +```jsx +function Chat() { + const [ + { + data: { messages }, + isLoading, + }, + sendMessage, + ] = useAIConversation('pirateChat'); + + return ( + + + + + + + + + + + + ); +} +``` diff --git a/examples/next/pages/ui/components/ai/ai-conversation-composable/amplify_outputs.js b/examples/next/pages/ui/components/ai/ai-conversation-composable/amplify_outputs.js new file mode 100644 index 00000000000..2f1016412fd --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-composable/amplify_outputs.js @@ -0,0 +1,2 @@ +import amplifyOutputs from '@environments/ai/gen2/amplify_outputs'; +export default amplifyOutputs; diff --git a/examples/next/pages/ui/components/ai/ai-conversation-composable/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation-composable/index.page.tsx new file mode 100644 index 00000000000..9a4ad3e9d82 --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-composable/index.page.tsx @@ -0,0 +1,56 @@ +import * as React from 'react'; +import { Amplify } from 'aws-amplify'; +import { createAIHooks, AIConversation } from '@aws-amplify/ui-react-ai'; +import { generateClient } from 'aws-amplify/api'; +import '@aws-amplify/ui-react/styles.css'; +import '@aws-amplify/ui-react-ai/ai-conversation-styles.css'; + +import outputs from './amplify_outputs'; +import type { Schema } from '@environments/ai/gen2/amplify/data/resource'; +import { Authenticator, Card, Flex } from '@aws-amplify/ui-react'; + +const client = generateClient({ authMode: 'userPool' }); +const { useAIConversation } = createAIHooks(client); + +Amplify.configure(outputs); + +function Chat() { + const [ + { + data: { messages }, + isLoading, + }, + sendMessage, + ] = useAIConversation('pirateChat'); + + return ( + + + + + + + + + + + + ); +} + +export default function Example() { + return ( + + + + ); +} diff --git a/examples/next/pages/ui/components/ai/ai-conversation-renderer/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation-renderer/index.page.tsx index 42409609fdd..04d75b965a1 100644 --- a/examples/next/pages/ui/components/ai/ai-conversation-renderer/index.page.tsx +++ b/examples/next/pages/ui/components/ai/ai-conversation-renderer/index.page.tsx @@ -67,11 +67,11 @@ function Chat() { suggestedPrompts={[ { inputText: 'hello', - header: 'hello', + component: 'hello', }, { inputText: 'how are you?', - header: 'how are you?', + component: 'how are you?', }, ]} variant="bubble" diff --git a/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx index b71fbecebf9..f60b0d6e93e 100644 --- a/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx +++ b/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx @@ -40,11 +40,11 @@ function Chat() { suggestedPrompts={[ { inputText: 'hello', - header: 'hello', + component: 'hello', }, { inputText: 'how are you?', - header: 'how are you?', + component: 'how are you?', }, ]} variant="bubble" diff --git a/examples/next/pages/ui/components/ai/create-ai-conversation/index.page.tsx b/examples/next/pages/ui/components/ai/create-ai-conversation/index.page.tsx index 86f73677127..ee1f22b954e 100644 --- a/examples/next/pages/ui/components/ai/create-ai-conversation/index.page.tsx +++ b/examples/next/pages/ui/components/ai/create-ai-conversation/index.page.tsx @@ -46,25 +46,14 @@ export default function Example() { return ( - {({ user, signOut }) => { - return ( - <> -

Hello {user.username}

- - - - ); - }} + + + +
); } - -// export default function Example() { -// return
hello world
; -// } diff --git a/packages/react-ai/src/components/AIConversation/AIConversation.tsx b/packages/react-ai/src/components/AIConversation/AIConversation.tsx index a17bc811c86..10a79abb3da 100644 --- a/packages/react-ai/src/components/AIConversation/AIConversation.tsx +++ b/packages/react-ai/src/components/AIConversation/AIConversation.tsx @@ -1,27 +1,31 @@ import * as React from 'react'; -import { Flex, ScrollView, Text, TextProps } from '@aws-amplify/ui-react'; +import { Flex, ScrollView, Text } from '@aws-amplify/ui-react'; import { IconAssistant, IconUser, useIcons, } from '@aws-amplify/ui-react/internal'; -import { AIConversationInput, AIConversationProps, Avatars } from './types'; +import { + AIConversation as AIConversationType, + AIConversationInput, + AIConversationProps, + Avatars, +} from './types'; import { MessagesControl } from './views/Controls/MessagesControl'; -import { FieldControl } from './views'; +import { FormControl } from './views/Controls/FormControl'; import { MessageList } from './views/default/MessageList'; import { Form } from './views/default/Form'; import { PromptList } from './views/default/PromptList'; -import { AutoHidablePromptControl } from './views/Controls'; import { ComponentClassName } from '@aws-amplify/ui'; -import { AIConversationProvider } from './AIConversationProvider'; +import { + AIConversationProvider, + AIConversationProviderProps, +} from './AIConversationProvider'; import { useSetUserAgent } from '@aws-amplify/ui-react-core'; import { VERSION } from '../../version'; +import { DefaultMessageControl } from './views/Controls/DefaultMessageControl'; -interface AIConversationBaseProps - extends AIConversationProps, - AIConversationInput {} - -function AIConversationBase({ +function Provider({ actions, avatars, controls, @@ -34,12 +38,14 @@ function AIConversationBase({ displayText, allowAttachments, messageRenderer, -}: AIConversationBaseProps): JSX.Element { + children, +}: AIConversationProviderProps): JSX.Element { useSetUserAgent({ componentName: 'AIConversation', packageName: 'react-ai', version: VERSION, }); + const icons = useIcons('aiConversation'); const defaultAvatars: Avatars = { ai: { @@ -61,11 +67,7 @@ function AIConversationBase({ }, isLoading, elements: { - Text: React.forwardRef( - function _Text(props, ref) { - return ; - } - ), + Text, }, actions, suggestedPrompts, @@ -84,22 +86,36 @@ function AIConversationBase({ return ( + {children} + + ); +} + +interface AIConversationBaseProps + extends AIConversationProps, + AIConversationInput {} + +function AIConversationBase(props: AIConversationBaseProps): JSX.Element { + return ( + - + - + - + ); } /** * @experimental */ -export const AIConversation = Object.assign(AIConversationBase, { - MessageList, - PromptList, - Form, -}); +export const AIConversation: AIConversationType = + Object.assign(AIConversationBase, { + Provider, + DefaultMessage: DefaultMessageControl, + Messages: MessagesControl, + Form: FormControl, + }); diff --git a/packages/react-ai/src/components/AIConversation/AIConversationProvider.tsx b/packages/react-ai/src/components/AIConversation/AIConversationProvider.tsx index 84b02cb0768..ee85e1fd720 100644 --- a/packages/react-ai/src/components/AIConversation/AIConversationProvider.tsx +++ b/packages/react-ai/src/components/AIConversation/AIConversationProvider.tsx @@ -16,29 +16,31 @@ import { LoadingContextProvider, ResponseComponentsProvider, SendMessageContextProvider, + WelcomeMessageProvider, } from './context'; import { AttachmentProvider } from './context/AttachmentContext'; -interface AIConversationProviderProps +export interface AIConversationProviderProps extends AIConversationInput, AIConversationProps { children?: React.ReactNode; } export const AIConversationProvider = ({ - elements, actions, - suggestedPrompts, - responseComponents, - variant, + allowAttachments, + avatars, + children, controls, displayText, - allowAttachments, - messages, + elements, handleSendMessage, - avatars, isLoading, - children, + messages, + responseComponents, + suggestedPrompts, + variant, + welcomeMessage, }: AIConversationProviderProps): React.JSX.Element => { const _displayText = { ...defaultAIConversationDisplayTextEn, @@ -48,29 +50,31 @@ export const AIConversationProvider = ({ - - - - - - - - - - - {children} - - - - - - - - - - + + + + + + + + + + + + {children} + + + + + + + + + + + diff --git a/packages/react-ai/src/components/AIConversation/context/WelcomeMessageContext.tsx b/packages/react-ai/src/components/AIConversation/context/WelcomeMessageContext.tsx new file mode 100644 index 00000000000..fe116d97bcf --- /dev/null +++ b/packages/react-ai/src/components/AIConversation/context/WelcomeMessageContext.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +type WelcomeMessageContextProps = React.ReactNode | undefined; + +export const WelcomeMessageContext = + React.createContext(undefined); + +export const WelcomeMessageProvider = ({ + children, + welcomeMessage, +}: { + children?: React.ReactNode; + welcomeMessage?: React.ReactNode; +}): JSX.Element => { + return ( + + {children} + + ); +}; diff --git a/packages/react-ai/src/components/AIConversation/context/index.ts b/packages/react-ai/src/components/AIConversation/context/index.ts index ca32e10d824..ba42f91c8bc 100644 --- a/packages/react-ai/src/components/AIConversation/context/index.ts +++ b/packages/react-ai/src/components/AIConversation/context/index.ts @@ -40,5 +40,8 @@ export { useMessageRenderer, } from './MessageRenderContext'; export { AttachmentProvider, AttachmentContext } from './AttachmentContext'; - +export { + WelcomeMessageContext, + WelcomeMessageProvider, +} from './WelcomeMessageContext'; export * from './elements'; diff --git a/packages/react-ai/src/components/AIConversation/createAIConversation.tsx b/packages/react-ai/src/components/AIConversation/createAIConversation.tsx index e672db0ef50..440f7672f0b 100644 --- a/packages/react-ai/src/components/AIConversation/createAIConversation.tsx +++ b/packages/react-ai/src/components/AIConversation/createAIConversation.tsx @@ -1,20 +1,13 @@ import React from 'react'; import { - Controls, AIConversationInput, AIConversation, AIConversationProps, } from './types'; -import { - ActionsBarControl, - AvatarControl, - Conversation, - FieldControl, - HeaderControl, - MessagesControl, - PromptControl, -} from './views'; +import { FormControl, MessagesControl } from './views'; +import { ViewElement as View } from './context/elements/definitions'; import { AIConversationProvider } from './AIConversationProvider'; +import { DefaultMessageControl } from './views/Controls/DefaultMessageControl'; /** * @experimental @@ -53,23 +46,23 @@ export function createAIConversation(input: AIConversationInput = {}): { }; return ( - + + + + + + + + + ); } - const Controls: Controls = { - ActionsBar: ActionsBarControl, - Avatars: AvatarControl, - Field: FieldControl, - Header: HeaderControl, - Messages: MessagesControl, - SuggestedPrompts: PromptControl, - }; - AIConversation.Provider = AIConversationProvider; - AIConversation.Conversation = Conversation; - AIConversation.Controls = Controls; + AIConversation.DefaultMessage = DefaultMessageControl; + AIConversation.Messages = MessagesControl; + AIConversation.Form = FormControl; return { AIConversation }; } diff --git a/packages/react-ai/src/components/AIConversation/types.ts b/packages/react-ai/src/components/AIConversation/types.ts index 1a6ccac8487..fba9f995226 100644 --- a/packages/react-ai/src/components/AIConversation/types.ts +++ b/packages/react-ai/src/components/AIConversation/types.ts @@ -4,8 +4,7 @@ import { AIConversationElements } from './context/elements'; import { ActionsBarControl, AvatarControl, - FieldControl, - HeaderControl, + FormControl, MessagesControl, PromptControl, } from './views'; @@ -18,12 +17,12 @@ import { TextContentBlock, } from '../../types'; import { ControlsContextProps } from './context/ControlsContext'; +import { AIConversationProviderProps } from './AIConversationProvider'; export interface Controls { Avatars: AvatarControl; ActionsBar: ActionsBarControl; - Field: FieldControl; - Header: HeaderControl; + Form: FormControl; Messages: MessagesControl; SuggestedPrompts: PromptControl; } @@ -31,6 +30,7 @@ export interface Controls { export interface AIConversationInput { elements?: Partial; displayText?: DisplayTextTemplate; + welcomeMessage?: React.ReactNode; suggestedPrompts?: SuggestedPrompt[]; actions?: CustomAction[]; responseComponents?: ResponseComponents; @@ -47,15 +47,14 @@ export interface AIConversationProps { isLoading?: boolean; } -export interface AIConversation { - (props: AIConversationProps): JSX.Element; - Conversation: () => React.JSX.Element; - Controls: Controls; - Provider: ( - props: { - children?: React.ReactNode; - } & Pick - ) => React.JSX.Element; +export interface AIConversation< + PropsType extends AIConversationProps = AIConversationProps, +> { + (props: PropsType): JSX.Element; + DefaultMessage: () => JSX.Element | undefined; + Messages: () => JSX.Element; + Form: () => JSX.Element; + Provider: (props: AIConversationProviderProps) => React.JSX.Element; } export type MessageVariant = 'bubble' | 'default'; @@ -82,8 +81,7 @@ export interface CustomAction { } export interface SuggestedPrompt { - icon?: React.ReactNode; - header: string; + component?: React.ReactNode; inputText: string; } diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/DefaultMessageControl.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/DefaultMessageControl.tsx new file mode 100644 index 00000000000..be2e769fbf9 --- /dev/null +++ b/packages/react-ai/src/components/AIConversation/views/Controls/DefaultMessageControl.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { MessagesContext } from '../../context'; +import { PromptControl } from './PromptControl'; +import { WelcomeMessageContext } from '../../context/WelcomeMessageContext'; + +export const DefaultMessageControl = (): JSX.Element | undefined => { + const messages = React.useContext(MessagesContext); + const welcomeMessage = React.useContext(WelcomeMessageContext); + + if (!messages || messages.length === 0) { + return ( + <> + {welcomeMessage} + + + ); + } +}; diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/FieldControl.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/FormControl.tsx similarity index 95% rename from packages/react-ai/src/components/AIConversation/views/Controls/FieldControl.tsx rename to packages/react-ai/src/components/AIConversation/views/Controls/FormControl.tsx index cc9e012362c..975a6710273 100644 --- a/packages/react-ai/src/components/AIConversation/views/Controls/FieldControl.tsx +++ b/packages/react-ai/src/components/AIConversation/views/Controls/FormControl.tsx @@ -146,7 +146,7 @@ const InputContainer = withBaseElementProps(View, { className: `${FIELD_BLOCK}__input-container`, }); -export const FieldControl: FieldControl = () => { +export const FormControl: FormControl = () => { const { input, setInput } = React.useContext(ConversationInputContext); const handleSendMessage = React.useContext(SendMessageContext); const allowAttachments = React.useContext(AttachmentContext); @@ -241,14 +241,14 @@ export const FieldControl: FieldControl = () => { ); }; -FieldControl.AttachFile = AttachFileControl; -FieldControl.InputContainer = InputContainer; -FieldControl.Label = Label; -FieldControl.TextInput = TextInput; -FieldControl.SendButton = SendButton; -FieldControl.SendIcon = SendIcon; +FormControl.AttachFile = AttachFileControl; +FormControl.InputContainer = InputContainer; +FormControl.Label = Label; +FormControl.TextInput = TextInput; +FormControl.SendButton = SendButton; +FormControl.SendIcon = SendIcon; -export interface FieldControl { +export interface FormControl { (): React.JSX.Element; AttachFile: AttachFileControl; InputContainer: AIConversationElements['View']; diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/HeaderControl.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/HeaderControl.tsx deleted file mode 100644 index 4dc9018cde1..00000000000 --- a/packages/react-ai/src/components/AIConversation/views/Controls/HeaderControl.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import { withBaseElementProps } from '@aws-amplify/ui-react-core/elements'; - -import { AIConversationElements } from '../../context/elements'; - -const { View, Button, Icon, Text } = AIConversationElements; - -const HEADER_BLOCK = 'ai-header'; - -const HeaderTextBase = withBaseElementProps(Text, { - className: `${HEADER_BLOCK}__text`, -}); - -const HeaderText: typeof HeaderTextBase = React.forwardRef( - function HeaderText(props, ref) { - return ; - } -); - -const CloseIcon = withBaseElementProps(Icon, { - className: `${HEADER_BLOCK}__icon`, - variant: 'close', -}); - -const CloseButtonBase = withBaseElementProps(Button, { - className: `${HEADER_BLOCK}__button`, -}); - -const CloseButton: typeof CloseButtonBase = React.forwardRef( - function CloseButton(props, ref) { - return ; - } -); - -const Container = withBaseElementProps(View, { - className: `${HEADER_BLOCK}__container`, -}); - -export const HeaderControl: HeaderControl = () => ( - - Raven Chat - - - - -); - -HeaderControl.Container = Container; -HeaderControl.Text = HeaderText; -HeaderControl.Button = CloseButton; - -export interface HeaderControl { - (): React.JSX.Element; - Container: AIConversationElements['View']; - Button: AIConversationElements['Button']; - Text: AIConversationElements['Text']; -} diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/MessagesControl.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/MessagesControl.tsx index 5de1fd3f1dc..59d7d3c4b2d 100644 --- a/packages/react-ai/src/components/AIConversation/views/Controls/MessagesControl.tsx +++ b/packages/react-ai/src/components/AIConversation/views/Controls/MessagesControl.tsx @@ -62,15 +62,40 @@ const ContentContainer: typeof View = React.forwardRef( } ); -export const MessageControl: MessageControl = ({ message }) => { +const ToolContent = ({ + toolUse, +}: { + toolUse: NonNullable; +}) => { const responseComponents = React.useContext(ResponseComponentsContext); + + // For now tool use is limited to custom response components + const { name, input } = toolUse; + + if ( + !responseComponents || + !name || + !name.startsWith(RESPONSE_COMPONENT_PREFIX) + ) { + return; + } else { + const response = responseComponents[name]; + const CustomComponent = response.component; + return ; + } +}; + +export const MessageControl: MessageControl = ({ message }) => { const messageRenderer = React.useContext(MessageRendererContext); + return ( {message.content.map((content, index) => { if (content.text) { return messageRenderer?.text ? ( - messageRenderer.text({ text: content.text }) + + {messageRenderer.text({ text: content.text })} + ) : ( {content.text} @@ -78,7 +103,9 @@ export const MessageControl: MessageControl = ({ message }) => { ); } else if (content.image) { return messageRenderer?.image ? ( - messageRenderer?.image({ image: content.image }) + + {messageRenderer?.image({ image: content.image })} + ) : ( { /> ); } else if (content.toolUse) { - // For now tool use is limited to custom response components - const { name, input } = content.toolUse; - if ( - !responseComponents || - !name || - !name.startsWith(RESPONSE_COMPONENT_PREFIX) - ) { - return; - } else { - const response = responseComponents[name]; - const CustomComponent = response.component; - return ; - } + return ; } })} diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/PromptControl.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/PromptControl.tsx index bf12b7b8aeb..125d0a35f9b 100644 --- a/packages/react-ai/src/components/AIConversation/views/Controls/PromptControl.tsx +++ b/packages/react-ai/src/components/AIConversation/views/Controls/PromptControl.tsx @@ -4,13 +4,11 @@ import { withBaseElementProps } from '@aws-amplify/ui-react-core/elements'; import { AIConversationElements, ConversationInputContext, - MessagesContext, SuggestedPromptsContext, } from '../../context'; -import { classNames } from '@aws-amplify/ui'; import { ControlsContext } from '../../context/ControlsContext'; -const { View, Button, Text, Heading, Icon } = AIConversationElements; +const { View, Button } = AIConversationElements; const PROMPT_BLOCK = 'ai-prompts'; const PROMPT_CONTROL = `${PROMPT_BLOCK}__prompt`; @@ -21,48 +19,6 @@ const PromptCard = withBaseElementProps(Button, { type: 'button', }); -const AIIconProps = () => ({ - children: ( - <> - - - - - - - - - - ), - className: `${PROMPT_CONTROL}__icon`, - width: '40', - height: '40', - viewBox: '0 0 40 40', - fill: 'none', - xmlns: 'http://www.w3.org/2000/svg', -}); - -const AIIcon = withBaseElementProps(Icon, AIIconProps); - -const HeaderText = withBaseElementProps(Heading, { - className: `${PROMPT_CONTROL}__header`, -}); - const PromptGroupBase = withBaseElementProps(View, { className: `${PROMPT_CONTROL}__buttongroup`, }); @@ -91,15 +47,7 @@ const PromptGroup: typeof PromptGroupBase = React.forwardRef( })) } > - - {prompt.header} - - {prompt.inputText} + {prompt.component} ); })} @@ -128,32 +76,18 @@ export const PromptControl: PromptControl = () => { return ( - - How can I help you today? ); }; -export const AutoHidablePromptControl = (): JSX.Element | undefined => { - const messages = React.useContext(MessagesContext); - - if (!messages || messages.length === 0) { - return ; - } -}; - PromptControl.Container = Container; -PromptControl.Header = HeaderText; -PromptControl.Icon = AIIcon; PromptControl.PromptGroup = PromptGroup; PromptControl.PromptCard = PromptCard; export interface PromptControl { (): React.JSX.Element; Container: AIConversationElements['View']; - Header: AIConversationElements['Heading']; - Icon: AIConversationElements['Icon']; PromptGroup: AIConversationElements['View']; PromptCard: AIConversationElements['Button']; } diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FieldControl.spec.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FormControl.spec.tsx similarity index 94% rename from packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FieldControl.spec.tsx rename to packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FormControl.spec.tsx index c153227af3a..285ca8bbac7 100644 --- a/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FieldControl.spec.tsx +++ b/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/FormControl.spec.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render, screen, act } from '@testing-library/react'; import { MessagesProvider } from '../../../context/MessagesContext'; -import { FieldControl } from '../FieldControl'; +import { FormControl } from '../FormControl'; import { ConversationInputContextProvider } from '../../../context/ConversationInputContext'; import userEvent from '@testing-library/user-event'; import { SendMessageContextProvider } from '../../../context/SendMessageContext'; @@ -11,7 +11,7 @@ describe('FieldControl', () => { it('renders a FieldControl component with the correct elements', () => { const result = render( - + ); expect(result.container).toBeDefined(); @@ -30,7 +30,7 @@ describe('FieldControl', () => { it('renders FieldControl with the correct accessibility roles', () => { render( - + ); @@ -52,7 +52,7 @@ describe('FieldControl', () => { it('renders correct placeholder text in the input field', () => { const { rerender } = render( - + ); const textInput = screen.getByTestId('text-input'); @@ -70,7 +70,7 @@ describe('FieldControl', () => { }, ]} > - + ); @@ -80,7 +80,7 @@ describe('FieldControl', () => { it('disables the send button when the input field is empty', async () => { render( - + ); expect(screen.getByTestId('send-button')).toBeDisabled(); @@ -97,7 +97,7 @@ describe('FieldControl', () => { render( - + ); diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/HeaderControl.spec.tsx b/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/HeaderControl.spec.tsx deleted file mode 100644 index 0b9c9198d13..00000000000 --- a/packages/react-ai/src/components/AIConversation/views/Controls/__tests__/HeaderControl.spec.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { HeaderControl } from '../HeaderControl'; - -describe('HeaderControl', () => { - it('renders a HeaderControl element', () => { - const result = render(); - expect(result.container).toBeDefined(); - expect(result.findAllByText('anything')).toBeDefined(); - }); -}); diff --git a/packages/react-ai/src/components/AIConversation/views/Controls/index.ts b/packages/react-ai/src/components/AIConversation/views/Controls/index.ts index f2b999fcd15..067e27a4ccd 100644 --- a/packages/react-ai/src/components/AIConversation/views/Controls/index.ts +++ b/packages/react-ai/src/components/AIConversation/views/Controls/index.ts @@ -1,16 +1,13 @@ import { ActionsBarControl } from './ActionsBarControl'; import { AvatarControl } from './AvatarControl'; -import { HeaderControl } from './HeaderControl'; -import { FieldControl } from './FieldControl'; +import { FormControl } from './FormControl'; import { MessagesControl } from './MessagesControl'; -import { AutoHidablePromptControl, PromptControl } from './PromptControl'; +import { PromptControl } from './PromptControl'; export { ActionsBarControl, AvatarControl, - HeaderControl, - FieldControl, + FormControl, MessagesControl, PromptControl, - AutoHidablePromptControl, }; diff --git a/packages/react-ai/src/components/AIConversation/views/ConversationView.tsx b/packages/react-ai/src/components/AIConversation/views/ConversationView.tsx deleted file mode 100644 index 28750646211..00000000000 --- a/packages/react-ai/src/components/AIConversation/views/ConversationView.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { ViewElement as View } from '../context/elements/definitions'; -import { - AutoHidablePromptControl, - HeaderControl, - FieldControl, - MessagesControl, -} from './Controls'; - -export default function Conversation(): JSX.Element { - return ( - - - - - - - - - - - ); -} diff --git a/packages/react-ai/src/components/AIConversation/views/__tests__/ConversationView.spec.tsx b/packages/react-ai/src/components/AIConversation/views/__tests__/ConversationView.spec.tsx deleted file mode 100644 index f0e78a5125c..00000000000 --- a/packages/react-ai/src/components/AIConversation/views/__tests__/ConversationView.spec.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import ConversationView from '../ConversationView'; - -describe('ConversationView', () => { - it('renders a ConversationView element', () => { - expect(render().container).toBeDefined(); - }); -}); diff --git a/packages/react-ai/src/components/AIConversation/views/default/PromptList.tsx b/packages/react-ai/src/components/AIConversation/views/default/PromptList.tsx index 29eef606856..fab975e4034 100644 --- a/packages/react-ai/src/components/AIConversation/views/default/PromptList.tsx +++ b/packages/react-ai/src/components/AIConversation/views/default/PromptList.tsx @@ -22,7 +22,7 @@ export const PromptList: ControlsContextProps['PromptList'] = ({ })); }} > - {prompt.header} + {prompt.component} ); })} diff --git a/packages/react-ai/src/components/AIConversation/views/index.ts b/packages/react-ai/src/components/AIConversation/views/index.ts index adbbd2ea688..ebe2edb3cc0 100644 --- a/packages/react-ai/src/components/AIConversation/views/index.ts +++ b/packages/react-ai/src/components/AIConversation/views/index.ts @@ -1,9 +1,7 @@ -import Conversation from './ConversationView'; import { ActionsBarControl, AvatarControl, - FieldControl, - HeaderControl, + FormControl, MessagesControl, PromptControl, } from './Controls'; @@ -11,9 +9,7 @@ import { export { ActionsBarControl, AvatarControl, - Conversation, - FieldControl, - HeaderControl, + FormControl, MessagesControl, PromptControl, };