UNPKG

@plteam/chat-ui

Version:

CUI Kit is a free and open-source library for creating AI assistant chat interfaces, built with React, Material UI, and TypeScript

65 lines (64 loc) 3.76 kB
import * as React from 'react'; import { styled } from '@mui/material/styles'; import ChatTextField from './ChatTextField'; import Stack from '@mui/material/Stack'; import { inputBaseClasses } from '@mui/material/InputBase'; import { useObserverValue } from '../hooks/useObserverValue'; import { materialDesignSysPalette } from '../../utils/materialDesign/palette'; import { motion } from '../../utils/materialDesign/motion'; import { useChatContext } from '../core/ChatGlobalContext'; import AttachmentsPreview from './preview/AttachmentsPreview'; import attachmentsStore from '../../models/AttachmentsStore'; import RowInnerFooter from './RowInnerFooter'; import SendMessageButton from './SendMessageButton'; import useFileAttachment from './attachments/useFileAttachment'; const StackStyled = styled(Stack)(({ theme }) => ({ position: 'relative', outline: `1px solid ${materialDesignSysPalette.outlineVariant}`, borderRadius: 24, padding: theme.spacing(1), transition: theme.transitions.create(['border-radius', 'outline'], { duration: motion.duration.short2 }), [`&:has(.${inputBaseClasses.focused})`]: { outline: `2px solid ${materialDesignSysPalette.primary}`, }, })); const ChatTextFieldRowInner = ({ thread }) => { const { defaultTextFieldValue, apiRef, enableFileAttachments, toolsList } = useChatContext(); const isTyping = useObserverValue(thread?.isTyping); const isLoadingAttachments = useObserverValue(thread?.isLoadingAttachments); const isLoadingFullData = useObserverValue(thread?.isLoadingFullData); const attachmentConfig = useFileAttachment(); const { attachments, setAttachments, handleFileUpload } = attachmentConfig; const [text, setText] = React.useState(defaultTextFieldValue ?? ''); const [expand, setExpand] = React.useState(false); const onSendMessage = () => { if (isLoadingAttachments?.length) return; setExpand(false); let content = text; if (attachments.length) { attachmentsStore.items.push(...attachments.filter((a) => !a.error.value)); content = attachments.map((a) => a.contentData); if (text) { content = [ { type: 'text', text }, ...content, ]; } } ; apiRef.current?.sendUserMessage(content); setText(''); setAttachments([]); }; const controlsInFooter = enableFileAttachments || !!toolsList?.length; const disabledTextField = !thread || isTyping || isLoadingFullData; const disabledButton = (!isTyping && !text && !attachments.length) || !!isLoadingAttachments?.length || isLoadingFullData; const previewComponent = React.useMemo(() => (React.createElement(AttachmentsPreview, { attachments: attachments, setAttachments: setAttachments, thread: thread })), [attachments, thread]); return (React.createElement(StackStyled, { flexDirection: controlsInFooter ? 'column' : 'row', alignItems: controlsInFooter ? undefined : 'flex-end' }, previewComponent, React.createElement(ChatTextField, { text: text, setText: setText, expand: expand, setExpand: setExpand, disabled: disabledTextField, handleFileUpload: handleFileUpload, onSendMessage: onSendMessage }), controlsInFooter ? (React.createElement(RowInnerFooter, { thread: thread, attachmentConfig: attachmentConfig, isTyping: isTyping, disabledSendMessage: disabledButton, onSendMessage: onSendMessage })) : (React.createElement(SendMessageButton, { disabled: disabledButton, isTyping: isTyping, onSendMessage: onSendMessage })))); }; export default ChatTextFieldRowInner;