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

80 lines (79 loc) 3.98 kB
import * as React from 'react'; import Stack from '@mui/material/Stack'; import { styled, keyframes } from '@mui/material/styles'; import ChatMessages from '../message/MessagesComponent'; import ChatTextFieldRow from '../form/ChatTextFieldRow'; import Box from '@mui/material/Box'; import { ChatViewConstants } from '../ChatViewConstants'; import MessageSelectedMobile from '../message/MessageSelectedMobile'; import ChatScroller from './ChatScroller'; import { ThreadProvider } from './ThreadContext'; import { useChatContext } from '../core/ChatGlobalContext'; import { useResolvedSpeed } from '../core/useResolvedSpeed'; import { NOOP } from '../../utils/NOOP'; import { useChatSlots } from '../core/ChatSlotsContext'; import { useObserverValue } from '../hooks/useObserverValue'; import { chatClassNames } from '../core/chatClassNames'; import { getSurfaceColor } from "../utils/colors"; const fadeIn = keyframes ` from { opacity: 0; } to { opacity: 1; } `; const MessagesRowStyled = styled(Stack, { shouldForwardProp: (prop) => prop !== 'animationSpeed', })(({ animationSpeed }) => ({ width: '100%', alignItems: 'center', flex: 1, paddingBottom: ChatViewConstants.MESSAGE_ROW_PADDING_BOTTOM, paddingTop: ChatViewConstants.MESSAGE_ROW_PADDING_TOP, boxSizing: 'border-box', [`.${chatClassNames.markdownSmoothedPending}`]: { opacity: 0, }, [`.${chatClassNames.markdownSmoothedAnimating}`]: { opacity: 0, // here `delay` has no meaning, since it is overwritten in style for each element animation: `${fadeIn} ${animationSpeed ?? ChatViewConstants.TEXT_SMOOTH_ANIMATION_DURATION_MS}ms ease-in-out 0ms 1 normal forwards`, }, })); const TextRowBlock = styled(Box)(({ theme }) => ({ width: '100%', minHeight: ChatViewConstants.TEXT_BLOCK_HEIGHT, display: 'flex', justifyContent: 'center', background: getSurfaceColor(theme), })); const ThreadComponent = ({ contentRef, className, loading, apiManager, enableBranches, initialThread }) => { const scrollApiRef = React.useRef({ handleBottomScroll: NOOP }); const { handleCreateNewThread, onAssistantMessageTypingFinish, onFirstMessageSent, getCurrentBranch, model, beforeUserMessageSend, getConversationBlockHeightMin, } = useChatContext(); const { typing: typingSpeed } = useResolvedSpeed(); const thread = useObserverValue(model.currentThread); const { slots, slotProps } = useChatSlots(); React.useEffect(() => { if (!initialThread && !loading) { apiManager.apiRef.current?.openNewThread(handleCreateNewThread()); } }, [loading]); return (React.createElement(ThreadProvider, { thread: thread, model: model, apiManager: apiManager, globalProps: { onAssistantMessageTypingFinish, enableBranches, onFirstMessageSent, beforeUserMessageSend, getCurrentBranch, getConversationBlockHeightMin, }, contentRef: contentRef, scrollRef: scrollApiRef }, React.createElement(slots.thread, { id: ChatViewConstants.DIALOGUE_ROOT_ID, ...slotProps.thread, className: className }, React.createElement(MessagesRowStyled, { justifyContent: thread?.messages.length ? 'stretch' : 'center', animationSpeed: typingSpeed }, !!thread && (React.createElement(React.Fragment, null, React.createElement(ChatMessages, null)))), React.createElement(Stack, { position: "sticky", bottom: 0, zIndex: 1 }, React.createElement(TextRowBlock, null, React.createElement(ChatScroller, { thread: thread, contentRef: contentRef, scrollApiRef: scrollApiRef, apiManager: apiManager }), React.createElement(ChatTextFieldRow, { thread: thread }))), React.createElement(MessageSelectedMobile, null)))); }; export default ThreadComponent;