UNPKG

juq-llm-kit

Version:

Customizable UI components for React Native (Expo) chat applications

232 lines (220 loc) • 9.17 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importStar(require("react")); const react_native_1 = require("react-native"); const vector_icons_1 = require("@expo/vector-icons"); const Clipboard = __importStar(require("expo-clipboard")); // Default sample messages for demo const defaultMessages = [ { id: 1, role: 'user', content: 'provide me shorter message', timestamp: new Date().toISOString(), }, { id: 2, role: 'assistant', content: `Here are some recent scientific discoveries: šŸš€ Space: JWST found tiny asteroids, and Voyager 1 re-established contact. 🧬 Medicine: New malaria vaccines, Alzheimer's drug (Kisunla), and the Human Cell Atlas. šŸŒŽ Environment: 27 new species discovered in Peru, a new rock skink found in Australia. šŸ’» Tech: Google DeepMind's AI (Gemini), advances in quantum computing. For more, check FT and NYPost. šŸš€`, timestamp: new Date().toISOString(), } ]; const Messages = ({ messages = defaultMessages, onCopy, onRegenerate, containerStyle, bubbleStyle, messageTextStyle, fontFamily, theme = 'dark', customActions }) => { const flatListRef = (0, react_1.useRef)(null); const colors = getThemeColors(theme); (0, react_1.useEffect)(() => { // Scroll to bottom when messages change if (flatListRef.current) { setTimeout(() => { var _a; (_a = flatListRef.current) === null || _a === void 0 ? void 0 : _a.scrollToEnd({ animated: true }); }, 100); } }, [messages]); const formatMessageContent = (content) => { return content.split('\n').map((line, i) => { if (line.trim() === '') { return <react_native_1.View key={i} style={{ height: 8 }}/>; } return (<react_native_1.Text key={i} style={[ styles.messageText, { color: colors.textColor, fontFamily }, messageTextStyle ]}> {line} </react_native_1.Text>); }); }; const copyToClipboard = (text, messageId) => __awaiter(void 0, void 0, void 0, function* () { yield Clipboard.setStringAsync(text); if (onCopy) { onCopy(text); } }); const handleRegenerate = (messageId) => { if (onRegenerate) { onRegenerate(messageId); } }; const renderMessage = ({ item }) => { const isUser = item.role === 'user'; return (<react_native_1.View style={[ styles.messageContainer, isUser ? styles.userMessageContainer : styles.assistantMessageContainer ]}> <react_native_1.View style={styles.messageHeader}> <react_native_1.Text style={[styles.senderName, { color: colors.secondaryTextColor }]}> {isUser ? 'You' : 'Assistant'} </react_native_1.Text> <react_native_1.Text style={[styles.timestamp, { color: colors.secondaryTextColor }]}> {new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} </react_native_1.Text> </react_native_1.View> <react_native_1.View style={[ styles.messageBubble, isUser ? { backgroundColor: colors.userBubbleBg } : { backgroundColor: colors.assistantBubbleBg }, bubbleStyle ]}> {formatMessageContent(item.content)} {!isUser && (<react_native_1.View style={[styles.messageActions, { borderTopColor: colors.borderColor }]}> <react_native_1.TouchableOpacity onPress={() => copyToClipboard(item.content, item.id)} style={styles.actionButton}> <vector_icons_1.Ionicons name="copy-outline" size={16} color={colors.iconColor}/> </react_native_1.TouchableOpacity> <react_native_1.TouchableOpacity style={styles.actionButton}> <vector_icons_1.Ionicons name="square-outline" size={16} color={colors.iconColor}/> </react_native_1.TouchableOpacity> <react_native_1.TouchableOpacity style={styles.actionButton} onPress={() => handleRegenerate(item.id)}> <vector_icons_1.Ionicons name="refresh-outline" size={16} color={colors.iconColor}/> </react_native_1.TouchableOpacity> <react_native_1.TouchableOpacity style={styles.actionButton}> <vector_icons_1.Ionicons name="ellipsis-horizontal" size={16} color={colors.iconColor}/> </react_native_1.TouchableOpacity> {/* Render custom actions if provided */} {customActions && customActions.map((action, index) => (<react_native_1.TouchableOpacity key={`custom-action-${index}`} style={styles.actionButton} onPress={() => action.onPress(item.id)}> {action.icon} </react_native_1.TouchableOpacity>))} </react_native_1.View>)} </react_native_1.View> </react_native_1.View>); }; return (<react_native_1.FlatList ref={flatListRef} data={messages} renderItem={renderMessage} keyExtractor={(item) => item.id.toString()} contentContainerStyle={[styles.messagesContainer, containerStyle]} showsVerticalScrollIndicator={react_native_1.Platform.OS === 'web'}/>); }; // Theme helper function function getThemeColors(theme) { if (theme === 'light') { return { backgroundColor: '#ffffff', userBubbleBg: '#e5e7eb', assistantBubbleBg: '#f3f4f6', textColor: '#111827', secondaryTextColor: '#6b7280', iconColor: '#6b7280', borderColor: '#d1d5db' }; } return { backgroundColor: '#111827', userBubbleBg: '#4B5563', assistantBubbleBg: '#1F2937', textColor: '#F9FAFB', secondaryTextColor: '#9CA3AF', iconColor: '#9CA3AF', borderColor: '#374151' }; } const styles = react_native_1.StyleSheet.create({ messagesContainer: { padding: 16, paddingBottom: 80, // Space for input }, messageContainer: { marginBottom: 16, maxWidth: '80%', }, userMessageContainer: { alignSelf: 'flex-end', }, assistantMessageContainer: { alignSelf: 'flex-start', }, messageHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 4, }, senderName: { fontSize: 14, fontWeight: '600', marginRight: 8, }, timestamp: { fontSize: 12, }, messageBubble: { padding: 12, borderRadius: 20, }, messageText: { fontSize: 15, marginBottom: 8, }, messageActions: { flexDirection: 'row', marginTop: 8, paddingTop: 8, borderTopWidth: 1, }, actionButton: { marginRight: 16, }, }); exports.default = Messages;