@ainative/aikit-react
v0.1.0
Published
React components for AI-powered streaming interfaces
Maintainers
Readme
@aikit/react
React components for building AI-powered streaming interfaces with smooth animations and markdown support.
Features
- Streaming Message Component: Display AI messages with real-time streaming support
- Token-by-Token Animations: Smooth typewriter and fade-in effects for new tokens
- Markdown Rendering: Full markdown support with GFM (GitHub Flavored Markdown)
- Syntax Highlighting: Beautiful code blocks with multiple themes
- Accessible: WCAG 2.1 AA compliant with proper ARIA attributes
- Responsive: Mobile-first design that works on all screen sizes
- TypeScript: Fully typed with comprehensive TypeScript definitions
- Customizable: Extensive props for styling and behavior customization
Installation
npm install @aikit/reactOr with yarn:
yarn add @aikit/reactPeer Dependencies
This package requires React 18+ as a peer dependency:
npm install react react-domQuick Start
import { StreamingMessage } from '@aikit/react';
function ChatInterface() {
const [message, setMessage] = useState('');
return (
<StreamingMessage
role="assistant"
content={message}
streamingState="streaming"
enableMarkdown={true}
animationType="typewriter"
/>
);
}Components
StreamingMessage
The main component for displaying AI messages with streaming support.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| role | 'user' \| 'assistant' \| 'system' | Required | Message sender role |
| content | string | Required | Message content (can be partial during streaming) |
| streamingState | 'idle' \| 'streaming' \| 'complete' \| 'error' | 'idle' | Current streaming state |
| animationType | 'none' \| 'fade' \| 'typewriter' \| 'smooth' | 'smooth' | Animation type for new tokens |
| animationSpeed | number | 30 | Animation speed in ms per character |
| enableMarkdown | boolean | true | Enable markdown rendering |
| codeTheme | 'dark' \| 'light' \| 'vs-dark' \| 'github' \| 'monokai' \| 'nord' \| 'dracula' | 'dark' | Code syntax highlighting theme |
| showStreamingIndicator | boolean | true | Show streaming indicator |
| className | string | '' | Custom CSS class |
| style | CSSProperties | - | Custom inline styles |
| avatar | string \| ReactNode | - | Avatar URL or custom element |
| displayName | string | - | Display name for message sender |
| showTimestamp | boolean | false | Show message timestamp |
| metadata | MessageMetadata | - | Additional message metadata |
| onStreamingComplete | () => void | - | Callback when streaming completes |
| onContentUpdate | (content: string) => void | - | Callback on content updates |
| onError | (error: Error) => void | - | Error handler |
| enableCodeCopy | boolean | true | Enable copy button for code blocks |
| roleColors | object | - | Custom colors for each role |
| testId | string | 'streaming-message' | Test ID for testing |
Examples
Basic Usage
<StreamingMessage
role="assistant"
content="Hello! How can I help you today?"
streamingState="complete"
/>With Streaming Animation
<StreamingMessage
role="assistant"
content={streamingContent}
streamingState="streaming"
animationType="typewriter"
animationSpeed={20}
showStreamingIndicator={true}
/>With Markdown and Code Highlighting
<StreamingMessage
role="assistant"
content={`
# Code Example
Here's a JavaScript function:
\`\`\`javascript
function greet(name) {
return \`Hello, \${name}!\`;
}
\`\`\`
`}
enableMarkdown={true}
codeTheme="dracula"
enableCodeCopy={true}
/>With Avatar and Metadata
<StreamingMessage
role="assistant"
content="Processing your request..."
avatar="https://example.com/bot-avatar.png"
displayName="AI Assistant"
showTimestamp={true}
metadata={{
timestamp: new Date(),
model: 'gpt-4',
tokensUsed: 150
}}
/>With Custom Styling
<StreamingMessage
role="user"
content="What's the weather like?"
className="custom-message"
style={{ maxWidth: '600px' }}
roleColors={{
user: '#2196F3',
assistant: '#4CAF50',
system: '#FF9800'
}}
/>With Callbacks
<StreamingMessage
role="assistant"
content={content}
streamingState={streamingState}
onStreamingComplete={() => {
console.log('Streaming completed!');
saveMessage();
}}
onContentUpdate={(newContent) => {
console.log('Content updated:', newContent);
}}
onError={(error) => {
console.error('Streaming error:', error);
handleError(error);
}}
/>StreamingIndicator
Animated indicator for showing streaming progress.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | 'dots' \| 'pulse' \| 'wave' | 'dots' | Indicator style variant |
| className | string | '' | Custom CSS class |
| style | CSSProperties | - | Custom inline styles |
| testId | string | 'streaming-indicator' | Test ID for testing |
Examples
import { StreamingIndicator } from '@aikit/react';
// Dots variant (default)
<StreamingIndicator variant="dots" />
// Pulse variant
<StreamingIndicator variant="pulse" />
// Wave variant
<StreamingIndicator variant="wave" />
// With custom styling
<StreamingIndicator
variant="dots"
style={{ color: '#3b82f6' }}
/>CodeBlock
Syntax-highlighted code block with copy functionality.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| language | string | Required | Programming language |
| children | string | Required | Code content |
| theme | CodeTheme | 'dark' | Syntax highlighting theme |
| enableCopy | boolean | true | Enable copy button |
| className | string | '' | Custom CSS class |
| showLineNumbers | boolean | true | Show line numbers |
Examples
import { CodeBlock } from '@aikit/react';
// JavaScript code
<CodeBlock language="javascript">
{`function hello() {
return "world";
}`}
</CodeBlock>
// Python with custom theme
<CodeBlock language="python" theme="monokai">
{`def greet(name):
return f"Hello, {name}!"`}
</CodeBlock>
// Without copy button
<CodeBlock language="typescript" enableCopy={false}>
{`const x: number = 42;`}
</CodeBlock>Advanced Usage
Building a Chat Interface
import { useState, useEffect } from 'react';
import { StreamingMessage } from '@aikit/react';
interface ChatMessage {
id: string;
role: 'user' | 'assistant';
content: string;
streaming?: boolean;
}
function ChatInterface() {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [streamingContent, setStreamingContent] = useState('');
const handleSendMessage = async (text: string) => {
// Add user message
const userMessage: ChatMessage = {
id: Date.now().toString(),
role: 'user',
content: text,
};
setMessages(prev => [...prev, userMessage]);
// Start streaming assistant response
const assistantMessage: ChatMessage = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: '',
streaming: true,
};
setMessages(prev => [...prev, assistantMessage]);
// Simulate streaming
const fullResponse = await fetchAIResponse(text);
for (let i = 0; i < fullResponse.length; i++) {
setStreamingContent(fullResponse.slice(0, i + 1));
await new Promise(resolve => setTimeout(resolve, 20));
}
// Complete streaming
setMessages(prev =>
prev.map(msg =>
msg.id === assistantMessage.id
? { ...msg, content: fullResponse, streaming: false }
: msg
)
);
};
return (
<div className="chat-container">
{messages.map(message => (
<StreamingMessage
key={message.id}
role={message.role}
content={message.streaming ? streamingContent : message.content}
streamingState={message.streaming ? 'streaming' : 'complete'}
enableMarkdown={true}
animationType="typewriter"
showTimestamp={true}
metadata={{
timestamp: new Date(),
}}
/>
))}
</div>
);
}Custom Animation Timing
<StreamingMessage
role="assistant"
content={content}
streamingState="streaming"
animationType="typewriter"
animationSpeed={15} // Faster animation (15ms per character)
/>Handling Different Message Types
function MessageRenderer({ message }) {
const getAnimationType = (role) => {
switch (role) {
case 'user':
return 'none'; // No animation for user messages
case 'assistant':
return 'typewriter'; // Typewriter for AI responses
case 'system':
return 'fade'; // Fade for system messages
default:
return 'smooth';
}
};
return (
<StreamingMessage
role={message.role}
content={message.content}
streamingState={message.streamingState}
animationType={getAnimationType(message.role)}
roleColors={{
user: '#3b82f6',
assistant: '#10b981',
system: '#f59e0b',
}}
/>
);
}TypeScript Support
All components are fully typed with TypeScript. Import types as needed:
import type {
StreamingMessageProps,
MessageRole,
StreamingState,
AnimationType,
CodeTheme,
MessageMetadata,
} from '@aikit/react';Accessibility
All components follow WCAG 2.1 AA guidelines:
- Proper ARIA attributes for screen readers
- Keyboard navigation support
- Sufficient color contrast ratios
- Descriptive labels for interactive elements
- Status indicators for streaming states
Browser Support
- Chrome/Edge: Last 2 versions
- Firefox: Last 2 versions
- Safari: Last 2 versions
- Mobile browsers: iOS Safari 12+, Chrome Android
Testing
Components are tested with React Testing Library:
npm test
npm run test:coverageCoverage threshold: 80%+ for all metrics.
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
License
MIT
Support
For issues and questions, please visit our GitHub repository or contact support.
