ChatPanel
A comprehensive chat interface system designed for AI assistant integration in editor applications. ChatPanel is the layout container, and the module exports a full suite of components for building rich conversational UIs: message lists, chat bubbles, input with attachments, typing indicators, tool call displays, code blocks, and empty states. Also includes hooks for managing message state, input behavior, and auto-scroll.
Live Preview
Import
import { ChatPanel, ChatMessageList, ChatMessage, ChatBubble, ChatInput, ChatTypingIndicator, ChatToolCall, ChatCodeBlock, ChatAttachmentChip, ChatContextChip, ChatEmptyState, ChatActionBar, ChatInputToolbar, useChatMessages, useChatInput, useChatScroll,} from 'entangle-ui';Usage
const { messages, appendMessage, updateMessage } = useChatMessages();
<ChatPanel density="comfortable"> <ChatMessageList messages={messages} emptyState={ <ChatEmptyState title="How can I help?" description="Ask me anything about your scene." suggestions={['Create a cube', 'Change material', 'Add lighting']} onSuggestionClick={s => handleSend(s)} /> } /> <ChatInput onSubmit={value => handleSend(value)} placeholder="Ask the assistant..." streaming={isStreaming} onStop={handleStop} /></ChatPanel>;Components
ChatPanel
The root layout container that controls spacing density. Wrap all other chat components inside it.
<ChatPanel density="comfortable"> {/* ChatMessageList, ChatInput, etc. */}</ChatPanel>| Density | Description |
|---|---|
comfortable | More spacing and larger bubbles. Use for side panels and fullscreen. |
compact | Tight spacing. Use for bottom panels and constrained areas. |
ChatMessageList
Renders an array of messages with auto-scroll behavior. Accepts a custom renderMessage function for full control over individual message rendering.
<ChatMessageList messages={messages} autoScroll={true} emptyState={<ChatEmptyState title="No messages yet" />} renderMessage={(message, index) => ( <ChatMessage key={message.id} message={message} showTimestamp showAvatar /> )}/>ChatMessage
Renders a single message with avatar, timestamp, and action buttons. Supports a custom content renderer for markdown, LaTeX, or other rich formats.
<ChatMessage message={message} showTimestamp showAvatar actions={ <ChatActionBar> <button onClick={handleCopy}>Copy</button> <button onClick={handleRetry}>Retry</button> </ChatActionBar> } renderContent={content => <MarkdownRenderer>{content}</MarkdownRenderer>}/>ChatBubble
Low-level bubble component with role-based alignment and coloring. Use for custom message layouts.
<ChatBubble role="user">Hello, can you help?</ChatBubble><ChatBubble role="assistant">Of course! What do you need?</ChatBubble><ChatBubble role="system">Session started</ChatBubble>ChatInput
Multi-line input with submit/stop button, attachment chips, and configurable submit key. Auto-resizes from 1 line up to maxLines.
<ChatInput value={input} onChange={setInput} onSubmit={handleSubmit} onStop={handleStop} streaming={isStreaming} placeholder="Type a message..." submitKey="enter" maxLines={6} attachments={attachments} onRemoveAttachment={handleRemoveAttachment} toolbar={ <ChatInputToolbar> <button onClick={handleUpload}>Attach File</button> </ChatInputToolbar> }/>ChatTypingIndicator
Animated indicator shown while the assistant is generating a response.
<ChatTypingIndicator visible={isStreaming} label="Thinking..." variant="dots" />ChatToolCall
Displays a tool/function invocation with expandable input/output details.
<ChatToolCall toolCall={{ id: '1', name: 'create_cube', status: 'completed', input: { size: 2 }, output: { nodeId: 'cube_01' }, durationMs: 120, }} collapsible defaultExpanded={false}/>ChatCodeBlock
Code display with optional syntax highlighting, line numbers, copy button, and custom action buttons.
<ChatCodeBlock code={`const mesh = new THREE.Mesh(geometry, material);`} language="typescript" copyable lineNumbers maxHeight={400} actions={<button onClick={handleInsert}>Insert</button>}/>ChatAttachmentChip
Displays an attached file, image, code snippet, or selection as a chip.
<ChatAttachmentChip attachment={{ id: '1', name: 'scene.glb', type: 'file', size: 1024000 }} removable onRemove={id => handleRemove(id)} onClick={attachment => handlePreview(attachment)}/>ChatContextChip
Displays editor context (e.g., selected objects, active file) as a labeled chip.
<ChatContextChip label="Selected" items={['Cube', 'Sphere', 'Light']} icon={<SelectionIcon />} onDismiss={handleDismiss}/>ChatEmptyState
Shown when the message list is empty. Includes optional suggestion chips.
<ChatEmptyState title="Start a conversation" description="Ask me to modify your scene, generate code, or explain concepts." suggestions={['Add a spotlight', 'Optimize materials', 'Export scene']} onSuggestionClick={suggestion => handleSend(suggestion)}/>ChatActionBar
Horizontal row of action buttons shown below a message.
<ChatActionBar> <button>Copy</button> <button>Retry</button> <button>Apply to Scene</button></ChatActionBar>ChatInputToolbar
Horizontal row of action buttons rendered below the chat input area.
<ChatInputToolbar> <button>Attach File</button> <button>Add Context</button></ChatInputToolbar>Hooks
useChatMessages
Manages the chat message array state with convenience methods.
const { messages, setMessages, appendMessage, updateMessage, removeMessage, clearMessages, getMessage,} = useChatMessages({ initialMessages: [], maxMessages: 200,});useChatInput
Manages textarea input state with auto-resize and submit key handling.
const { value, setValue, clear, textareaRef, handleKeyDown, handleChange } = useChatInput({ submitKey: 'enter', maxLines: 6, onSubmit: value => handleSend(value), });useChatScroll
Manages auto-scroll behavior for the message list, pausing when the user scrolls up.
const { scrollContainerRef, isAtBottom, hasNewMessages, scrollToBottom } = useChatScroll({ messages, enabled: true, threshold: 100, });Props
ChatPanel
| Prop | Type | Default | Description |
|---|---|---|---|
density | 'comfortable' | 'compact' | 'comfortable' | Visual density of the chat layout. Comfortable has more spacing for side panels; compact is for constrained areas. |
children * | ReactNode | — | Panel content, typically ChatMessageList and ChatInput. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ref | Ref<HTMLDivElement> | — | Ref to the root element. |
ChatMessageList
| Prop | Type | Default | Description |
|---|---|---|---|
messages * | ChatMessageData[] | — | Array of messages to render. |
renderMessage | (message: ChatMessageData, index: number) => ReactNode | — | Custom renderer for individual messages. |
emptyState | ReactNode | — | Content shown when the messages array is empty. |
autoScroll | boolean | true | Auto-scroll to bottom on new messages. Pauses when user scrolls up, resumes at bottom. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatMessage
| Prop | Type | Default | Description |
|---|---|---|---|
message * | ChatMessageData | — | Message data object. |
showTimestamp | boolean | — | Show timestamp below the message content. |
showAvatar | boolean | — | Show avatar next to the message. |
actions | ReactNode | — | Action buttons rendered below the message (typically a ChatActionBar). |
renderContent | (content: string) => ReactNode | — | Custom content renderer for markdown, LaTeX, or other rich formats. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatInput
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Current input value (controlled). |
onChange | (value: string) => void | — | Change handler for controlled usage. |
onSubmit | (value: string, attachments: ChatAttachmentData[]) => void | — | Called when the user submits the message. |
onStop | () => void | — | Called when the user clicks the stop generation button. |
placeholder | string | — | Placeholder text for the input. |
streaming | boolean | false | Whether the assistant is currently streaming. Shows stop button instead of send. |
disabled | boolean | — | Disable the input. |
submitKey | 'enter' | 'ctrl+enter' | 'enter' | Key combination that submits the message. The other combination inserts a newline. |
maxLines | number | 6 | Maximum visible lines before the input scrolls. |
attachments | ChatAttachmentData[] | — | Currently attached items shown as chips above the input. |
onRemoveAttachment | (attachmentId: string) => void | — | Called when user removes an attachment chip. |
prefix | ReactNode | — | Content rendered before the textarea (e.g., context chips). |
suffix | ReactNode | — | Content rendered after the textarea (e.g., additional action buttons). |
toolbar | ReactNode | — | Toolbar rendered below the input area (use ChatInputToolbar as the wrapper). |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatTypingIndicator
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | 'Thinking...' | Label shown alongside the animation. |
variant | 'dots' | 'pulse' | 'dots' | Animation style: three animated dots or a pulsing bar. |
visible | boolean | — | Whether the indicator is visible. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatToolCall
| Prop | Type | Default | Description |
|---|---|---|---|
toolCall * | ChatToolCallData | — | Tool call data object with id, name, status, input, output, error, and duration. |
collapsible | boolean | true | Whether the input/output details can be expanded. |
defaultExpanded | boolean | false | Whether details are initially expanded. |
icon | ReactNode | — | Custom icon for the tool (defaults to a wrench icon). |
renderOutput | (output: Record<string, unknown>) => ReactNode | — | Custom renderer for the tool output. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatCodeBlock
| Prop | Type | Default | Description |
|---|---|---|---|
code * | string | — | Code content to display. |
language | string | — | Programming language for syntax highlighting. |
copyable | boolean | true | Show a copy-to-clipboard button. |
lineNumbers | boolean | false | Show line numbers. |
maxHeight | number | 400 | Maximum visible height in pixels before the block scrolls. |
actions | ReactNode | — | Actions rendered in the code block header alongside the copy button. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatAttachmentChip
| Prop | Type | Default | Description |
|---|---|---|---|
attachment * | ChatAttachmentData | — | Attachment data object. |
onRemove | (id: string) => void | — | Called when the remove button is clicked. |
onClick | (attachment: ChatAttachmentData) => void | — | Called when the chip itself is clicked (e.g., to preview). |
removable | boolean | false | Whether to show the remove button. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatContextChip
| Prop | Type | Default | Description |
|---|---|---|---|
label * | string | — | Label describing the context (e.g., "Selected", "Active file"). |
items * | string[] | — | Items in this context group. |
icon | ReactNode | — | Icon shown before the label. |
onDismiss | () => void | — | Called when the chip is dismissed. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
ChatEmptyState
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Main heading text. |
description | string | — | Supporting description text. |
icon | ReactNode | — | Icon or illustration. |
suggestions | string[] | — | Quick-start suggestion chips that populate the input when clicked. |
onSuggestionClick | (suggestion: string) => void | — | Called when a suggestion chip is clicked. |
className | string | — | Additional CSS class names. |
style | CSSProperties | — | Inline styles. |
testId | string | — | Test identifier for automated testing. |
Data Types
ChatMessageData
interface ChatMessageData { id: string; role: 'user' | 'assistant' | 'system' | 'tool'; content: string; status: 'complete' | 'streaming' | 'error' | 'pending'; timestamp: string; // ISO 8601 attachments?: ChatAttachmentData[]; toolCalls?: ChatToolCallData[]; avatar?: string; displayName?: string;}ChatAttachmentData
interface ChatAttachmentData { id: string; name: string; type: 'file' | 'image' | 'code' | 'selection'; mimeType?: string; size?: number; thumbnailUrl?: string; content?: string; meta?: Record<string, unknown>;}ChatToolCallData
interface ChatToolCallData { id: string; name: string; status: 'pending' | 'running' | 'completed' | 'error'; input?: Record<string, unknown>; output?: Record<string, unknown>; error?: string; durationMs?: number;}