@xcelsior/ui-chat 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/hooks/useWebSocket.ts","../src/hooks/useMessages.ts","../src/utils/api.ts","../src/hooks/useFileUpload.ts","../src/hooks/useTypingIndicator.ts","../src/hooks/useResizableWidget.ts","../src/components/BrandIcons.tsx","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/MessageItem.tsx","../src/components/MarkdownMessage.tsx","../src/utils/markdown-styles.ts","../src/components/ThinkingIndicator.tsx","../src/components/ChatInput.tsx","../src/components/Chat.tsx","../src/components/PreChatForm.tsx","../src/hooks/useDraggablePosition.ts","../src/hooks/useChatWidgetState.ts","../src/components/TypingIndicator.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useWebSocket } from '../hooks/useWebSocket';\nimport { useMessages } from '../hooks/useMessages';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useTypingIndicator } from '../hooks/useTypingIndicator';\nimport { useResizableWidget } from '../hooks/useResizableWidget';\nimport { ChatHeader } from './ChatHeader';\nimport { MessageList } from './MessageList';\nimport { ChatInput } from './ChatInput';\nimport type { IChatConfig, IMessage, IUser } from '../types';\n\nexport interface ChatWidgetProps {\n config: IChatConfig;\n className?: string;\n variant?: 'popover' | 'fullPage';\n externalWebSocket?: WebSocket | null;\n onMinimize?: () => void;\n onClose?: () => void;\n /** Resolved position (left or right) from the parent Chat component */\n resolvedPosition?: 'left' | 'right';\n}\n\n/** Generate an anonymous user for progressive identity mode */\nfunction getAnonymousUser(): IUser {\n let anonId: string;\n try {\n const stored = localStorage.getItem('xcelsior-chat-anon-id');\n if (stored) {\n anonId = stored;\n } else {\n anonId = `anon-${crypto.randomUUID?.() || Math.random().toString(36).slice(2)}`;\n localStorage.setItem('xcelsior-chat-anon-id', anonId);\n }\n } catch {\n anonId = `anon-${Math.random().toString(36).slice(2)}`;\n }\n\n return {\n name: 'Visitor',\n email: `${anonId}@anonymous.xcelsior.co`,\n type: 'customer',\n status: 'online',\n };\n}\n\nexport function ChatWidget({\n config,\n className = '',\n variant = 'popover',\n externalWebSocket,\n onMinimize,\n onClose,\n resolvedPosition = 'right',\n}: ChatWidgetProps) {\n const isFullPage = variant === 'fullPage';\n\n // Resolve user — support anonymous mode for progressive identity\n const effectiveUser = config.currentUser || getAnonymousUser();\n const effectiveConfig = { ...config, currentUser: effectiveUser };\n\n const websocket = useWebSocket(effectiveConfig, externalWebSocket);\n\n const { messages, addMessage, isLoading, loadMore, hasMore, isLoadingMore, isBotThinking } =\n useMessages(websocket, effectiveConfig);\n\n const fileUpload = useFileUpload(config.apiKey, config.fileUpload);\n const { isTyping, typingUsers } = useTypingIndicator(websocket);\n\n const { width, height, isResizing, isNearEdge, containerResizeProps } = useResizableWidget({\n initialWidth: 380,\n initialHeight: 580,\n minWidth: 320,\n minHeight: 400,\n maxWidth: 800,\n maxHeight: 900,\n enabled: !isFullPage,\n });\n\n const handleSendMessage = useCallback(\n (content: string) => {\n if (!websocket.isConnected) {\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n const optimisticMessage: IMessage = {\n id: `temp-${Date.now()}`,\n conversationId: config.conversationId || '',\n senderId: effectiveUser.email,\n senderType: effectiveUser.type,\n content,\n messageType: 'text',\n createdAt: new Date().toISOString(),\n status: 'sent',\n };\n\n addMessage(optimisticMessage);\n\n websocket.sendMessage('sendMessage', {\n conversationId: config.conversationId,\n content,\n messageType: 'text',\n });\n\n config.onMessageSent?.(optimisticMessage);\n },\n [websocket, config, addMessage, effectiveUser]\n );\n\n const handleTyping = useCallback(\n (isTyping: boolean) => {\n if (!websocket.isConnected || config.enableTypingIndicator === false) return;\n websocket.sendMessage('typing', {\n conversationId: config.conversationId,\n isTyping,\n });\n },\n [websocket, config]\n );\n\n useEffect(() => {\n if (websocket.error) {\n config.toast?.error(websocket.error.message || 'An error occurred');\n }\n }, [websocket.error, config]);\n\n // Theme tokens — aligned with Xcelsior website design system\n const bgColor = config.theme?.background || '#00001a';\n const bgAlt = config.theme?.backgroundAlt || '#02164a';\n const textColor = config.theme?.text || '#f7f7f8';\n const primaryColor = config.theme?.primary || '#337eff';\n const textMuted = config.theme?.textMuted || 'rgba(247,247,248,0.45)';\n\n // Detect light vs dark theme based on background luminance\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n // Position-aware container styles\n const positionClass = resolvedPosition === 'left' ? 'left-4' : 'right-4';\n\n const containerStyle: React.CSSProperties = isFullPage\n ? { backgroundColor: bgColor, color: textColor }\n : {\n position: 'relative',\n width,\n height,\n maxHeight: 'calc(100vh - 100px)',\n backgroundColor: bgColor,\n color: textColor,\n borderRadius: 16,\n /* Xcelsior card pattern: inset box-shadow borders instead of border-image */\n boxShadow: isLightTheme\n ? [\n '0 25px 60px -12px rgba(0,0,0,0.15)',\n '0 0 0 1px rgba(0,0,0,0.08)',\n ].join(', ')\n : [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.12)',\n '0 25px 60px -12px rgba(0,0,0,0.6)',\n '0 0 40px -8px rgba(51,126,255,0.15)',\n ].join(', '),\n userSelect: isResizing ? 'none' : undefined,\n };\n\n /* Dot grid texture matching the Xcelsior website background */\n const dotGridBg: React.CSSProperties = !isFullPage\n ? {\n backgroundImage: isLightTheme\n ? `radial-gradient(circle, rgba(0,0,0,0.04) 1px, transparent 1px)`\n : `radial-gradient(circle, rgba(255,255,255,0.03) 1px, transparent 1px)`,\n backgroundSize: '24px 24px',\n }\n : {};\n\n // Subtle edge glow when user hovers near a resize edge\n // Uses outline (not clipped by overflow:hidden) for visibility\n const edgeHintStyle: React.CSSProperties = !isFullPage && isNearEdge\n ? {\n outline: isLightTheme\n ? '2px solid rgba(0,94,255,0.25)'\n : '2px solid rgba(51,126,255,0.35)',\n outlineOffset: -1,\n transition: 'outline 150ms ease',\n }\n : {\n outline: '2px solid transparent',\n outlineOffset: -1,\n transition: 'outline 150ms ease',\n };\n\n return (\n <div\n className={\n isFullPage\n ? `flex flex-col h-full ${className}`\n : `fixed bottom-20 ${positionClass} z-50 flex flex-col overflow-hidden ${className}`\n }\n style={{ ...containerStyle, ...dotGridBg, ...edgeHintStyle }}\n {...(!isFullPage ? containerResizeProps : {})}\n >\n {!isFullPage && (\n <ChatHeader\n agent={\n effectiveUser.type === 'customer'\n ? {\n email: 'contact@xcelsior.co',\n name: 'Xcelsior Software',\n type: 'agent',\n status: websocket.isConnected ? 'online' : 'offline',\n }\n : undefined\n }\n onMinimize={onMinimize}\n onClose={onClose}\n theme={config.theme}\n />\n )}\n\n {/* Connection Status */}\n {!websocket.isConnected && (\n <div\n className=\"px-4 py-2\"\n style={{\n backgroundColor: isLightTheme ? 'rgba(255,169,56,0.08)' : 'rgba(255,169,56,0.06)',\n borderBottom: `1px solid rgba(255,169,56,${isLightTheme ? '0.15' : '0.12'})`,\n }}\n >\n <div className=\"flex items-center gap-2\">\n <div\n className=\"w-1.5 h-1.5 rounded-full animate-pulse\"\n style={{ backgroundColor: config.theme?.statusCaution || '#ffa938' }}\n />\n <span\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: config.theme?.statusCaution || '#ffa938',\n }}\n >\n Reconnecting...\n </span>\n <button\n type=\"button\"\n onClick={websocket.reconnect}\n className=\"ml-auto transition-opacity\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: config.theme?.statusCaution || '#ffa938',\n opacity: 0.7,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7';\n }}\n >\n Retry\n </button>\n </div>\n </div>\n )}\n\n {/* Messages */}\n {isLoading ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <div className=\"text-center\">\n <div\n className=\"w-7 h-7 border-2 border-t-transparent rounded-full animate-spin mx-auto mb-3\"\n style={{\n borderColor: primaryColor,\n borderTopColor: 'transparent',\n }}\n />\n <p\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: textMuted,\n }}\n >\n Loading messages...\n </p>\n </div>\n </div>\n ) : (\n <MessageList\n messages={messages}\n currentUser={effectiveUser}\n isTyping={isTyping}\n typingUser={typingUsers[0]}\n autoScroll={true}\n onLoadMore={loadMore}\n hasMore={hasMore}\n isLoadingMore={isLoadingMore}\n theme={config.theme}\n onQuickAction={handleSendMessage}\n isBotThinking={isBotThinking}\n />\n )}\n\n {/* Input */}\n <ChatInput\n onSend={handleSendMessage}\n onTyping={handleTyping}\n config={effectiveConfig}\n fileUpload={fileUpload}\n disabled={!websocket.isConnected}\n />\n\n {/* Powered by footer */}\n {!isFullPage && (\n <div\n className=\"px-4 py-1.5 text-center\"\n style={{\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.06)'\n : '1px solid rgba(255,255,255,0.06)',\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.03)'\n : 'rgba(0,0,0,0.2)',\n }}\n >\n <p\n style={{\n fontSize: '10px',\n letterSpacing: '0.025em',\n color: isLightTheme\n ? 'rgba(0,0,0,0.35)'\n : 'rgba(247,247,248,0.28)',\n }}\n >\n Powered by{' '}\n <span style={{\n fontWeight: 600,\n color: isLightTheme\n ? 'rgba(0,0,0,0.5)'\n : 'rgba(247,247,248,0.45)',\n }}>\n Xcelsior\n </span>\n </p>\n </div>\n )}\n\n </div>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from 'react';\nimport type { IChatConfig, IWebSocketMessage } from '../types';\n\nexport interface UseWebSocketReturn {\n isConnected: boolean;\n sendMessage: (action: string, data: any) => void;\n lastMessage: IWebSocketMessage | null;\n error: Error | null;\n reconnect: () => void;\n}\n\n/**\n * Hook for WebSocket connection in chat widget.\n * Can use an external WebSocket connection (for agents) via the externalWebSocket prop.\n */\nexport function useWebSocket(\n config: IChatConfig,\n externalWebSocket?: WebSocket | null\n): UseWebSocketReturn {\n const [isConnected, setIsConnected] = useState(false);\n const [lastMessage, setLastMessage] = useState<IWebSocketMessage | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const wsRef = useRef<WebSocket | null>(null);\n const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | null>(null);\n const maxReconnectAttempts = 5;\n const reconnectDelay = 3000;\n\n // Use external WebSocket if provided (for agents)\n const isUsingExternalWs = !!externalWebSocket;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const subscribeToMessage = useCallback((webSocket: WebSocket) => {\n // Remove previous listener if it exists\n if (messageHandlerRef.current) {\n webSocket.removeEventListener('message', messageHandlerRef.current);\n }\n\n // Create new message handler\n const handler = (event: MessageEvent) => {\n try {\n const message: IWebSocketMessage = JSON.parse(event.data);\n setLastMessage(message);\n\n // Handle different message types\n if (message.type === 'message' && message.data) {\n config.onMessageReceived?.(message.data);\n } else if (message.type === 'error') {\n const err = new Error(message.data?.message || 'WebSocket error');\n setError(err);\n config.onError?.(err);\n }\n } catch (err) {\n console.error('Failed to parse WebSocket message:', err);\n }\n };\n\n // Add the new listener\n webSocket.addEventListener('message', handler);\n messageHandlerRef.current = handler;\n\n // Return cleanup function\n return () => {\n webSocket.removeEventListener('message', handler);\n if (messageHandlerRef.current === handler) {\n messageHandlerRef.current = null;\n }\n };\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const connect = useCallback(() => {\n console.log('connecting to WebSocket...', config.currentUser, config.conversationId);\n try {\n // Clean up existing connection\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close();\n }\n\n // Build WebSocket URL with query parameters\n const url = new URL(config.websocketUrl);\n url.searchParams.set('user', JSON.stringify(config.currentUser));\n if (config.conversationId) {\n url.searchParams.set('conversationId', config.conversationId);\n }\n if (config.apiKey) {\n url.searchParams.set('apiKey', config.apiKey);\n }\n\n const ws = new WebSocket(url.toString());\n\n ws.onopen = () => {\n console.log('WebSocket connected');\n setIsConnected(true);\n setError(null);\n reconnectAttemptsRef.current = 0;\n config.onConnectionChange?.(true);\n };\n\n ws.onerror = (event) => {\n console.error('WebSocket error:', event);\n const err = new Error('WebSocket connection error');\n setError(err);\n config.onError?.(err);\n };\n\n ws.onclose = (event) => {\n console.log('WebSocket closed:', event.code, event.reason);\n setIsConnected(false);\n config.onConnectionChange?.(false);\n wsRef.current = null;\n\n // Attempt to reconnect if not a normal closure\n if (event.code !== 1000 && reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current += 1;\n console.log(\n `Reconnecting... (${reconnectAttemptsRef.current}/${maxReconnectAttempts})`\n );\n reconnectTimeoutRef.current = setTimeout(() => {\n connect();\n }, reconnectDelay);\n }\n };\n\n subscribeToMessage(ws);\n wsRef.current = ws ?? null;\n } catch (err) {\n console.error('Failed to create WebSocket connection:', err);\n const error = err instanceof Error ? err : new Error('Failed to connect');\n setError(error);\n config.onError?.(error);\n }\n }, [JSON.stringify([config.currentUser, config.conversationId])]);\n\n const sendMessage = useCallback(\n (action: string, data: any) => {\n if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {\n console.error('WebSocket is not connected');\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n try {\n wsRef.current.send(\n JSON.stringify({\n action,\n data,\n })\n );\n } catch (err) {\n console.error('Failed to send message:', err);\n const error = err instanceof Error ? err : new Error('Failed to send message');\n setError(error);\n config.onError?.(error);\n }\n },\n [config]\n );\n\n const reconnect = useCallback(() => {\n reconnectAttemptsRef.current = 0;\n connect();\n }, [connect]);\n\n useEffect(() => {\n if (isUsingExternalWs) {\n setIsConnected(externalWebSocket?.readyState === WebSocket.OPEN || false);\n wsRef.current = externalWebSocket;\n const cleanup = subscribeToMessage(externalWebSocket);\n return cleanup;\n }\n\n connect();\n\n // Cleanup on unmount\n return () => {\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n }\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close(1000, 'Component unmounted');\n }\n };\n }, [connect, isUsingExternalWs, externalWebSocket, subscribeToMessage]);\n\n // Use external connection state if available\n const effectiveIsConnected = isUsingExternalWs\n ? externalWebSocket?.readyState === WebSocket.OPEN || false\n : isConnected;\n\n return {\n isConnected: effectiveIsConnected,\n sendMessage,\n lastMessage,\n error,\n reconnect,\n };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { IMessage, IChatConfig, UseMessagesReturn } from '../types';\nimport type { UseWebSocketReturn } from './useWebSocket';\nimport { fetchMessages } from '../utils/api';\n\nexport function useMessages(websocket: UseWebSocketReturn, config: IChatConfig): UseMessagesReturn {\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nextPageToken, setNextPageToken] = useState<string | undefined>(undefined);\n const [hasMore, setHasMore] = useState(true);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n const [isBotThinking, setIsBotThinking] = useState(false);\n\n // Extract stable references from config\n const { httpApiUrl, conversationId, headers, onError, toast } = config;\n\n const headersWithApiKey = useMemo(\n () => ({\n ...headers,\n 'x-api-key': config.apiKey,\n }),\n [headers, config.apiKey]\n );\n\n // Fetch existing messages when conversationId changes\n useEffect(() => {\n const loadMessages = async () => {\n // Only fetch if we have httpApiUrl and conversationId\n if (!httpApiUrl || !conversationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n { conversationId, limit: 20 },\n headersWithApiKey\n );\n\n setMessages(result.data);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load messages');\n setError(error);\n onError?.(error);\n toast?.error('Failed to load existing messages');\n } finally {\n setIsLoading(false);\n }\n };\n\n loadMessages();\n // Only re-run when conversationId or httpApiUrl changes\n }, [conversationId, httpApiUrl, headersWithApiKey, onError, toast]);\n\n // Extract onMessageReceived callback\n const { onMessageReceived } = config;\n\n // Listen for incoming messages from WebSocket\n useEffect(() => {\n if (websocket.lastMessage?.type === 'message' && websocket.lastMessage.data) {\n const newMessage: IMessage = websocket.lastMessage.data;\n\n if (conversationId && newMessage.conversationId !== conversationId) {\n // Ignore messages for other conversations\n return;\n }\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === newMessage.id)) {\n return prev;\n }\n return [...prev, newMessage];\n });\n\n // Clear bot thinking state when bot or system message arrives\n if (newMessage.senderType === 'bot' || newMessage.senderType === 'system') {\n setIsBotThinking(false);\n }\n\n // Notify parent component about new message\n onMessageReceived?.(newMessage);\n }\n }, [websocket.lastMessage, onMessageReceived, conversationId]);\n\n const addMessage = useCallback((message: IMessage) => {\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === message.id)) {\n return prev;\n }\n return [...prev, message];\n });\n // Show bot thinking indicator immediately when customer sends a message\n if (message.senderType === 'customer') {\n setIsBotThinking(true);\n }\n }, []);\n\n const updateMessageStatus = useCallback((messageId: string, status: IMessage['status']) => {\n setMessages((prev) => prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg)));\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n }, []);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || isLoadingMore || !httpApiUrl || !conversationId || !nextPageToken) {\n return;\n }\n\n setIsLoadingMore(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n {\n conversationId,\n limit: 20,\n pageToken: nextPageToken,\n },\n headersWithApiKey\n );\n\n setMessages((prev) => [...result.data, ...prev]);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load more messages');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoadingMore(false);\n }\n }, [\n hasMore,\n isLoadingMore,\n httpApiUrl,\n conversationId,\n nextPageToken,\n headersWithApiKey,\n onError,\n ]);\n\n return {\n messages,\n addMessage,\n updateMessageStatus,\n clearMessages,\n isLoading,\n error,\n loadMore,\n hasMore,\n isLoadingMore,\n isBotThinking,\n };\n}\n","import axios from 'axios';\nimport type { IMessage, IApiResponse } from '../types';\n\nexport interface FetchMessagesParams {\n conversationId: string;\n limit?: number;\n pageToken?: string;\n}\n\n/**\n * Fetch messages for a conversation from the REST API\n */\nexport async function fetchMessages(\n baseUrl: string,\n params: FetchMessagesParams,\n headers?: Record<string, string>\n) {\n try {\n const response = await axios.get<IApiResponse<IMessage[]>>(`${baseUrl}/messages`, {\n params: {\n conversationId: params.conversationId,\n limit: params.limit || 50,\n pageToken: params.pageToken,\n },\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n });\n\n return {\n data: response.data.data ?? [],\n nextPageToken: response.data.pagination?.nextPageToken,\n };\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(\n error.response?.data?.error?.message || error.message || 'Failed to fetch messages'\n );\n }\n throw error;\n }\n}\n","import { useState } from 'react';\nimport axios from 'axios';\nimport type { IFileUploadConfig, IUploadedFile } from '../types';\n\nexport interface UseFileUploadReturn {\n uploadFile: (file: File) => Promise<IUploadedFile | null>;\n isUploading: boolean;\n uploadProgress: number;\n error: Error | null;\n canUpload: boolean;\n}\n\nexport function useFileUpload(apiKey: string, config?: IFileUploadConfig): UseFileUploadReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadProgress, setUploadProgress] = useState(0);\n const [error, setError] = useState<Error | null>(null);\n\n const defaultConfig = {\n maxFileSize: 10 * 1024 * 1024, // 10MB default\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n };\n\n const finalConfig = { ...defaultConfig, ...config };\n const canUpload = !!config?.uploadUrl;\n\n const validateFile = (file: File): string | null => {\n if (!finalConfig.allowedTypes.includes(file.type)) {\n return `File type ${file.type} is not supported. Allowed types: ${finalConfig.allowedTypes.join(', ')}`;\n }\n\n if (file.size > finalConfig.maxFileSize) {\n return `File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds the maximum allowed size of ${(finalConfig.maxFileSize / 1024 / 1024).toFixed(2)}MB`;\n }\n\n return null;\n };\n\n const uploadFile = async (file: File): Promise<IUploadedFile | null> => {\n if (!config?.uploadUrl) {\n const err = new Error('File upload URL is not configured');\n setError(err);\n throw err;\n }\n\n const validationError = validateFile(file);\n if (validationError) {\n const err = new Error(validationError);\n setError(err);\n throw err;\n }\n\n setIsUploading(true);\n setUploadProgress(0);\n setError(null);\n\n try {\n // Step 1: Get presigned upload URL from the API\n const uploadUrlResponse = await axios.post(\n config.uploadUrl,\n {\n fileName: file.name,\n contentType: file.type,\n fileSize: file.size,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey || '',\n ...config.headers,\n },\n }\n );\n\n const { uploadUrl, attachmentUrl } =\n uploadUrlResponse.data.data || uploadUrlResponse.data;\n\n if (!uploadUrl || !attachmentUrl) {\n throw new Error('Failed to get upload URL from server');\n }\n\n // Step 2: Upload file directly to S3 using presigned URL\n await axios.put(uploadUrl, file, {\n headers: {\n 'Content-Type': file.type,\n },\n onUploadProgress: (progressEvent) => {\n if (progressEvent.total) {\n const progress = Math.round(\n (progressEvent.loaded * 100) / progressEvent.total\n );\n setUploadProgress(progress);\n }\n },\n });\n\n return {\n url: attachmentUrl,\n name: file.name,\n size: file.size,\n type: file.type,\n markdown: file.type.startsWith('image/')\n ? `![${file.name}](${attachmentUrl})`\n : `[${file.name}](${attachmentUrl})`,\n };\n } catch (err) {\n console.error('File upload failed:', err);\n const error = err instanceof Error ? err : new Error('Upload failed');\n setError(error);\n throw error;\n } finally {\n setIsUploading(false);\n setUploadProgress(0);\n }\n };\n\n return {\n uploadFile,\n isUploading,\n uploadProgress,\n error,\n canUpload,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { UseWebSocketReturn } from './useWebSocket';\n\nexport interface UseTypingIndicatorReturn {\n isTyping: boolean;\n typingUsers: string[];\n}\n\nexport function useTypingIndicator(websocket: UseWebSocketReturn): UseTypingIndicatorReturn {\n const [typingUsers, setTypingUsers] = useState<string[]>([]);\n\n useEffect(() => {\n if (websocket.lastMessage?.type === 'typing' && websocket.lastMessage.data) {\n const { userId, isTyping } = websocket.lastMessage.data;\n\n if (isTyping) {\n setTypingUsers((prev) => {\n if (!prev.includes(userId)) {\n return [...prev, userId];\n }\n return prev;\n });\n } else {\n setTypingUsers((prev) => prev.filter((id) => id !== userId));\n }\n }\n }, [websocket.lastMessage]);\n\n return {\n isTyping: typingUsers.length > 0,\n typingUsers,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type ResizeEdge = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\ninterface UseResizableWidgetOptions {\n initialWidth?: number;\n initialHeight?: number;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n storageKey?: string;\n enabled?: boolean;\n}\n\nexport interface UseResizableWidgetReturn {\n width: number;\n height: number;\n isResizing: boolean;\n /** Attach to the widget container for edge/corner resize zones */\n containerResizeProps: {\n onMouseMove: (e: React.MouseEvent) => void;\n onMouseDown: (e: React.MouseEvent) => void;\n onMouseLeave: (e: React.MouseEvent) => void;\n onTouchStart: (e: React.TouchEvent) => void;\n };\n /** True when user hovers near a resize edge — use for visual hint */\n isNearEdge: boolean;\n /** Which edge/corner the user is near or dragging */\n activeEdge: ResizeEdge | null;\n}\n\nconst STORAGE_KEY = 'xcelsior-chat-size';\nconst EDGE_ZONE = 8; // px from edge to trigger resize cursor\n\nconst CURSOR_MAP: Record<ResizeEdge, string> = {\n n: 'ns-resize',\n s: 'ns-resize',\n e: 'ew-resize',\n w: 'ew-resize',\n ne: 'nesw-resize',\n nw: 'nwse-resize',\n se: 'nwse-resize',\n sw: 'nesw-resize',\n};\n\nfunction readStoredSize(\n key: string,\n fallbackWidth: number,\n fallbackHeight: number,\n): { width: number; height: number } {\n try {\n const stored = localStorage.getItem(key);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed.width === 'number' && typeof parsed.height === 'number') {\n return { width: parsed.width, height: parsed.height };\n }\n }\n } catch {\n // localStorage unavailable\n }\n return { width: fallbackWidth, height: fallbackHeight };\n}\n\nfunction persistSize(key: string, width: number, height: number) {\n try {\n localStorage.setItem(key, JSON.stringify({ width, height }));\n } catch {\n // Storage unavailable\n }\n}\n\nfunction isMobile(): boolean {\n return typeof window !== 'undefined' && window.innerWidth < 768;\n}\n\n/** Detect which edge/corner the mouse is near */\nfunction detectEdge(\n e: { clientX: number; clientY: number },\n rect: DOMRect,\n): ResizeEdge | null {\n const { clientX: x, clientY: y } = e;\n const nearTop = y - rect.top < EDGE_ZONE;\n const nearBottom = rect.bottom - y < EDGE_ZONE;\n const nearLeft = x - rect.left < EDGE_ZONE;\n const nearRight = rect.right - x < EDGE_ZONE;\n\n if (nearTop && nearLeft) return 'nw';\n if (nearTop && nearRight) return 'ne';\n if (nearBottom && nearLeft) return 'sw';\n if (nearBottom && nearRight) return 'se';\n if (nearTop) return 'n';\n if (nearBottom) return 's';\n if (nearLeft) return 'w';\n if (nearRight) return 'e';\n return null;\n}\n\nexport function useResizableWidget({\n initialWidth = 380,\n initialHeight = 580,\n minWidth = 320,\n minHeight = 400,\n maxWidth = 800,\n maxHeight = 900,\n storageKey = STORAGE_KEY,\n enabled = true,\n}: UseResizableWidgetOptions = {}): UseResizableWidgetReturn {\n const [size, setSize] = useState<{ width: number; height: number }>(() => {\n if (typeof window === 'undefined') return { width: initialWidth, height: initialHeight };\n return readStoredSize(storageKey, initialWidth, initialHeight);\n });\n const [isResizing, setIsResizing] = useState(false);\n const [isNearEdge, setIsNearEdge] = useState(false);\n const [activeEdge, setActiveEdge] = useState<ResizeEdge | null>(null);\n\n const sizeRef = useRef(size);\n sizeRef.current = size;\n\n const dragRef = useRef<{\n edge: ResizeEdge;\n startX: number;\n startY: number;\n startWidth: number;\n startHeight: number;\n } | null>(null);\n\n const containerRef = useRef<HTMLElement | null>(null);\n\n const clamp = useCallback(\n (w: number, h: number) => {\n const mxW = Math.min(maxWidth, window.innerWidth - 24);\n const mxH = Math.min(maxHeight, window.innerHeight - 100);\n return {\n width: Math.round(Math.max(minWidth, Math.min(mxW, w))),\n height: Math.round(Math.max(minHeight, Math.min(mxH, h))),\n };\n },\n [minWidth, minHeight, maxWidth, maxHeight],\n );\n\n /** Calculate new size from drag delta based on which edge is being dragged */\n const calcSize = useCallback(\n (dx: number, dy: number) => {\n if (!dragRef.current) return sizeRef.current;\n const { edge, startWidth, startHeight } = dragRef.current;\n\n let w = startWidth;\n let h = startHeight;\n\n // Horizontal: east edges expand right, west edges expand left (invert delta)\n if (edge.includes('e')) w = startWidth + dx;\n if (edge.includes('w')) w = startWidth - dx;\n\n // Vertical: south edges expand down, north edges expand up (invert delta)\n if (edge.includes('s')) h = startHeight + dy;\n if (edge.includes('n')) h = startHeight - dy;\n\n return clamp(w, h);\n },\n [clamp],\n );\n\n // ─── Mouse handlers ──────────────────────────────────────────────────\n\n const handleDocMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n setSize(calcSize(dx, dy));\n },\n [calcSize],\n );\n\n const handleDocMouseUp = useCallback(\n (e: MouseEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n const final = calcSize(dx, dy);\n persistSize(storageKey, final.width, final.height);\n dragRef.current = null;\n setIsResizing(false);\n setActiveEdge(null);\n document.body.style.cursor = '';\n document.removeEventListener('mousemove', handleDocMouseMove);\n document.removeEventListener('mouseup', handleDocMouseUp);\n },\n [calcSize, storageKey, handleDocMouseMove],\n );\n\n // ─── Touch handlers ──────────────────────────────────────────────────\n\n const handleDocTouchMove = useCallback(\n (e: TouchEvent) => {\n if (!dragRef.current || e.touches.length === 0) return;\n e.preventDefault();\n const t = e.touches[0];\n const dx = t.clientX - dragRef.current.startX;\n const dy = t.clientY - dragRef.current.startY;\n setSize(calcSize(dx, dy));\n },\n [calcSize],\n );\n\n const handleDocTouchEnd = useCallback(\n (e: TouchEvent) => {\n if (!dragRef.current) return;\n const t = e.changedTouches[0];\n if (t) {\n const dx = t.clientX - dragRef.current.startX;\n const dy = t.clientY - dragRef.current.startY;\n const final = calcSize(dx, dy);\n persistSize(storageKey, final.width, final.height);\n }\n dragRef.current = null;\n setIsResizing(false);\n setActiveEdge(null);\n document.removeEventListener('touchmove', handleDocTouchMove);\n document.removeEventListener('touchend', handleDocTouchEnd);\n },\n [calcSize, storageKey, handleDocTouchMove],\n );\n\n // ─── Cleanup ─────────────────────────────────────────────────────────\n\n useEffect(() => {\n return () => {\n document.removeEventListener('mousemove', handleDocMouseMove);\n document.removeEventListener('mouseup', handleDocMouseUp);\n document.removeEventListener('touchmove', handleDocTouchMove);\n document.removeEventListener('touchend', handleDocTouchEnd);\n document.body.style.cursor = '';\n };\n }, [handleDocMouseMove, handleDocMouseUp, handleDocTouchMove, handleDocTouchEnd]);\n\n // ─── Container event props ───────────────────────────────────────────\n\n const onContainerMouseMove = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled || isMobile() || isResizing) return;\n const el = e.currentTarget as HTMLElement;\n containerRef.current = el;\n const rect = el.getBoundingClientRect();\n const edge = detectEdge(e, rect);\n setIsNearEdge(!!edge);\n setActiveEdge(edge);\n el.style.cursor = edge ? CURSOR_MAP[edge] : '';\n },\n [enabled, isResizing],\n );\n\n const onContainerMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled || isMobile() || !activeEdge) return;\n // Only start resize if near an edge\n e.preventDefault();\n e.stopPropagation();\n dragRef.current = {\n edge: activeEdge,\n startX: e.clientX,\n startY: e.clientY,\n startWidth: sizeRef.current.width,\n startHeight: sizeRef.current.height,\n };\n setIsResizing(true);\n document.body.style.cursor = CURSOR_MAP[activeEdge];\n document.addEventListener('mousemove', handleDocMouseMove);\n document.addEventListener('mouseup', handleDocMouseUp);\n },\n [enabled, activeEdge, handleDocMouseMove, handleDocMouseUp],\n );\n\n const onContainerMouseLeave = useCallback(\n (_e: React.MouseEvent) => {\n if (!isResizing) {\n setIsNearEdge(false);\n setActiveEdge(null);\n if (containerRef.current) containerRef.current.style.cursor = '';\n }\n },\n [isResizing],\n );\n\n const onContainerTouchStart = useCallback(\n (e: React.TouchEvent) => {\n if (!enabled || isMobile() || e.touches.length === 0) return;\n const el = e.currentTarget as HTMLElement;\n const rect = el.getBoundingClientRect();\n const t = e.touches[0];\n const edge = detectEdge(t, rect);\n if (!edge) return;\n\n dragRef.current = {\n edge,\n startX: t.clientX,\n startY: t.clientY,\n startWidth: sizeRef.current.width,\n startHeight: sizeRef.current.height,\n };\n setIsResizing(true);\n setActiveEdge(edge);\n document.addEventListener('touchmove', handleDocTouchMove, { passive: false });\n document.addEventListener('touchend', handleDocTouchEnd);\n },\n [enabled, handleDocTouchMove, handleDocTouchEnd],\n );\n\n return {\n width: size.width,\n height: size.height,\n isResizing,\n isNearEdge,\n activeEdge,\n containerResizeProps: {\n onMouseMove: onContainerMouseMove,\n onMouseDown: onContainerMouseDown,\n onMouseLeave: onContainerMouseLeave,\n onTouchStart: onContainerTouchStart,\n },\n };\n}\n","import type { CSSProperties } from 'react';\n\ninterface BrandIconProps {\n size?: number;\n color?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Xcelsior \"X\" symbol mark (from favicon-brand.svg)\n * Reusable across the chat widget — FAB button, avatar, header, etc.\n */\nexport function XcelsiorSymbol({ size = 24, color = 'white', className = '', style }: BrandIconProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n style={style}\n aria-hidden=\"true\"\n >\n <path\n d=\"M20.582 15.027L31.849 0.036H24.808L17.039 10.303L20.582 15.027ZM24.808 31.837H31.849L20.582 16.846L17.039 21.57L24.808 31.837Z\"\n fill={color}\n />\n <path\n d=\"M14.313 15.027H18.402L7.135 0.036H0.185L9.406 12.392C10.587 13.983 12.359 15.027 14.313 15.027Z\"\n fill={color}\n />\n <path\n d=\"M0.185 31.837H7.135L18.402 16.846H14.313C12.359 16.846 10.588 17.891 9.406 19.481L0.185 31.837Z\"\n fill={color}\n />\n </svg>\n );\n}\n\n/**\n * Chat bubble icon for the FAB launcher button.\n * Instantly recognizable as a chat trigger.\n */\nexport function ChatBubbleIcon({ size = 28, color = 'white', className = '', style }: BrandIconProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={color}\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n style={style}\n aria-hidden=\"true\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n/**\n * Xcelsior \"X\" avatar — symbol inside a gradient circle\n * Used as bot avatar in messages and chat header\n */\nexport function XcelsiorAvatar({ size = 40, className = '' }: { size?: number; className?: string }) {\n const iconSize = Math.round(size * 0.55);\n return (\n <div\n className={`flex items-center justify-center rounded-full ${className}`}\n style={{\n width: size,\n height: size,\n background: 'linear-gradient(135deg, #337eff, #005eff)',\n }}\n >\n <XcelsiorSymbol size={iconSize} color=\"white\" />\n </div>\n );\n}\n","import type { IChatTheme, IUser } from '../types';\nimport { XcelsiorSymbol } from './BrandIcons';\n\ninterface ChatHeaderProps {\n agent?: IUser;\n onClose?: () => void;\n onMinimize?: () => void;\n theme?: IChatTheme;\n}\n\nexport function ChatHeader({ agent, onClose, onMinimize, theme }: ChatHeaderProps) {\n return (\n <div\n className=\"relative text-white overflow-hidden\"\n style={{\n flexShrink: 0,\n /* Layered blue smoke/glow effect for premium look */\n background: [\n 'radial-gradient(ellipse at 30% 50%, rgba(0,50,255,0.4) 0%, transparent 60%)',\n 'radial-gradient(ellipse at 70% 30%, rgba(0,80,255,0.3) 0%, transparent 50%)',\n 'radial-gradient(ellipse at 50% 80%, rgba(0,30,200,0.3) 0%, transparent 60%)',\n `linear-gradient(135deg, #0030cc 0%, #001a66 50%, #000d33 100%)`,\n ].join(', '),\n }}\n >\n {/* Top glass highlight — subtle light sweep for depth */}\n <div\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n background:\n 'linear-gradient(180deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 50%)',\n }}\n />\n\n <div className=\"flex items-center justify-between\" style={{ padding: '8px 16px' }}>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n {agent?.avatar ? (\n <img\n src={agent.avatar}\n alt={agent.name}\n className=\"h-10 w-10 rounded-full object-cover\"\n style={{\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n }}\n />\n ) : (\n <div style={{ filter: 'drop-shadow(0 2px 8px rgba(0,0,0,0.3))' }}>\n <XcelsiorSymbol size={28} color=\"white\" />\n </div>\n )}\n {agent?.status === 'online' && (\n <div\n className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full\"\n style={{\n backgroundColor: theme?.statusPositive || '#1ed473',\n border: '2.5px solid rgba(0,50,180,0.9)',\n boxShadow: `0 0 8px ${theme?.statusPositive || '#1ed473'}80`,\n }}\n />\n )}\n </div>\n <div>\n <h3\n className=\"font-semibold leading-tight\"\n style={{\n fontSize: '15px',\n letterSpacing: '-0.01em',\n }}\n >\n {agent?.name || 'Xcelsior Software'}\n </h3>\n <p\n className=\"mt-0.5 leading-tight\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: 'rgba(255,255,255,0.6)',\n }}\n >\n {agent?.status === 'online' ? (\n <span className=\"flex items-center gap-1.5\">\n <span\n className=\"inline-block w-1.5 h-1.5 rounded-full\"\n style={{\n backgroundColor: theme?.statusPositive || '#1ed473',\n boxShadow: `0 0 4px ${theme?.statusPositive || '#1ed473'}60`,\n }}\n />\n Online now\n </span>\n ) : agent?.status === 'away' ? (\n 'Away'\n ) : (\n 'We typically reply within minutes'\n )}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-0.5\">\n {/* Single minimize button — always minimizes back to FAB bubble */}\n {(onMinimize || onClose) && (\n <button\n type=\"button\"\n onClick={onMinimize || onClose}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Minimize chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {/* Bottom edge — subtle gradient line (matches website section dividers) */}\n <div\n className=\"h-px\"\n style={{\n background:\n 'linear-gradient(90deg, transparent 5%, rgba(255,255,255,0.12) 30%, rgba(255,255,255,0.12) 70%, transparent 95%)',\n }}\n />\n </div>\n );\n}\n","import { useCallback, useEffect, useRef } from 'react';\n\nimport { Spinner } from '@xcelsior/design-system';\n\nimport { XcelsiorAvatar, XcelsiorSymbol } from './BrandIcons';\nimport { MessageItem } from './MessageItem';\nimport { ThinkingIndicator } from './ThinkingIndicator';\n\nimport type { IMessage, IUser, IChatTheme } from '../types';\n\ninterface MessageListProps {\n messages: IMessage[];\n currentUser: IUser;\n isLoading?: boolean;\n isTyping?: boolean;\n typingUser?: string;\n autoScroll?: boolean;\n onLoadMore?: () => void;\n hasMore?: boolean;\n isLoadingMore?: boolean;\n theme?: IChatTheme;\n /** Called when a quick-start action button is clicked — sends the text as a message */\n onQuickAction?: (text: string) => void;\n /** True when user sent a message and bot response hasn't arrived yet */\n isBotThinking?: boolean;\n}\n\nexport function MessageList({\n messages,\n currentUser,\n isLoading = false,\n isTyping = false,\n typingUser,\n autoScroll = true,\n onLoadMore,\n hasMore = false,\n isLoadingMore = false,\n theme,\n onQuickAction,\n isBotThinking = false,\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n const loadMoreTriggerRef = useRef<HTMLDivElement>(null);\n const prevScrollHeightRef = useRef(0);\n const hasInitialScrolledRef = useRef(false);\n const isUserScrollingRef = useRef(false);\n\n const bgColor = theme?.background || '#00001a';\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n const primaryColor = theme?.primary || '#337eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (autoScroll && messagesEndRef.current) {\n if (messages.length > prevLengthRef.current && !isLoadingMore) {\n messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });\n }\n prevLengthRef.current = messages.length;\n }\n }, [messages.length, autoScroll, isLoadingMore]);\n\n // Initial scroll to bottom when messages first load\n useEffect(() => {\n if (\n messages.length > 0 &&\n messagesEndRef.current &&\n !isLoading &&\n !hasInitialScrolledRef.current\n ) {\n setTimeout(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'auto' });\n setTimeout(() => {\n isUserScrollingRef.current = true;\n }, 200);\n }, 100);\n hasInitialScrolledRef.current = true;\n } else if (!isLoading && messages.length === 0 && !hasInitialScrolledRef.current) {\n isUserScrollingRef.current = true;\n hasInitialScrolledRef.current = true;\n }\n }, [isLoading, messages.length]);\n\n // Restore scroll position after loading more messages\n useEffect(() => {\n if (isLoadingMore) {\n prevScrollHeightRef.current = containerRef.current?.scrollHeight || 0;\n } else if (prevScrollHeightRef.current > 0 && containerRef.current) {\n const newScrollHeight = containerRef.current.scrollHeight;\n const scrollDiff = newScrollHeight - prevScrollHeightRef.current;\n containerRef.current.scrollTop = scrollDiff;\n prevScrollHeightRef.current = 0;\n }\n }, [isLoadingMore]);\n\n // Infinite scroll: detect when user scrolls near the top\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !onLoadMore || !hasMore || isLoadingMore) return;\n if (!isUserScrollingRef.current) return;\n\n const { scrollTop } = containerRef.current;\n if (scrollTop < 100) {\n onLoadMore();\n }\n }, [onLoadMore, hasMore, isLoadingMore]);\n\n // Set up scroll event listener\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n // Empty state — premium, minimal, matching Xcelsior website feel\n if (messages.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center\" style={{ padding: '40px 32px' }}>\n <h3\n className=\"font-semibold mb-2\"\n style={{\n color: textColor,\n fontSize: '17px',\n letterSpacing: '-0.01em',\n }}\n >\n How can we help?\n </h3>\n <p\n className=\"max-w-[240px]\"\n style={{\n color: textMuted,\n fontSize: '13px',\n lineHeight: '1.5',\n letterSpacing: '0.015em',\n marginBottom: 20,\n }}\n >\n Ask us anything. We are here to help you get the most out of Xcelsior.\n </p>\n\n {/* Quick-start action buttons */}\n <div className=\"flex flex-wrap justify-center gap-2\">\n {[\n { label: 'Our services', message: 'What services does Xcelsior offer?' },\n { label: 'Get a quote', message: 'I would like to get a quote for a project' },\n { label: 'Support', message: 'I need help with something' },\n ].map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={() => onQuickAction?.(action.message)}\n style={{\n padding: '6px 14px',\n borderRadius: '999px',\n cursor: 'pointer',\n transition: 'all 150ms ease',\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n border: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.1)',\n color: isLightTheme\n ? 'rgba(0,0,0,0.6)'\n : 'rgba(247,247,248,0.6)',\n fontSize: '12px',\n letterSpacing: '0.015em',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme\n ? 'rgba(0,0,0,0.08)'\n : 'rgba(255,255,255,0.08)';\n e.currentTarget.style.color = isLightTheme\n ? 'rgba(0,0,0,0.8)'\n : 'rgba(247,247,248,0.8)';\n e.currentTarget.style.borderColor = primaryColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)';\n e.currentTarget.style.color = isLightTheme\n ? 'rgba(0,0,0,0.6)'\n : 'rgba(247,247,248,0.6)';\n e.currentTarget.style.borderColor = isLightTheme\n ? 'rgba(0,0,0,0.1)'\n : 'rgba(255,255,255,0.1)';\n }}\n >\n {action.label}\n </button>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 overflow-y-auto px-4 py-3\"\n style={{ scrollBehavior: 'smooth' }}\n >\n <style>{`\n @keyframes thinkingPulse {\n 0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); }\n 30% { opacity: 1; transform: scale(1); }\n }\n @keyframes cursorBlink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n }\n `}</style>\n {/* Loading indicator at the top for infinite scroll */}\n {isLoadingMore && (\n <div className=\"flex justify-center py-3\">\n <Spinner size=\"sm\" />\n </div>\n )}\n\n {/* Load more trigger point */}\n <div ref={loadMoreTriggerRef} />\n\n {messages.map((message) => (\n <MessageItem\n key={message.id}\n message={message}\n currentUser={currentUser}\n showAvatar={true}\n showTimestamp={true}\n theme={theme}\n />\n ))}\n\n {/* Typing indicator — matching bot message bubble style */}\n {isTyping && (\n <div className=\"flex gap-2.5 mb-3\">\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n <XcelsiorAvatar size={28} />\n </div>\n <div className=\"flex flex-col items-start\">\n <div\n className=\"px-4 py-3\"\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n borderRadius: '18px 18px 18px 4px',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n }}\n >\n <div className=\"flex gap-1.5 items-center\" style={{ height: 16 }}>\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"rounded-full animate-bounce\"\n style={{\n width: 5,\n height: 5,\n backgroundColor: `${primaryColor}80`,\n animationDelay: `${i * 0.15}s`,\n animationDuration: '0.8s',\n }}\n />\n ))}\n </div>\n </div>\n {typingUser && (\n <span\n className=\"mt-1 px-1\"\n style={{\n color: textMuted,\n fontSize: '11px',\n letterSpacing: '0.019em',\n }}\n >\n {typingUser} is typing...\n </span>\n )}\n </div>\n </div>\n )}\n\n {/* Bot thinking indicator — Claude-like typewriter with rotating phrases */}\n {isBotThinking && !isTyping && (\n <ThinkingIndicator\n theme={theme}\n lastUserMessage={messages.filter((m) => m.senderType === 'customer').pop()?.content}\n />\n )}\n\n <div ref={messagesEndRef} />\n </div>\n );\n}\n","import { formatDistanceToNow } from 'date-fns';\nimport type { IMessage, IUser, IChatTheme } from '../types';\nimport { XcelsiorAvatar } from './BrandIcons';\nimport { MarkdownMessage } from './MarkdownMessage';\n\ninterface MessageItemProps {\n message: IMessage;\n currentUser: IUser;\n showAvatar?: boolean;\n showTimestamp?: boolean;\n theme?: IChatTheme;\n}\n\nexport function MessageItem({\n message,\n currentUser,\n showAvatar = true,\n showTimestamp = true,\n theme,\n}: MessageItemProps) {\n const isOwnMessage = message.senderType === currentUser.type;\n const isSystemMessage = message.senderType === 'system';\n const isAIMessage = message.metadata?.isAI === true;\n const isBotMessage = message.senderType === 'bot';\n\n const bgColor = theme?.background || '#00001a';\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n const primaryColor = theme?.primary || '#337eff';\n const primaryStrong = theme?.primaryStrong || '#005eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.35)' : 'rgba(247,247,248,0.35)');\n\n // System messages — centered pill with ultra-subtle surface\n if (isSystemMessage) {\n return (\n <div className=\"flex justify-center my-3\">\n <div\n className=\"px-4 py-1.5 rounded-full\"\n style={{\n backgroundColor: isLightTheme ? 'rgba(0,0,0,0.04)' : 'rgba(255,255,255,0.03)',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n }}\n >\n <p\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n {message.content}\n </p>\n </div>\n </div>\n );\n }\n\n // Determine label for non-customer messages\n const getSenderLabel = () => {\n if (isBotMessage || isAIMessage) return 'AI Assistant';\n if (message.senderType === 'agent') {\n return (message.metadata?.agentName as string) || 'Support Agent';\n }\n return null;\n };\n\n const senderLabel = !isOwnMessage ? getSenderLabel() : null;\n\n // Own message: blue gradient pill (matches website primary CTA)\n const ownBubbleStyle: React.CSSProperties = {\n background: `linear-gradient(135deg, ${primaryColor}, ${primaryStrong})`,\n color: '#ffffff',\n borderRadius: '18px 18px 4px 18px',\n boxShadow: `0 2px 12px -3px ${primaryColor}40`,\n };\n\n // Other message: surface with subtle inset border (adapts to theme)\n const otherBubbleStyle: React.CSSProperties = isLightTheme\n ? {\n backgroundColor: 'rgba(0,0,0,0.04)',\n color: textColor,\n borderRadius: '18px 18px 18px 4px',\n boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.06)',\n }\n : {\n backgroundColor: 'rgba(255,255,255,0.04)',\n color: textColor,\n borderRadius: '18px 18px 18px 4px',\n boxShadow:\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n };\n\n return (\n <div\n className={`flex gap-2.5 mb-3 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n {/* Avatar */}\n {showAvatar && !isOwnMessage && (\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n {isBotMessage || isAIMessage ? (\n <XcelsiorAvatar size={28} />\n ) : (\n <div\n className=\"h-7 w-7 rounded-full flex items-center justify-center\"\n style={{\n background: isLightTheme\n ? `linear-gradient(135deg, ${primaryColor}30, rgba(0,0,0,0.04))`\n : `linear-gradient(135deg, ${primaryColor}60, rgba(255,255,255,0.06))`,\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.08)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.1)',\n }}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={isLightTheme ? primaryColor : 'white'}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Agent</title>\n <path d=\"M3 18v-6a9 9 0 0 1 18 0v6\" />\n <path d=\"M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z\" />\n </svg>\n </div>\n )}\n </div>\n )}\n\n {/* Spacer for own messages to maintain alignment */}\n {showAvatar && isOwnMessage && <div className=\"w-7 flex-shrink-0\" />}\n\n <div\n className={`flex flex-col max-w-[75%] ${isOwnMessage ? 'items-end' : 'items-start'}`}\n >\n {/* Sender label */}\n {senderLabel && (\n <span\n className=\"mb-1 px-1 font-medium\"\n style={{\n color: isLightTheme ? 'rgba(0,0,0,0.45)' : 'rgba(247,247,248,0.4)',\n fontSize: '11px',\n letterSpacing: '0.019em',\n }}\n >\n {senderLabel}\n </span>\n )}\n\n {/* Message bubble */}\n <div\n className=\"px-4 py-2.5\"\n style={{\n ...( isOwnMessage ? ownBubbleStyle : otherBubbleStyle ),\n fontSize: '14px',\n lineHeight: '1.5',\n letterSpacing: '0.006em',\n }}\n >\n {message.messageType === 'text' && (\n isOwnMessage ? (\n // User messages: plain text — no markdown parsing\n <span style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>\n {message.content}\n </span>\n ) : (\n // Bot / agent messages: full markdown rendering\n <MarkdownMessage content={message.content} theme={theme} />\n )\n )}\n {message.messageType === 'image' && (\n <div>\n <img\n src={message.content}\n alt=\"Attachment\"\n className=\"max-w-full h-auto rounded-lg\"\n loading=\"lazy\"\n />\n </div>\n )}\n {message.messageType === 'file' && (\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>File</title>\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\" />\n </svg>\n <a\n href={message.content}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n color: isOwnMessage\n ? 'rgba(255,255,255,0.85)'\n : primaryColor,\n textDecoration: 'underline',\n textUnderlineOffset: '2px',\n }}\n >\n {(message.metadata?.fileName as any) || 'Download file'}\n </a>\n </div>\n )}\n </div>\n\n {/* Timestamp + status */}\n {showTimestamp && (\n <div\n className={`flex items-center gap-1.5 mt-1 px-1 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n <span\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n {formatDistanceToNow(new Date(message.createdAt), {\n addSuffix: true,\n })}\n </span>\n {isOwnMessage && message.status && (\n <span style={{ color: textMuted }}>\n {message.status === 'sent' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Sent</title>\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n {message.status === 'delivered' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Delivered</title>\n <polyline points=\"18 6 7 17 2 12\" />\n <polyline points=\"22 6 11 17\" />\n </svg>\n )}\n {message.status === 'read' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={primaryColor}\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Read</title>\n <polyline points=\"18 6 7 17 2 12\" />\n <polyline points=\"22 6 11 17\" />\n </svg>\n )}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport type { Components } from 'react-markdown';\nimport type { IChatTheme } from '../types';\nimport { getMarkdownStyles } from '../utils/markdown-styles';\n\ninterface MarkdownMessageProps {\n content: string;\n theme?: IChatTheme;\n}\n\nfunction computeIsLightTheme(theme?: IChatTheme): boolean {\n const bgColor = theme?.background || '#00001a';\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n if (hex.length < 6) return false;\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\nexport function MarkdownMessage({ content, theme }: MarkdownMessageProps) {\n const isLightTheme = computeIsLightTheme(theme);\n const styles = getMarkdownStyles(theme, isLightTheme);\n\n // Last paragraph in a message should have no bottom margin to avoid\n // extra space at the bottom of the bubble. We track last child via\n // a wrapper + CSS last-child, but since we use inline styles we\n // strip the margin in the paragraph renderer if the node is the last\n // element. react-markdown does not expose \"is last sibling\" easily,\n // so we use a simple wrapper approach: strip bottom margin on the\n // outermost container's last child by keeping the container style tight\n // and letting natural flow handle it.\n\n const wrapperStyle: CSSProperties = {\n // Collapse bottom margin of the last child to avoid extra padding\n // inside the bubble.\n display: 'block',\n };\n\n return (\n <div style={wrapperStyle}>\n <ReactMarkdown\n components={{\n // Paragraphs\n p: ({ children }) => (\n <p style={styles.paragraph}>{children}</p>\n ),\n\n // Bold\n strong: ({ children }) => (\n <strong style={styles.strong}>{children}</strong>\n ),\n\n // Italic\n em: ({ children }) => (\n <em style={styles.emphasis}>{children}</em>\n ),\n\n // Links — open in new tab\n a: ({ href, children }) => (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={styles.link}\n >\n {children}\n </a>\n ),\n\n // Unordered list\n ul: ({ children }) => (\n <ul style={{ ...styles.list, listStyleType: 'disc' }}>\n {children}\n </ul>\n ),\n\n // Ordered list\n ol: ({ children }) => (\n <ol\n style={{ ...styles.list, listStyleType: 'decimal' }}\n >\n {children}\n </ol>\n ),\n\n // List item\n li: ({ children }) => (\n <li style={styles.listItem}>{children}</li>\n ),\n\n // Inline code vs code block — react-markdown wraps fenced\n // code blocks as <pre><code className=\"language-*\">. The\n // cleanest heuristic: if the className starts with\n // \"language-\" it is a fenced block; otherwise it's inline.\n code: (({ children, className }) => {\n const isBlock = Boolean(\n className?.startsWith('language-'),\n );\n if (isBlock) {\n return (\n <code\n className={className}\n style={styles.codeBlock}\n >\n {children}\n </code>\n );\n }\n return <code style={styles.code}>{children}</code>;\n }) as Components['code'],\n\n // Pre wrapper for code blocks\n pre: ({ children }) => (\n <pre\n style={{\n margin: '8px 0',\n padding: 0,\n backgroundColor: 'transparent',\n border: 'none',\n overflow: 'visible',\n }}\n >\n {children}\n </pre>\n ),\n\n // Headings — h1 through h6 with progressive size reduction\n h1: ({ children }) => (\n <h1\n style={{\n ...styles.heading,\n fontSize: '1.15em',\n }}\n >\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2\n style={{\n ...styles.heading,\n fontSize: '1.1em',\n }}\n >\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3\n style={{\n ...styles.heading,\n fontSize: '1.05em',\n }}\n >\n {children}\n </h3>\n ),\n h4: ({ children }) => (\n <h4 style={{ ...styles.heading, fontSize: '1em' }}>\n {children}\n </h4>\n ),\n h5: ({ children }) => (\n <h5\n style={{\n ...styles.heading,\n fontSize: '0.95em',\n }}\n >\n {children}\n </h5>\n ),\n h6: ({ children }) => (\n <h6\n style={{\n ...styles.heading,\n fontSize: '0.9em',\n }}\n >\n {children}\n </h6>\n ),\n\n // Blockquote\n blockquote: ({ children }) => (\n <blockquote style={styles.blockquote}>\n {children}\n </blockquote>\n ),\n\n // Horizontal rule\n hr: () => <hr style={styles.hr} />,\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\nimport type { IChatTheme } from '../types';\n\nexport interface MarkdownStyles {\n paragraph: CSSProperties;\n strong: CSSProperties;\n emphasis: CSSProperties;\n link: CSSProperties;\n list: CSSProperties;\n listItem: CSSProperties;\n code: CSSProperties;\n codeBlock: CSSProperties;\n heading: CSSProperties;\n blockquote: CSSProperties;\n hr: CSSProperties;\n}\n\nexport function getMarkdownStyles(\n theme?: IChatTheme,\n isLightTheme?: boolean,\n): MarkdownStyles {\n const primaryColor = theme?.primary || '#337eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n\n // Slightly brightened text for strong elements\n const strongColor = isLightTheme\n ? 'rgba(0,0,0,0.9)'\n : 'rgba(255,255,255,0.95)';\n\n // Subtle background for inline code\n const inlineCodeBg = isLightTheme\n ? 'rgba(0,0,0,0.06)'\n : 'rgba(255,255,255,0.08)';\n\n // Darker background for code blocks\n const codeBlockBg = isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(0,0,0,0.25)';\n\n const codeBlockBorder = isLightTheme\n ? '1px solid rgba(0,0,0,0.08)'\n : '1px solid rgba(255,255,255,0.06)';\n\n const blockquoteBorder = isLightTheme\n ? `3px solid ${primaryColor}60`\n : `3px solid ${primaryColor}80`;\n\n const blockquoteBg = isLightTheme\n ? 'rgba(0,0,0,0.02)'\n : 'rgba(255,255,255,0.02)';\n\n return {\n paragraph: {\n margin: '0 0 8px 0',\n lineHeight: '1.6',\n color: textColor,\n },\n\n strong: {\n fontWeight: 600,\n color: strongColor,\n },\n\n emphasis: {\n fontStyle: 'italic',\n color: textColor,\n },\n\n link: {\n color: primaryColor,\n textDecoration: 'underline',\n textUnderlineOffset: '2px',\n cursor: 'pointer',\n },\n\n list: {\n paddingLeft: '20px',\n margin: '8px 0',\n color: textColor,\n },\n\n listItem: {\n margin: '4px 0',\n lineHeight: '1.5',\n color: textColor,\n },\n\n code: {\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n fontSize: '0.875em',\n backgroundColor: inlineCodeBg,\n padding: '2px 6px',\n borderRadius: '4px',\n color: textColor,\n },\n\n codeBlock: {\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n fontSize: '0.8125em',\n backgroundColor: codeBlockBg,\n border: codeBlockBorder,\n padding: '12px',\n borderRadius: '8px',\n overflowX: 'auto',\n margin: '8px 0',\n color: textColor,\n lineHeight: '1.5',\n display: 'block',\n whiteSpace: 'pre',\n },\n\n heading: {\n fontWeight: 600,\n marginTop: '12px',\n marginBottom: '6px',\n color: strongColor,\n lineHeight: '1.3',\n },\n\n blockquote: {\n borderLeft: blockquoteBorder,\n backgroundColor: blockquoteBg,\n margin: '8px 0',\n padding: '6px 12px',\n borderRadius: '0 4px 4px 0',\n color: textColor,\n fontStyle: 'italic',\n },\n\n hr: {\n border: 'none',\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.08)',\n margin: '12px 0',\n },\n };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { XcelsiorAvatar } from './BrandIcons';\nimport type { IChatTheme } from '../types';\n\n// ─── Phrase Pools ────────────────────────────────────────────────────────────\n// Each pool is tied to a detected conversation context.\n// Phrases should feel casual, human, and short (≤4 words ideal).\n\nconst PHRASE_POOLS: Record<string, string[]> = {\n // ── Greetings & small talk ──\n greeting: [\n 'Hey there!',\n 'Hello!',\n 'Hi! One moment',\n 'Welcome!',\n 'Nice to meet you',\n ],\n farewell: [\n 'Wrapping up',\n 'One last thing',\n 'Almost done',\n ],\n\n // ── Sales & pricing ──\n pricing: [\n 'Crunching numbers',\n 'Checking our plans',\n 'Let me look into that',\n 'Pulling up pricing',\n 'Running the numbers',\n 'Checking options',\n ],\n quote: [\n 'Putting this together',\n 'Working on your quote',\n 'Gathering the details',\n 'Tailoring this for you',\n ],\n\n // ── Scheduling & booking ──\n booking: [\n 'Checking the calendar',\n 'Finding good times',\n 'Pulling up availability',\n 'Let me check slots',\n ],\n\n // ── Technical questions ──\n technical: [\n 'Diving into the docs',\n 'Interesting question',\n 'Let me look that up',\n 'Checking the specs',\n 'Hmm, good one',\n 'Researching this',\n ],\n code: [\n 'Reading the code',\n 'Checking the repo',\n 'Let me trace that',\n 'Debugging in my head',\n ],\n\n // ── Support & issues ──\n support: [\n 'On it!',\n 'Let me help',\n 'Looking into this',\n 'Checking for you',\n 'I got you',\n 'Investigating',\n ],\n frustrated: [\n 'I hear you',\n 'Let me fix this',\n 'Sorry about that',\n 'Working on it now',\n 'Bear with me',\n ],\n\n // ── Services & capabilities ──\n services: [\n 'Great question',\n 'Let me explain',\n 'Pulling up details',\n 'Good to know you ask',\n ],\n portfolio: [\n 'Checking our work',\n 'Pulling up examples',\n 'Let me show you',\n 'Finding case studies',\n ],\n\n // ── About the company ──\n about: [\n 'Glad you asked!',\n 'Let me tell you',\n 'Good question',\n 'Here we go',\n ],\n\n // ── Comparison & decisions ──\n comparison: [\n 'Weighing the options',\n 'Let me compare',\n 'Thinking through this',\n 'Good point',\n ],\n\n // ── Follow-up & continuation ──\n followUp: [\n 'Let me dig deeper',\n 'More details coming',\n 'Building on that',\n 'Expanding on this',\n ],\n\n // ── General / fallback ──\n general: [\n 'Hmm, let me think',\n 'One sec',\n 'On it',\n 'Working on it',\n 'Almost there',\n 'Bear with me',\n 'Let me check',\n 'Good question',\n 'Hang tight',\n 'Looking into it',\n 'Let me see',\n 'Thinking',\n 'Just a moment',\n 'Figuring this out',\n ],\n};\n\n// ─── Context Detection ───────────────────────────────────────────────────────\n// Ordered by specificity — first match wins.\n\ninterface ContextRule {\n key: string;\n pattern: RegExp;\n}\n\nconst CONTEXT_RULES: ContextRule[] = [\n // Frustration / urgency (check first — trumps topic)\n { key: 'frustrated', pattern: /frustrat|angry|annoyed|terrible|worst|useless|waste|stupid|wtf|seriously|ridiculous|unacceptable|disappointing/ },\n\n // Greetings (start of message)\n { key: 'greeting', pattern: /^(hi\\b|hey\\b|hello\\b|good morning|good afternoon|good evening|g'day|howdy|yo\\b|sup\\b|what's up|greetings)/ },\n { key: 'farewell', pattern: /\\b(thanks|thank you|bye|goodbye|cheers|that's all|that's it|no more|all good|perfect thanks)\\b/ },\n\n // Booking & scheduling\n { key: 'booking', pattern: /\\b(book|schedule|meeting|appointment|calendar|available time|free slot|set up a call|arrange|consultation time|when can)\\b/ },\n\n // Pricing & quotes\n { key: 'quote', pattern: /\\b(quote|proposal|estimate|project cost|custom price|tailor|bespoke)\\b/ },\n { key: 'pricing', pattern: /\\b(price|cost|how much|pricing|rate|fee|budget|afford|charge|per hour|hourly|package|plan|tier|subscription)\\b/ },\n\n // Technical / code\n { key: 'code', pattern: /\\b(code|github|repo|commit|deploy|ci\\/cd|docker|aws|lambda|api endpoint|sdk|npm|yarn|pnpm|typescript|react|next\\.?js)\\b/ },\n { key: 'technical', pattern: /\\b(api|integrate|integration|stack|server|database|backend|frontend|infrastructure|architecture|performance|scalab|migration|devops|cloud)\\b/ },\n\n // Support & bugs\n { key: 'support', pattern: /\\b(bug|error|issue|broken|not working|help|support|problem|fix|crash|down|fail|stuck|trouble|can't|cannot|doesn't work|won't)\\b/ },\n\n // Services & portfolio\n { key: 'portfolio', pattern: /\\b(portfolio|case stud|example|previous work|client|project you|showcase|demo|sample)\\b/ },\n { key: 'services', pattern: /\\b(service|what do you|what can you|offer|do you do|capabilit|specializ|expertise|solution|consult|develop|design|build|create)\\b/ },\n\n // About company\n { key: 'about', pattern: /\\b(who are|about you|your team|your company|where are you|location|office|founded|history|values|mission)\\b/ },\n\n // Comparison / decision-making\n { key: 'comparison', pattern: /\\b(compare|vs|versus|difference|better|which one|alternative|competitor|pros and cons|trade.?off|should i|recommend)\\b/ },\n\n // Follow-up patterns (vague follow-ups to prior answers)\n { key: 'followUp', pattern: /\\b(more detail|tell me more|elaborate|explain further|what about|and also|another question|one more|can you also|what else|go on)\\b/ },\n];\n\nfunction detectContext(message?: string): string {\n if (!message) return 'general';\n const lower = message.toLowerCase().trim();\n\n for (const rule of CONTEXT_RULES) {\n if (rule.pattern.test(lower)) return rule.key;\n }\n\n // Short messages (1-3 words) that didn't match anything → likely casual\n if (lower.split(/\\s+/).length <= 3) return 'general';\n\n // Questions tend to be exploratory\n if (lower.endsWith('?')) return 'general';\n\n return 'general';\n}\n\n// ─── Shuffle Utility ─────────────────────────────────────────────────────────\n\nfunction getShuffledPhrases(context: string): string[] {\n const pool = PHRASE_POOLS[context] || PHRASE_POOLS.general;\n const contextPhrases = [...pool];\n\n // Mix in 2-3 general phrases for variety (avoid duplicates)\n const extras = PHRASE_POOLS.general\n .filter((p) => !contextPhrases.includes(p))\n .sort(() => Math.random() - 0.5)\n .slice(0, 3);\n\n const combined = [...contextPhrases, ...extras];\n\n // Fisher-Yates shuffle\n for (let i = combined.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [combined[i], combined[j]] = [combined[j], combined[i]];\n }\n return combined;\n}\n\n// ─── Theme Helpers ───────────────────────────────────────────────────────────\n\nfunction computeIsLightTheme(bg?: string): boolean {\n if (!bg?.startsWith('#')) return false;\n const hex = bg.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport interface ThinkingIndicatorProps {\n /** Last message the user sent — used to pick contextual phrases */\n lastUserMessage?: string;\n /** Chat theme for color matching */\n theme?: IChatTheme;\n /** Show avatar next to the indicator */\n showAvatar?: boolean;\n}\n\nexport function ThinkingIndicator({\n lastUserMessage,\n theme,\n showAvatar = true,\n}: ThinkingIndicatorProps) {\n const isLightTheme = computeIsLightTheme(theme?.background);\n const primaryColor = theme?.primary || '#337eff';\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n\n const [phraseIndex, setPhraseIndex] = useState(0);\n const [displayText, setDisplayText] = useState('');\n const [isDeleting, setIsDeleting] = useState(false);\n const phrasesRef = useRef<string[]>(getShuffledPhrases(detectContext(lastUserMessage)));\n\n // Re-shuffle when user sends a new message\n useEffect(() => {\n phrasesRef.current = getShuffledPhrases(detectContext(lastUserMessage));\n setPhraseIndex(0);\n setDisplayText('');\n setIsDeleting(false);\n }, [lastUserMessage]);\n\n // Typewriter effect\n useEffect(() => {\n const phrases = phrasesRef.current;\n const phrase = phrases[phraseIndex % phrases.length];\n let timeout: NodeJS.Timeout;\n\n if (!isDeleting) {\n if (displayText.length < phrase.length) {\n // Typing forward — variable speed for natural feel\n timeout = setTimeout(\n () => setDisplayText(phrase.slice(0, displayText.length + 1)),\n 30 + Math.random() * 30,\n );\n } else {\n // Pause at full phrase before deleting\n timeout = setTimeout(() => setIsDeleting(true), 1800);\n }\n } else {\n if (displayText.length > 0) {\n // Deleting — faster than typing\n timeout = setTimeout(\n () => setDisplayText(displayText.slice(0, -1)),\n 18,\n );\n } else {\n // Advance to next phrase\n setIsDeleting(false);\n setPhraseIndex((prev) => (prev + 1) % phrasesRef.current.length);\n }\n }\n\n return () => clearTimeout(timeout);\n }, [displayText, isDeleting, phraseIndex]);\n\n return (\n <div\n className=\"flex gap-2.5 mb-3\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Xcelsior is thinking\"\n >\n {showAvatar && (\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n <XcelsiorAvatar size={28} />\n </div>\n )}\n <div className=\"flex flex-col items-start\">\n <div\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n borderRadius: '18px 18px 18px 4px',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n padding: '12px 16px',\n minWidth: 160,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {/* Pulsing dots */}\n <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: 5,\n height: 5,\n borderRadius: '50%',\n backgroundColor: primaryColor,\n display: 'inline-block',\n animation: `thinkingPulse 1.4s ease-in-out ${i * 0.2}s infinite`,\n }}\n />\n ))}\n </div>\n\n {/* Typewriter text + blinking cursor */}\n <span\n style={{\n fontSize: 12,\n color: textMuted,\n letterSpacing: '0.015em',\n fontStyle: 'italic',\n }}\n >\n {displayText}\n <span\n style={{\n display: 'inline-block',\n width: 1,\n height: 13,\n backgroundColor: textMuted,\n marginLeft: 1,\n animation: 'cursorBlink 0.8s step-end infinite',\n verticalAlign: 'text-bottom',\n }}\n />\n </span>\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport Picker from '@emoji-mart/react';\nimport type { IChatConfig } from '../types';\nimport type { UseFileUploadReturn } from '../hooks/useFileUpload';\n\n/** Detect if a hex/rgb color is \"light\" (luminance > 0.5) */\nfunction isLightColor(color: string): boolean {\n let r = 0, g = 0, b = 0;\n if (color.startsWith('#')) {\n const hex = color.replace('#', '');\n r = parseInt(hex.substring(0, 2), 16);\n g = parseInt(hex.substring(2, 4), 16);\n b = parseInt(hex.substring(4, 6), 16);\n }\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\ninterface ChatInputProps {\n onSend: (message: string) => void;\n onTyping?: (isTyping: boolean) => void;\n config: IChatConfig;\n fileUpload: UseFileUploadReturn;\n disabled?: boolean;\n}\n\nexport function ChatInput({\n onSend,\n onTyping,\n config,\n fileUpload,\n disabled = false,\n}: ChatInputProps) {\n const [message, setMessage] = useState('');\n const [showEmojiPicker, setShowEmojiPicker] = useState(false);\n const [emojiData, setEmojiData] = useState<any>();\n const [emojiPickerPosition, setEmojiPickerPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const [isFocused, setIsFocused] = useState(false);\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\n const emojiPickerRef = useRef<HTMLDivElement>(null);\n const emojiButtonRef = useRef<HTMLButtonElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const startTypingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const isTypingRef = useRef<boolean>(false);\n\n const enableEmoji = config.enableEmoji ?? true;\n const enableFileUpload = config.enableFileUpload ?? true;\n\n // Theme tokens — aligned with Xcelsior website design system\n const bgColor = config.theme?.background || '#00001a';\n const isLightTheme = isLightColor(bgColor);\n const textColor = config.theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = config.theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n const primaryColor = config.theme?.primary || '#337eff';\n\n // Load emoji data\n useEffect(() => {\n if (!enableEmoji) return;\n (async () => {\n try {\n const response = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data');\n setEmojiData(await response.json());\n } catch (error) {\n console.error('Failed to load emoji data:', error);\n }\n })();\n }, [enableEmoji]);\n\n // Handle click outside emoji picker\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(event.target as Node)) {\n setShowEmojiPicker(false);\n }\n };\n\n if (showEmojiPicker) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [showEmojiPicker]);\n\n // Cleanup typing timeouts on unmount\n useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n };\n }, []);\n\n // Update emoji picker position on window resize/scroll\n useEffect(() => {\n if (!showEmojiPicker) return;\n\n const updatePosition = () => {\n if (emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 370,\n left: rect.left - 300,\n });\n }\n };\n\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [showEmojiPicker]);\n\n const handleTyping = (value: string) => {\n setMessage(value);\n\n // Send typing indicator with debouncing\n if (onTyping && config.enableTypingIndicator !== false) {\n // Clear any pending \"start typing\" timeout\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n\n // Clear any pending \"stop typing\" timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // If not already typing, debounce the start typing event\n if (!isTypingRef.current) {\n startTypingTimeoutRef.current = setTimeout(() => {\n onTyping(true);\n isTypingRef.current = true;\n }, 300);\n }\n\n // Set timeout to stop typing indicator after inactivity\n typingTimeoutRef.current = setTimeout(() => {\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }, 1500);\n }\n };\n\n const handleSend = () => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage || disabled) return;\n\n onSend(trimmedMessage);\n setMessage('');\n setShowEmojiPicker(false);\n\n // Stop typing indicator\n if (onTyping) {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }\n\n // Focus back on textarea\n textAreaRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const insertAtCursor = (text: string) => {\n const textarea = textAreaRef.current;\n if (!textarea) {\n setMessage((prev) => prev + text);\n return;\n }\n\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const newValue = message.slice(0, start) + text + message.slice(end);\n setMessage(newValue);\n\n // Set cursor position after inserted text\n setTimeout(() => {\n const newCursorPos = start + text.length;\n textarea.setSelectionRange(newCursorPos, newCursorPos);\n textarea.focus();\n }, 0);\n };\n\n const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n const file = files[0];\n try {\n config.toast?.info('Uploading file...');\n const uploadedFile = await fileUpload.uploadFile(file);\n if (uploadedFile?.markdown) {\n insertAtCursor(`\\n${uploadedFile.markdown}\\n`);\n config.toast?.success('File uploaded successfully');\n }\n } catch (error: any) {\n console.error('File upload failed:', error);\n config.toast?.error(error.message);\n } finally {\n // Clear the file input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n }\n };\n\n const canSend = message.trim().length > 0 && !disabled;\n\n const placeholderColor = isLightTheme ? 'rgba(0,0,0,0.35)' : 'rgba(247,247,248,0.3)';\n\n return (\n <div\n className=\"px-4 py-3\"\n style={{\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.06)'\n : '1px solid rgba(255,255,255,0.06)',\n }}\n >\n <div\n className=\"relative flex items-center rounded-full transition-all duration-200\"\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(112,115,124,0.08)'\n : 'rgba(112,115,124,0.12)',\n outline: isFocused ? `2px solid ${primaryColor}` : 'none',\n outlineOffset: '-1px',\n border: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.08)',\n backdropFilter: 'blur(32px)',\n }}\n >\n {/* Placeholder color via inline style element */}\n <style>{`.xchat-input::placeholder { color: ${placeholderColor}; }`}</style>\n <textarea\n ref={textAreaRef}\n value={message}\n onChange={(e) => handleTyping(e.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n placeholder=\"Type a message...\"\n rows={1}\n className=\"xchat-input flex-1 resize-none bg-transparent\"\n style={{\n color: textColor,\n border: 'none',\n outline: 'none',\n boxShadow: 'none',\n WebkitAppearance: 'none',\n padding: '10px 0 10px 20px',\n minHeight: '42px',\n maxHeight: '120px',\n caretColor: primaryColor,\n fontSize: '14px',\n lineHeight: '20px',\n letterSpacing: '0.006em',\n }}\n disabled={disabled}\n />\n\n {/* Action buttons row */}\n <div className=\"flex items-center gap-1 px-2 shrink-0\">\n {enableEmoji && (\n <button\n ref={emojiButtonRef}\n type=\"button\"\n onClick={() => {\n if (!showEmojiPicker && emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 450,\n left: rect.left - 290,\n });\n }\n setShowEmojiPicker((v) => !v);\n }}\n className=\"p-1.5 rounded-lg transition-all duration-150\"\n style={{\n color: textMuted,\n backgroundColor: 'transparent',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)';\n e.currentTarget.style.color = textColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = textMuted;\n }}\n disabled={disabled}\n aria-label=\"Add emoji\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Emoji</title>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n <line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\" />\n <line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\" />\n </svg>\n </button>\n )}\n\n {enableFileUpload && fileUpload.canUpload && (\n <>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n className=\"p-1.5 rounded-lg transition-all duration-150\"\n style={{\n color: textMuted,\n backgroundColor: 'transparent',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.06)';\n e.currentTarget.style.color = textColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = textMuted;\n }}\n disabled={disabled || fileUpload.isUploading}\n aria-label=\"Attach file\"\n >\n {fileUpload.isUploading ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n className=\"animate-spin\"\n aria-hidden=\"true\"\n >\n <title>Uploading</title>\n <path d=\"M21 12a9 9 0 11-6.219-8.56\" />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Attach file</title>\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\" />\n </svg>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*,application/pdf,.doc,.docx\"\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </>\n )}\n\n {/* Send button — gradient pill matching website CTA style */}\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-1.5 rounded-lg transition-all duration-200\"\n style={{\n background: canSend\n ? `linear-gradient(135deg, ${primaryColor}, ${config.theme?.primaryStrong || '#005eff'})`\n : 'transparent',\n color: canSend ? '#ffffff' : textMuted,\n opacity: canSend ? 1 : 0.35,\n cursor: canSend ? 'pointer' : 'default',\n boxShadow: canSend\n ? `0 2px 8px -2px ${primaryColor}60`\n : 'none',\n }}\n aria-label=\"Send message\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Send</title>\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Upload progress */}\n {fileUpload.isUploading && (\n <div className=\"mt-2 px-1\">\n <div\n className=\"w-full rounded-full overflow-hidden\"\n style={{\n height: 3,\n backgroundColor: isLightTheme ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)',\n }}\n >\n <div\n className=\"h-full rounded-full transition-all duration-300\"\n style={{\n width: `${fileUpload.uploadProgress}%`,\n background: `linear-gradient(90deg, ${primaryColor}, ${config.theme?.primaryStrong || '#005eff'})`,\n }}\n />\n </div>\n <p\n className=\"mt-1\"\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n Uploading... {fileUpload.uploadProgress}%\n </p>\n </div>\n )}\n\n {/* Emoji picker portal */}\n {showEmojiPicker &&\n emojiData &&\n emojiPickerPosition &&\n typeof document !== 'undefined' &&\n createPortal(\n <div\n ref={emojiPickerRef}\n className=\"fixed rounded-xl overflow-hidden\"\n style={{\n top: `${emojiPickerPosition.top}px`,\n left: `${emojiPickerPosition.left}px`,\n zIndex: 9999,\n boxShadow: [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.1)',\n '0 16px 48px -8px rgba(0,0,0,0.5)',\n ].join(', '),\n }}\n >\n <Picker\n data={emojiData}\n onEmojiSelect={(emoji: any) => {\n insertAtCursor(emoji.native || emoji.shortcodes || '');\n setShowEmojiPicker(false);\n }}\n previewPosition=\"none\"\n skinTonePosition=\"none\"\n navPosition=\"bottom\"\n perLine={8}\n searchPosition=\"sticky\"\n theme=\"dark\"\n />\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { ChatWidget } from './ChatWidget';\nimport { PreChatForm } from './PreChatForm';\nimport { ChatBubbleIcon } from './BrandIcons';\nimport { useDraggablePosition } from '../hooks/useDraggablePosition';\nimport type { IChatConfig, IUser } from '../types';\nimport { useChatWidgetState } from '../hooks/useChatWidgetState';\nimport type { ChatWidgetState } from '../hooks/useChatWidgetState';\n\ninterface ChatWidgetWrapperProps {\n config: Omit<IChatConfig, 'conversationId'> & {\n conversationId?: string;\n };\n className?: string;\n storageKeyPrefix?: string;\n onPreChatSubmit?: (user: IUser) => void;\n state?: ChatWidgetState;\n defaultState?: ChatWidgetState;\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\ninterface StoredUserData {\n name: string;\n email: string;\n conversationId: string;\n timestamp: number;\n}\n\nfunction generateSessionId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\nexport function Chat({\n config,\n className = '',\n storageKeyPrefix = 'xcelsior_chat',\n onPreChatSubmit,\n state,\n defaultState = 'minimized',\n onStateChange,\n}: ChatWidgetWrapperProps) {\n const [userInfo, setUserInfo] = useState<IUser | null>(null);\n const [conversationId, setConversationId] = useState<string>('');\n const [isLoading, setIsLoading] = useState(true);\n const [isAnimating, setIsAnimating] = useState(false);\n const [showWidget, setShowWidget] = useState(false);\n\n const identityMode = config.identityCollection || 'progressive';\n const { position, isDragging, showHint, handlers } = useDraggablePosition(config.position);\n\n const { currentState, setState: setStateRaw } = useChatWidgetState({\n state,\n defaultState,\n onStateChange,\n });\n\n // Wrap setState with animation handling\n const setState = useCallback(\n (newState: ChatWidgetState) => {\n if (newState === 'open' && currentState === 'minimized') {\n // Opening: show widget immediately, trigger animation\n setShowWidget(true);\n setIsAnimating(true);\n setStateRaw(newState);\n // Let the animation class apply on next frame\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setIsAnimating(false);\n });\n });\n } else if (\n (newState === 'minimized' || newState === 'closed') &&\n currentState === 'open'\n ) {\n // Closing: animate out, then change state\n setIsAnimating(true);\n setTimeout(() => {\n setShowWidget(false);\n setIsAnimating(false);\n setStateRaw(newState);\n }, 200);\n } else {\n setStateRaw(newState);\n }\n },\n [currentState, setStateRaw]\n );\n\n // Sync showWidget with state\n useEffect(() => {\n if (currentState === 'open') {\n setShowWidget(true);\n }\n }, [currentState]);\n\n // Initialize session\n useEffect(() => {\n const initializeSession = () => {\n try {\n if (config.currentUser?.email && config.currentUser?.name) {\n const convId = config.conversationId || generateSessionId();\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: config.currentUser.status,\n };\n setUserInfo(user);\n setConversationId(convId);\n setIsLoading(false);\n return;\n }\n\n const storedDataJson = localStorage.getItem(`${storageKeyPrefix}_user`);\n if (storedDataJson) {\n const storedData: StoredUserData = JSON.parse(storedDataJson);\n const isExpired = Date.now() - storedData.timestamp > 24 * 60 * 60 * 1000;\n\n if (!isExpired && storedData.email && storedData.name) {\n const user: IUser = {\n name: storedData.name,\n email: storedData.email,\n type: 'customer',\n status: 'online',\n };\n setUserInfo(user);\n setConversationId(storedData.conversationId);\n setIsLoading(false);\n return;\n }\n }\n\n const convId = config.conversationId || generateSessionId();\n setConversationId(convId);\n\n if (identityMode === 'progressive' || identityMode === 'none') {\n setUserInfo(null);\n }\n } catch (error) {\n console.error('Error initializing chat session:', error);\n setConversationId(config.conversationId || generateSessionId());\n } finally {\n setIsLoading(false);\n }\n };\n\n initializeSession();\n }, [config, storageKeyPrefix, identityMode]);\n\n const handlePreChatSubmit = useCallback(\n (name: string, email: string) => {\n const convId = conversationId || generateSessionId();\n const user: IUser = { name, email, type: 'customer', status: 'online' };\n\n const storageData: StoredUserData = {\n name,\n email,\n conversationId: convId,\n timestamp: Date.now(),\n };\n\n try {\n localStorage.setItem(`${storageKeyPrefix}_user`, JSON.stringify(storageData));\n } catch {\n // Storage unavailable\n }\n\n setUserInfo(user);\n setConversationId(convId);\n onPreChatSubmit?.(user);\n },\n [conversationId, storageKeyPrefix, onPreChatSubmit]\n );\n\n if (isLoading) return null;\n if (currentState === 'closed') return null;\n\n const positionClass = position === 'left' ? 'left-4' : 'right-4';\n const primaryColor = config.theme?.primary || '#337eff';\n const primaryStrong = config.theme?.primaryStrong || '#005eff';\n\n // FAB button — only show when minimized\n if (currentState === 'minimized') {\n return (\n <div className={`fixed bottom-5 ${positionClass} z-50 ${className}`}>\n <button\n type=\"button\"\n onClick={() => setState('open')}\n className={`group relative rounded-full text-white transition-all duration-300 flex items-center justify-center touch-none select-none ${\n showHint ? 'animate-bounce' : ''\n } ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`}\n onMouseEnter={(e) => { e.currentTarget.style.transform = 'scale(1.08)'; }}\n onMouseLeave={(e) => { e.currentTarget.style.transform = isDragging ? 'scale(1.1)' : 'scale(1)'; }}\n style={{\n width: 64,\n height: 64,\n background: `linear-gradient(135deg, ${primaryColor}, ${primaryStrong})`,\n boxShadow: [\n `0 4px 24px 0 ${primaryColor}80`,\n `0 8px 32px -4px rgba(0,0,0,0.3)`,\n `inset 0 1px 0 0 rgba(255,255,255,0.2)`,\n ].join(', '),\n }}\n aria-label=\"Open chat\"\n {...handlers}\n >\n <ChatBubbleIcon size={28} color=\"white\" className=\"pointer-events-none\" />\n\n {/* Pulse ring — subtle blue glow */}\n <span\n className=\"absolute inset-0 rounded-full animate-ping pointer-events-none\"\n style={{\n backgroundColor: primaryColor,\n opacity: 0.15,\n animationDuration: '2.5s',\n }}\n />\n </button>\n </div>\n );\n }\n\n // Open state — pre-chat form (form mode only)\n if (identityMode === 'form' && (!userInfo || !userInfo.email || !userInfo.name)) {\n return (\n <PreChatForm\n onSubmit={handlePreChatSubmit}\n className={className}\n initialName={config.currentUser?.name}\n initialEmail={config.currentUser?.email}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n }\n\n // Open state — chat widget\n const fullConfig: IChatConfig = {\n ...config,\n conversationId,\n currentUser: userInfo || undefined,\n };\n\n // Animation styles for open/close\n const widgetAnimationStyle: React.CSSProperties =\n showWidget && !isAnimating\n ? {\n opacity: 1,\n transform: 'translateY(0) scale(1)',\n transition: 'opacity 0.25s ease-out, transform 0.25s ease-out',\n }\n : {\n opacity: 0,\n transform: 'translateY(12px) scale(0.97)',\n transition: 'opacity 0.2s ease-in, transform 0.2s ease-in',\n };\n\n return (\n <div style={widgetAnimationStyle}>\n <ChatWidget\n config={fullConfig}\n className={className}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n resolvedPosition={position}\n />\n </div>\n );\n}\n","import { useState } from 'react';\n\ninterface PreChatFormProps {\n onSubmit: (name: string, email: string) => void;\n className?: string;\n initialName?: string;\n initialEmail?: string;\n /**\n * Callback when user wants to minimize the form\n */\n onMinimize: () => void;\n /**\n * Callback when user wants to close the form\n */\n onClose: () => void;\n}\n\n/**\n * PreChatForm component for collecting user information before starting chat.\n * Styled to match the Xcelsior website design system.\n */\nexport function PreChatForm({\n onSubmit,\n className = '',\n initialName = '',\n initialEmail = '',\n onMinimize,\n onClose,\n}: PreChatFormProps) {\n const [name, setName] = useState(initialName);\n const [email, setEmail] = useState(initialEmail);\n const [errors, setErrors] = useState<{ name?: string; email?: string }>({});\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [focusedField, setFocusedField] = useState<string | null>(null);\n\n const validateForm = (): boolean => {\n const newErrors: { name?: string; email?: string } = {};\n\n // Validate name\n if (!name.trim()) {\n newErrors.name = 'Name is required';\n } else if (name.trim().length < 2) {\n newErrors.name = 'Name must be at least 2 characters';\n }\n\n // Validate email\n if (!email.trim()) {\n newErrors.email = 'Email is required';\n } else {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n newErrors.email = 'Please enter a valid email address';\n }\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n setIsSubmitting(true);\n try {\n onSubmit(name.trim(), email.trim());\n } catch (error) {\n console.error('Error submitting form:', error);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const inputStyle = (fieldName: string, hasError: boolean): React.CSSProperties => ({\n width: '100%',\n padding: '10px 16px',\n fontSize: '14px',\n lineHeight: '20px',\n letterSpacing: '0.006em',\n color: '#f7f7f8',\n backgroundColor: 'rgba(255,255,255,0.04)',\n border: 'none',\n borderRadius: '12px',\n outline: 'none',\n boxShadow: hasError\n ? 'inset 0 0 0 1px rgba(255,99,99,0.5)'\n : focusedField === fieldName\n ? 'inset 0 0 0 1px rgba(51,126,255,0.4), 0 0 0 3px rgba(51,126,255,0.15)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.08)',\n transition: 'box-shadow 0.2s ease',\n caretColor: '#337eff',\n });\n\n return (\n <div\n className={`fixed bottom-4 right-4 z-50 flex flex-col overflow-hidden ${className}`}\n style={{\n width: 380,\n maxHeight: 'calc(100vh - 2rem)',\n backgroundColor: '#00001a',\n borderRadius: 16,\n boxShadow: [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.12)',\n '0 25px 60px -12px rgba(0,0,0,0.6)',\n '0 0 40px -8px rgba(51,126,255,0.15)',\n ].join(', '),\n /* Dot grid texture */\n backgroundImage:\n 'radial-gradient(circle, rgba(255,255,255,0.03) 1px, transparent 1px)',\n backgroundSize: '24px 24px',\n }}\n >\n {/* Header — matching ChatHeader gradient */}\n <div\n className=\"relative text-white overflow-hidden\"\n style={{\n background: 'linear-gradient(135deg, #337eff 0%, #005eff 50%, #001a66 100%)',\n }}\n >\n {/* Glass overlay */}\n <div\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n background:\n 'linear-gradient(180deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 40%)',\n }}\n />\n <div className=\"relative px-5 py-4\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h2\n className=\"font-semibold\"\n style={{\n fontSize: '17px',\n letterSpacing: '-0.01em',\n }}\n >\n Start a Conversation\n </h2>\n <p\n className=\"mt-1\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(255,255,255,0.6)',\n }}\n >\n Please provide your details to continue\n </p>\n </div>\n <div className=\"flex gap-1 ml-2\">\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Minimize chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Close chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Close</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n </div>\n {/* Bottom edge line */}\n <div\n className=\"h-px\"\n style={{\n background:\n 'linear-gradient(90deg, transparent 5%, rgba(255,255,255,0.12) 30%, rgba(255,255,255,0.12) 70%, transparent 95%)',\n }}\n />\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"p-5 flex flex-col gap-4\">\n {/* Name Input */}\n <div>\n <label\n htmlFor=\"chat-name\"\n className=\"block mb-2 font-medium\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.72)',\n }}\n >\n Name <span style={{ color: '#ff6363' }}>*</span>\n </label>\n <input\n type=\"text\"\n id=\"chat-name\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (errors.name) {\n setErrors((prev) => ({ ...prev, name: undefined }));\n }\n }}\n onFocus={() => setFocusedField('name')}\n onBlur={() => setFocusedField(null)}\n style={inputStyle('name', !!errors.name)}\n placeholder=\"John Doe\"\n disabled={isSubmitting}\n autoComplete=\"name\"\n />\n {errors.name && (\n <p\n className=\"mt-1.5\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: '#ff6363',\n }}\n role=\"alert\"\n >\n {errors.name}\n </p>\n )}\n </div>\n\n {/* Email Input */}\n <div>\n <label\n htmlFor=\"chat-email\"\n className=\"block mb-2 font-medium\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.72)',\n }}\n >\n Email <span style={{ color: '#ff6363' }}>*</span>\n </label>\n <input\n type=\"email\"\n id=\"chat-email\"\n value={email}\n onChange={(e) => {\n setEmail(e.target.value);\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }));\n }\n }}\n onFocus={() => setFocusedField('email')}\n onBlur={() => setFocusedField(null)}\n style={inputStyle('email', !!errors.email)}\n placeholder=\"john@example.com\"\n disabled={isSubmitting}\n autoComplete=\"email\"\n />\n {errors.email && (\n <p\n className=\"mt-1.5\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: '#ff6363',\n }}\n role=\"alert\"\n >\n {errors.email}\n </p>\n )}\n </div>\n\n {/* Submit Button — gradient pill matching website CTA */}\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className=\"w-full py-2.5 rounded-xl font-semibold text-white transition-all duration-200\"\n style={{\n fontSize: '14px',\n letterSpacing: '0.006em',\n background: 'linear-gradient(135deg, #337eff, #005eff)',\n boxShadow: '0 4px 16px -4px rgba(51,126,255,0.4)',\n opacity: isSubmitting ? 0.6 : 1,\n cursor: isSubmitting ? 'not-allowed' : 'pointer',\n }}\n onMouseEnter={(e) => {\n if (!isSubmitting) {\n e.currentTarget.style.boxShadow =\n '0 6px 20px -4px rgba(51,126,255,0.5)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.boxShadow =\n '0 4px 16px -4px rgba(51,126,255,0.4)';\n }}\n >\n {isSubmitting ? (\n <span className=\"flex items-center justify-center gap-2\">\n <svg\n className=\"animate-spin\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n aria-label=\"Loading\"\n >\n <title>Loading</title>\n <path d=\"M21 12a9 9 0 11-6.219-8.56\" />\n </svg>\n Starting Chat...\n </span>\n ) : (\n 'Start Chat'\n )}\n </button>\n\n {/* Privacy Notice */}\n <p\n className=\"text-center\"\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: 'rgba(247,247,248,0.28)',\n }}\n >\n We respect your privacy. Your information will only be used to assist you.\n </p>\n </form>\n\n {/* Footer */}\n <div\n className=\"px-4 py-1.5 text-center\"\n style={{\n borderTop: '1px solid rgba(255,255,255,0.06)',\n backgroundColor: 'rgba(0,0,0,0.2)',\n }}\n >\n <p\n style={{\n fontSize: '10px',\n letterSpacing: '0.025em',\n color: 'rgba(247,247,248,0.28)',\n }}\n >\n Powered by{' '}\n <span style={{ fontWeight: 600, color: 'rgba(247,247,248,0.45)' }}>\n Xcelsior\n </span>\n </p>\n </div>\n </div>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport type { WidgetPosition } from '../types';\n\nconst STORAGE_KEY = 'xcelsior-chat-position';\n\nfunction getStoredPosition(): 'left' | 'right' {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored === 'left' || stored === 'right') return stored;\n } catch {\n // localStorage not available\n }\n return 'right';\n}\n\nfunction storePosition(position: 'left' | 'right') {\n try {\n localStorage.setItem(STORAGE_KEY, position);\n } catch {\n // localStorage not available\n }\n}\n\nexport function useDraggablePosition(configPosition: WidgetPosition = 'auto') {\n const resolvedDefault = configPosition === 'auto' ? getStoredPosition() : configPosition;\n const [position, setPosition] = useState<'left' | 'right'>(resolvedDefault);\n const [isDragging, setIsDragging] = useState(false);\n const dragStartX = useRef(0);\n const fabRef = useRef<HTMLButtonElement>(null);\n const hasShownHint = useRef(false);\n const [showHint, setShowHint] = useState(false);\n\n // Show bounce hint on first visit\n useEffect(() => {\n try {\n const hasVisited = localStorage.getItem('xcelsior-chat-hint-shown');\n if (!hasVisited && !hasShownHint.current) {\n hasShownHint.current = true;\n setShowHint(true);\n const timer = setTimeout(() => {\n setShowHint(false);\n localStorage.setItem('xcelsior-chat-hint-shown', 'true');\n }, 2000);\n return () => clearTimeout(timer);\n }\n } catch {\n // localStorage not available\n }\n }, []);\n\n const handlePointerDown = useCallback((e: React.PointerEvent) => {\n dragStartX.current = e.clientX;\n setIsDragging(true);\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n }, []);\n\n const handlePointerMove = useCallback((_e: React.PointerEvent) => {\n // Visual feedback could be added here (e.g., opacity change)\n }, []);\n\n const handlePointerUp = useCallback(\n (e: React.PointerEvent) => {\n setIsDragging(false);\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n\n const deltaX = e.clientX - dragStartX.current;\n // Only snap if dragged more than 50px horizontally\n if (Math.abs(deltaX) > 50) {\n const screenMid = window.innerWidth / 2;\n const newPosition = e.clientX < screenMid ? 'left' : 'right';\n if (newPosition !== position) {\n setPosition(newPosition);\n storePosition(newPosition);\n }\n }\n },\n [position]\n );\n\n return {\n position,\n isDragging,\n showHint,\n fabRef,\n handlers: {\n onPointerDown: handlePointerDown,\n onPointerMove: handlePointerMove,\n onPointerUp: handlePointerUp,\n },\n };\n}\n","import { useCallback, useState } from 'react';\n\nexport type ChatWidgetState = 'open' | 'minimized' | 'closed' | 'undefined';\n\nexport interface UseChatWidgetStateOptions {\n /**\n * Controlled state. When provided, the component is controlled.\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\nexport interface UseChatWidgetStateReturn {\n /**\n * Current state of the widget\n */\n currentState: ChatWidgetState;\n /**\n * Function to update the state\n */\n setState: (newState: ChatWidgetState) => void;\n /**\n * Whether the state is controlled\n */\n isControlled: boolean;\n}\n\n/**\n * Hook to manage chat widget state (controlled vs uncontrolled)\n * Encapsulates the logic for handling both controlled and uncontrolled state patterns\n */\nexport function useChatWidgetState({\n state: controlledState,\n defaultState = 'minimized',\n onStateChange,\n}: UseChatWidgetStateOptions): UseChatWidgetStateReturn {\n // Handle controlled vs uncontrolled state\n const [uncontrolledState, setUncontrolledState] = useState<ChatWidgetState>(defaultState);\n const isControlled = controlledState !== undefined && controlledState !== 'undefined';\n const currentState = isControlled ? controlledState : uncontrolledState;\n\n // State setter that works for both controlled and uncontrolled modes\n const setState = useCallback(\n (newValue: ChatWidgetState) => {\n // Update internal state if uncontrolled\n if (!isControlled) {\n setUncontrolledState(newValue);\n }\n // Always call the change handler if provided\n onStateChange?.(newValue);\n },\n [isControlled, onStateChange]\n );\n\n return {\n currentState,\n setState,\n isControlled,\n };\n}\n","interface TypingIndicatorProps {\n isTyping: boolean;\n userName?: string;\n}\n\nexport function TypingIndicator({ isTyping, userName }: TypingIndicatorProps) {\n if (!isTyping) {\n return null;\n }\n\n return (\n <div\n className=\"px-4 py-2\"\n style={{\n borderTop: '1px solid rgba(255,255,255,0.06)',\n backgroundColor: 'rgba(0,0,0,0.15)',\n }}\n >\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"rounded-full animate-bounce\"\n style={{\n width: 5,\n height: 5,\n backgroundColor: 'rgba(51,126,255,0.6)',\n animationDelay: `${i * 0.1}s`,\n animationDuration: '0.8s',\n }}\n />\n ))}\n </div>\n <span\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.45)',\n }}\n >\n {userName ? `${userName} is typing...` : 'Someone is typing...'}\n </span>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","error","useCallback","useEffect","useState","useState","useEffect","error","useCallback","useState","axios","error","useEffect","useState","useCallback","useEffect","useRef","useState","jsx","jsxs","useCallback","useEffect","useRef","jsx","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","computeIsLightTheme","useState","useRef","useEffect","jsx","jsxs","useRef","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useCallback","isTyping","useEffect","useCallback","useEffect","useState","useState","jsx","jsxs","useState","useCallback","useRef","useEffect","STORAGE_KEY","useCallback","useState","jsx","jsxs","useState","useCallback","useEffect","convId","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/hooks/useWebSocket.ts","../src/hooks/useMessages.ts","../src/utils/api.ts","../src/hooks/useFileUpload.ts","../src/hooks/useTypingIndicator.ts","../src/hooks/useResizableWidget.ts","../src/components/BrandIcons.tsx","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/Spinner.tsx","../src/components/MessageItem.tsx","../src/components/MarkdownMessage.tsx","../src/utils/markdown-styles.ts","../src/components/ThinkingIndicator.tsx","../src/components/ChatInput.tsx","../src/components/Chat.tsx","../src/components/PreChatForm.tsx","../src/hooks/useDraggablePosition.ts","../src/hooks/useChatWidgetState.ts","../src/components/TypingIndicator.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useWebSocket } from '../hooks/useWebSocket';\nimport { useMessages } from '../hooks/useMessages';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useTypingIndicator } from '../hooks/useTypingIndicator';\nimport { useResizableWidget } from '../hooks/useResizableWidget';\nimport { ChatHeader } from './ChatHeader';\nimport { MessageList } from './MessageList';\nimport { ChatInput } from './ChatInput';\nimport type { IChatConfig, IMessage, IUser } from '../types';\n\nexport interface ChatWidgetProps {\n config: IChatConfig;\n className?: string;\n variant?: 'popover' | 'fullPage';\n externalWebSocket?: WebSocket | null;\n onMinimize?: () => void;\n onClose?: () => void;\n /** Resolved position (left or right) from the parent Chat component */\n resolvedPosition?: 'left' | 'right';\n}\n\n/** Generate an anonymous user for progressive identity mode */\nfunction getAnonymousUser(): IUser {\n let anonId: string;\n try {\n const stored = localStorage.getItem('xcelsior-chat-anon-id');\n if (stored) {\n anonId = stored;\n } else {\n anonId = `anon-${crypto.randomUUID?.() || Math.random().toString(36).slice(2)}`;\n localStorage.setItem('xcelsior-chat-anon-id', anonId);\n }\n } catch {\n anonId = `anon-${Math.random().toString(36).slice(2)}`;\n }\n\n return {\n name: 'Visitor',\n email: `${anonId}@anonymous.xcelsior.co`,\n type: 'customer',\n status: 'online',\n };\n}\n\nexport function ChatWidget({\n config,\n className = '',\n variant = 'popover',\n externalWebSocket,\n onMinimize,\n onClose,\n resolvedPosition = 'right',\n}: ChatWidgetProps) {\n const isFullPage = variant === 'fullPage';\n\n // Resolve user — support anonymous mode for progressive identity\n const effectiveUser = config.currentUser || getAnonymousUser();\n const effectiveConfig = { ...config, currentUser: effectiveUser };\n\n const websocket = useWebSocket(effectiveConfig, externalWebSocket);\n\n const { messages, addMessage, isLoading, loadMore, hasMore, isLoadingMore, isBotThinking } =\n useMessages(websocket, effectiveConfig);\n\n const fileUpload = useFileUpload(config.apiKey, config.fileUpload);\n const { isTyping, typingUsers } = useTypingIndicator(websocket);\n\n const { width, height, isResizing, isNearEdge, containerResizeProps } = useResizableWidget({\n initialWidth: 380,\n initialHeight: 580,\n minWidth: 320,\n minHeight: 400,\n maxWidth: 800,\n maxHeight: 900,\n enabled: !isFullPage,\n });\n\n const handleSendMessage = useCallback(\n (content: string) => {\n if (!websocket.isConnected) {\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n const optimisticMessage: IMessage = {\n id: `temp-${Date.now()}`,\n conversationId: config.conversationId || '',\n senderId: effectiveUser.email,\n senderType: effectiveUser.type,\n content,\n messageType: 'text',\n createdAt: new Date().toISOString(),\n status: 'sent',\n };\n\n addMessage(optimisticMessage);\n\n websocket.sendMessage('sendMessage', {\n conversationId: config.conversationId,\n content,\n messageType: 'text',\n });\n\n config.onMessageSent?.(optimisticMessage);\n },\n [websocket, config, addMessage, effectiveUser]\n );\n\n const handleTyping = useCallback(\n (isTyping: boolean) => {\n if (!websocket.isConnected || config.enableTypingIndicator === false) return;\n websocket.sendMessage('typing', {\n conversationId: config.conversationId,\n isTyping,\n });\n },\n [websocket, config]\n );\n\n useEffect(() => {\n if (websocket.error) {\n config.toast?.error(websocket.error.message || 'An error occurred');\n }\n }, [websocket.error, config]);\n\n // Theme tokens — aligned with Xcelsior website design system\n const bgColor = config.theme?.background || '#00001a';\n const bgAlt = config.theme?.backgroundAlt || '#02164a';\n const textColor = config.theme?.text || '#f7f7f8';\n const primaryColor = config.theme?.primary || '#337eff';\n const textMuted = config.theme?.textMuted || 'rgba(247,247,248,0.45)';\n\n // Detect light vs dark theme based on background luminance\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n // Position-aware container styles\n const positionClass = resolvedPosition === 'left' ? 'left-4' : 'right-4';\n\n const containerStyle: React.CSSProperties = isFullPage\n ? { backgroundColor: bgColor, color: textColor }\n : {\n position: 'relative',\n width,\n height,\n maxHeight: 'calc(100vh - 100px)',\n backgroundColor: bgColor,\n color: textColor,\n borderRadius: 16,\n /* Xcelsior card pattern: inset box-shadow borders instead of border-image */\n boxShadow: isLightTheme\n ? [\n '0 25px 60px -12px rgba(0,0,0,0.15)',\n '0 0 0 1px rgba(0,0,0,0.08)',\n ].join(', ')\n : [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.12)',\n '0 25px 60px -12px rgba(0,0,0,0.6)',\n '0 0 40px -8px rgba(51,126,255,0.15)',\n ].join(', '),\n userSelect: isResizing ? 'none' : undefined,\n };\n\n /* Dot grid texture matching the Xcelsior website background */\n const dotGridBg: React.CSSProperties = !isFullPage\n ? {\n backgroundImage: isLightTheme\n ? `radial-gradient(circle, rgba(0,0,0,0.04) 1px, transparent 1px)`\n : `radial-gradient(circle, rgba(255,255,255,0.03) 1px, transparent 1px)`,\n backgroundSize: '24px 24px',\n }\n : {};\n\n // Subtle edge glow when user hovers near a resize edge\n // Uses outline (not clipped by overflow:hidden) for visibility\n const edgeHintStyle: React.CSSProperties = !isFullPage && isNearEdge\n ? {\n outline: isLightTheme\n ? '2px solid rgba(0,94,255,0.25)'\n : '2px solid rgba(51,126,255,0.35)',\n outlineOffset: -1,\n transition: 'outline 150ms ease',\n }\n : {\n outline: '2px solid transparent',\n outlineOffset: -1,\n transition: 'outline 150ms ease',\n };\n\n return (\n <div\n className={\n isFullPage\n ? `flex flex-col h-full ${className}`\n : `fixed bottom-20 ${positionClass} z-50 flex flex-col overflow-hidden ${className}`\n }\n style={{ ...containerStyle, ...dotGridBg, ...edgeHintStyle }}\n {...(!isFullPage ? containerResizeProps : {})}\n >\n {!isFullPage && (\n <ChatHeader\n agent={\n effectiveUser.type === 'customer'\n ? {\n email: 'contact@xcelsior.co',\n name: 'Xcelsior Software',\n type: 'agent',\n status: websocket.isConnected ? 'online' : 'offline',\n }\n : undefined\n }\n onMinimize={onMinimize}\n onClose={onClose}\n theme={config.theme}\n />\n )}\n\n {/* Connection Status */}\n {!websocket.isConnected && (\n <div\n className=\"px-4 py-2\"\n style={{\n backgroundColor: isLightTheme ? 'rgba(255,169,56,0.08)' : 'rgba(255,169,56,0.06)',\n borderBottom: `1px solid rgba(255,169,56,${isLightTheme ? '0.15' : '0.12'})`,\n }}\n >\n <div className=\"flex items-center gap-2\">\n <div\n className=\"w-1.5 h-1.5 rounded-full animate-pulse\"\n style={{ backgroundColor: config.theme?.statusCaution || '#ffa938' }}\n />\n <span\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: config.theme?.statusCaution || '#ffa938',\n }}\n >\n Reconnecting...\n </span>\n <button\n type=\"button\"\n onClick={websocket.reconnect}\n className=\"ml-auto transition-opacity\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: config.theme?.statusCaution || '#ffa938',\n opacity: 0.7,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.opacity = '1';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.opacity = '0.7';\n }}\n >\n Retry\n </button>\n </div>\n </div>\n )}\n\n {/* Messages */}\n {isLoading ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <div className=\"text-center\">\n <div\n className=\"w-7 h-7 border-2 border-t-transparent rounded-full animate-spin mx-auto mb-3\"\n style={{\n borderColor: primaryColor,\n borderTopColor: 'transparent',\n }}\n />\n <p\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: textMuted,\n }}\n >\n Loading messages...\n </p>\n </div>\n </div>\n ) : (\n <MessageList\n messages={messages}\n currentUser={effectiveUser}\n isTyping={isTyping}\n typingUser={typingUsers[0]}\n autoScroll={true}\n onLoadMore={loadMore}\n hasMore={hasMore}\n isLoadingMore={isLoadingMore}\n theme={config.theme}\n onQuickAction={handleSendMessage}\n isBotThinking={isBotThinking}\n />\n )}\n\n {/* Input */}\n <ChatInput\n onSend={handleSendMessage}\n onTyping={handleTyping}\n config={effectiveConfig}\n fileUpload={fileUpload}\n disabled={!websocket.isConnected}\n />\n\n {/* Powered by footer */}\n {!isFullPage && (\n <div\n className=\"px-4 py-1.5 text-center\"\n style={{\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.06)'\n : '1px solid rgba(255,255,255,0.06)',\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.03)'\n : 'rgba(0,0,0,0.2)',\n }}\n >\n <p\n style={{\n fontSize: '10px',\n letterSpacing: '0.025em',\n color: isLightTheme\n ? 'rgba(0,0,0,0.35)'\n : 'rgba(247,247,248,0.28)',\n }}\n >\n Powered by{' '}\n <span style={{\n fontWeight: 600,\n color: isLightTheme\n ? 'rgba(0,0,0,0.5)'\n : 'rgba(247,247,248,0.45)',\n }}>\n Xcelsior\n </span>\n </p>\n </div>\n )}\n\n </div>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from 'react';\nimport type { IChatConfig, IWebSocketMessage } from '../types';\n\nexport interface UseWebSocketReturn {\n isConnected: boolean;\n sendMessage: (action: string, data: any) => void;\n lastMessage: IWebSocketMessage | null;\n error: Error | null;\n reconnect: () => void;\n}\n\n/**\n * Hook for WebSocket connection in chat widget.\n * Can use an external WebSocket connection (for agents) via the externalWebSocket prop.\n */\nexport function useWebSocket(\n config: IChatConfig,\n externalWebSocket?: WebSocket | null\n): UseWebSocketReturn {\n const [isConnected, setIsConnected] = useState(false);\n const [lastMessage, setLastMessage] = useState<IWebSocketMessage | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const wsRef = useRef<WebSocket | null>(null);\n const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | null>(null);\n const maxReconnectAttempts = 5;\n const reconnectDelay = 3000;\n\n // Use external WebSocket if provided (for agents)\n const isUsingExternalWs = !!externalWebSocket;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const subscribeToMessage = useCallback((webSocket: WebSocket) => {\n // Remove previous listener if it exists\n if (messageHandlerRef.current) {\n webSocket.removeEventListener('message', messageHandlerRef.current);\n }\n\n // Create new message handler\n const handler = (event: MessageEvent) => {\n try {\n const message: IWebSocketMessage = JSON.parse(event.data);\n setLastMessage(message);\n\n // Handle different message types\n if (message.type === 'message' && message.data) {\n config.onMessageReceived?.(message.data);\n } else if (message.type === 'error') {\n const err = new Error(message.data?.message || 'WebSocket error');\n setError(err);\n config.onError?.(err);\n }\n } catch (err) {\n console.error('Failed to parse WebSocket message:', err);\n }\n };\n\n // Add the new listener\n webSocket.addEventListener('message', handler);\n messageHandlerRef.current = handler;\n\n // Return cleanup function\n return () => {\n webSocket.removeEventListener('message', handler);\n if (messageHandlerRef.current === handler) {\n messageHandlerRef.current = null;\n }\n };\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const connect = useCallback(() => {\n console.log('connecting to WebSocket...', config.currentUser, config.conversationId);\n try {\n // Clean up existing connection\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close();\n }\n\n // Build WebSocket URL with query parameters\n const url = new URL(config.websocketUrl);\n url.searchParams.set('user', JSON.stringify(config.currentUser));\n if (config.conversationId) {\n url.searchParams.set('conversationId', config.conversationId);\n }\n if (config.apiKey) {\n url.searchParams.set('apiKey', config.apiKey);\n }\n\n const ws = new WebSocket(url.toString());\n\n ws.onopen = () => {\n console.log('WebSocket connected');\n setIsConnected(true);\n setError(null);\n reconnectAttemptsRef.current = 0;\n config.onConnectionChange?.(true);\n };\n\n ws.onerror = (event) => {\n console.error('WebSocket error:', event);\n const err = new Error('WebSocket connection error');\n setError(err);\n config.onError?.(err);\n };\n\n ws.onclose = (event) => {\n console.log('WebSocket closed:', event.code, event.reason);\n setIsConnected(false);\n config.onConnectionChange?.(false);\n wsRef.current = null;\n\n // Attempt to reconnect if not a normal closure\n if (event.code !== 1000 && reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current += 1;\n console.log(\n `Reconnecting... (${reconnectAttemptsRef.current}/${maxReconnectAttempts})`\n );\n reconnectTimeoutRef.current = setTimeout(() => {\n connect();\n }, reconnectDelay);\n }\n };\n\n subscribeToMessage(ws);\n wsRef.current = ws ?? null;\n } catch (err) {\n console.error('Failed to create WebSocket connection:', err);\n const error = err instanceof Error ? err : new Error('Failed to connect');\n setError(error);\n config.onError?.(error);\n }\n }, [JSON.stringify([config.currentUser, config.conversationId])]);\n\n const sendMessage = useCallback(\n (action: string, data: any) => {\n if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {\n console.error('WebSocket is not connected');\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n try {\n wsRef.current.send(\n JSON.stringify({\n action,\n data,\n })\n );\n } catch (err) {\n console.error('Failed to send message:', err);\n const error = err instanceof Error ? err : new Error('Failed to send message');\n setError(error);\n config.onError?.(error);\n }\n },\n [config]\n );\n\n const reconnect = useCallback(() => {\n reconnectAttemptsRef.current = 0;\n connect();\n }, [connect]);\n\n useEffect(() => {\n if (isUsingExternalWs) {\n setIsConnected(externalWebSocket?.readyState === WebSocket.OPEN || false);\n wsRef.current = externalWebSocket;\n const cleanup = subscribeToMessage(externalWebSocket);\n return cleanup;\n }\n\n connect();\n\n // Cleanup on unmount\n return () => {\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n }\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close(1000, 'Component unmounted');\n }\n };\n }, [connect, isUsingExternalWs, externalWebSocket, subscribeToMessage]);\n\n // Use external connection state if available\n const effectiveIsConnected = isUsingExternalWs\n ? externalWebSocket?.readyState === WebSocket.OPEN || false\n : isConnected;\n\n return {\n isConnected: effectiveIsConnected,\n sendMessage,\n lastMessage,\n error,\n reconnect,\n };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { IMessage, IChatConfig, UseMessagesReturn } from '../types';\nimport type { UseWebSocketReturn } from './useWebSocket';\nimport { fetchMessages } from '../utils/api';\n\nexport function useMessages(websocket: UseWebSocketReturn, config: IChatConfig): UseMessagesReturn {\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nextPageToken, setNextPageToken] = useState<string | undefined>(undefined);\n const [hasMore, setHasMore] = useState(true);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n const [isBotThinking, setIsBotThinking] = useState(false);\n\n // Extract stable references from config\n const { httpApiUrl, conversationId, headers, onError, toast } = config;\n\n const headersWithApiKey = useMemo(\n () => ({\n ...headers,\n 'x-api-key': config.apiKey,\n }),\n [headers, config.apiKey]\n );\n\n // Fetch existing messages when conversationId changes\n useEffect(() => {\n const loadMessages = async () => {\n // Only fetch if we have httpApiUrl and conversationId\n if (!httpApiUrl || !conversationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n { conversationId, limit: 20 },\n headersWithApiKey\n );\n\n setMessages(result.data);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load messages');\n setError(error);\n onError?.(error);\n toast?.error('Failed to load existing messages');\n } finally {\n setIsLoading(false);\n }\n };\n\n loadMessages();\n // Only re-run when conversationId or httpApiUrl changes\n }, [conversationId, httpApiUrl, headersWithApiKey, onError, toast]);\n\n // Extract onMessageReceived callback\n const { onMessageReceived } = config;\n\n // Listen for incoming messages from WebSocket\n useEffect(() => {\n if (websocket.lastMessage?.type === 'message' && websocket.lastMessage.data) {\n const newMessage: IMessage = websocket.lastMessage.data;\n\n if (conversationId && newMessage.conversationId !== conversationId) {\n // Ignore messages for other conversations\n return;\n }\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === newMessage.id)) {\n return prev;\n }\n return [...prev, newMessage];\n });\n\n // Clear bot thinking state when bot or system message arrives\n if (newMessage.senderType === 'bot' || newMessage.senderType === 'system') {\n setIsBotThinking(false);\n }\n\n // Notify parent component about new message\n onMessageReceived?.(newMessage);\n }\n }, [websocket.lastMessage, onMessageReceived, conversationId]);\n\n const addMessage = useCallback((message: IMessage) => {\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === message.id)) {\n return prev;\n }\n return [...prev, message];\n });\n // Show bot thinking indicator immediately when customer sends a message\n if (message.senderType === 'customer') {\n setIsBotThinking(true);\n }\n }, []);\n\n const updateMessageStatus = useCallback((messageId: string, status: IMessage['status']) => {\n setMessages((prev) => prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg)));\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n }, []);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || isLoadingMore || !httpApiUrl || !conversationId || !nextPageToken) {\n return;\n }\n\n setIsLoadingMore(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n {\n conversationId,\n limit: 20,\n pageToken: nextPageToken,\n },\n headersWithApiKey\n );\n\n setMessages((prev) => [...result.data, ...prev]);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load more messages');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoadingMore(false);\n }\n }, [\n hasMore,\n isLoadingMore,\n httpApiUrl,\n conversationId,\n nextPageToken,\n headersWithApiKey,\n onError,\n ]);\n\n return {\n messages,\n addMessage,\n updateMessageStatus,\n clearMessages,\n isLoading,\n error,\n loadMore,\n hasMore,\n isLoadingMore,\n isBotThinking,\n };\n}\n","import axios from 'axios';\nimport type { IMessage, IApiResponse } from '../types';\n\nexport interface FetchMessagesParams {\n conversationId: string;\n limit?: number;\n pageToken?: string;\n}\n\n/**\n * Fetch messages for a conversation from the REST API\n */\nexport async function fetchMessages(\n baseUrl: string,\n params: FetchMessagesParams,\n headers?: Record<string, string>\n) {\n try {\n const response = await axios.get<IApiResponse<IMessage[]>>(`${baseUrl}/messages`, {\n params: {\n conversationId: params.conversationId,\n limit: params.limit || 50,\n pageToken: params.pageToken,\n },\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n });\n\n return {\n data: response.data.data ?? [],\n nextPageToken: response.data.pagination?.nextPageToken,\n };\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(\n error.response?.data?.error?.message || error.message || 'Failed to fetch messages'\n );\n }\n throw error;\n }\n}\n","import { useState } from 'react';\nimport axios from 'axios';\nimport type { IFileUploadConfig, IUploadedFile } from '../types';\n\nexport interface UseFileUploadReturn {\n uploadFile: (file: File) => Promise<IUploadedFile | null>;\n isUploading: boolean;\n uploadProgress: number;\n error: Error | null;\n canUpload: boolean;\n}\n\nexport function useFileUpload(apiKey: string, config?: IFileUploadConfig): UseFileUploadReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadProgress, setUploadProgress] = useState(0);\n const [error, setError] = useState<Error | null>(null);\n\n const defaultConfig = {\n maxFileSize: 10 * 1024 * 1024, // 10MB default\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n };\n\n const finalConfig = { ...defaultConfig, ...config };\n const canUpload = !!config?.uploadUrl;\n\n const validateFile = (file: File): string | null => {\n if (!finalConfig.allowedTypes.includes(file.type)) {\n return `File type ${file.type} is not supported. Allowed types: ${finalConfig.allowedTypes.join(', ')}`;\n }\n\n if (file.size > finalConfig.maxFileSize) {\n return `File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds the maximum allowed size of ${(finalConfig.maxFileSize / 1024 / 1024).toFixed(2)}MB`;\n }\n\n return null;\n };\n\n const uploadFile = async (file: File): Promise<IUploadedFile | null> => {\n if (!config?.uploadUrl) {\n const err = new Error('File upload URL is not configured');\n setError(err);\n throw err;\n }\n\n const validationError = validateFile(file);\n if (validationError) {\n const err = new Error(validationError);\n setError(err);\n throw err;\n }\n\n setIsUploading(true);\n setUploadProgress(0);\n setError(null);\n\n try {\n // Step 1: Get presigned upload URL from the API\n const uploadUrlResponse = await axios.post(\n config.uploadUrl,\n {\n fileName: file.name,\n contentType: file.type,\n fileSize: file.size,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey || '',\n ...config.headers,\n },\n }\n );\n\n const { uploadUrl, attachmentUrl } =\n uploadUrlResponse.data.data || uploadUrlResponse.data;\n\n if (!uploadUrl || !attachmentUrl) {\n throw new Error('Failed to get upload URL from server');\n }\n\n // Step 2: Upload file directly to S3 using presigned URL\n await axios.put(uploadUrl, file, {\n headers: {\n 'Content-Type': file.type,\n },\n onUploadProgress: (progressEvent) => {\n if (progressEvent.total) {\n const progress = Math.round(\n (progressEvent.loaded * 100) / progressEvent.total\n );\n setUploadProgress(progress);\n }\n },\n });\n\n return {\n url: attachmentUrl,\n name: file.name,\n size: file.size,\n type: file.type,\n markdown: file.type.startsWith('image/')\n ? `![${file.name}](${attachmentUrl})`\n : `[${file.name}](${attachmentUrl})`,\n };\n } catch (err) {\n console.error('File upload failed:', err);\n const error = err instanceof Error ? err : new Error('Upload failed');\n setError(error);\n throw error;\n } finally {\n setIsUploading(false);\n setUploadProgress(0);\n }\n };\n\n return {\n uploadFile,\n isUploading,\n uploadProgress,\n error,\n canUpload,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { UseWebSocketReturn } from './useWebSocket';\n\nexport interface UseTypingIndicatorReturn {\n isTyping: boolean;\n typingUsers: string[];\n}\n\nexport function useTypingIndicator(websocket: UseWebSocketReturn): UseTypingIndicatorReturn {\n const [typingUsers, setTypingUsers] = useState<string[]>([]);\n\n useEffect(() => {\n if (websocket.lastMessage?.type === 'typing' && websocket.lastMessage.data) {\n const { userId, isTyping } = websocket.lastMessage.data;\n\n if (isTyping) {\n setTypingUsers((prev) => {\n if (!prev.includes(userId)) {\n return [...prev, userId];\n }\n return prev;\n });\n } else {\n setTypingUsers((prev) => prev.filter((id) => id !== userId));\n }\n }\n }, [websocket.lastMessage]);\n\n return {\n isTyping: typingUsers.length > 0,\n typingUsers,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type ResizeEdge = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\ninterface UseResizableWidgetOptions {\n initialWidth?: number;\n initialHeight?: number;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n storageKey?: string;\n enabled?: boolean;\n}\n\nexport interface UseResizableWidgetReturn {\n width: number;\n height: number;\n isResizing: boolean;\n /** Attach to the widget container for edge/corner resize zones */\n containerResizeProps: {\n onMouseMove: (e: React.MouseEvent) => void;\n onMouseDown: (e: React.MouseEvent) => void;\n onMouseLeave: (e: React.MouseEvent) => void;\n onTouchStart: (e: React.TouchEvent) => void;\n };\n /** True when user hovers near a resize edge — use for visual hint */\n isNearEdge: boolean;\n /** Which edge/corner the user is near or dragging */\n activeEdge: ResizeEdge | null;\n}\n\nconst STORAGE_KEY = 'xcelsior-chat-size';\nconst EDGE_ZONE = 8; // px from edge to trigger resize cursor\n\nconst CURSOR_MAP: Record<ResizeEdge, string> = {\n n: 'ns-resize',\n s: 'ns-resize',\n e: 'ew-resize',\n w: 'ew-resize',\n ne: 'nesw-resize',\n nw: 'nwse-resize',\n se: 'nwse-resize',\n sw: 'nesw-resize',\n};\n\nfunction readStoredSize(\n key: string,\n fallbackWidth: number,\n fallbackHeight: number,\n): { width: number; height: number } {\n try {\n const stored = localStorage.getItem(key);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed.width === 'number' && typeof parsed.height === 'number') {\n return { width: parsed.width, height: parsed.height };\n }\n }\n } catch {\n // localStorage unavailable\n }\n return { width: fallbackWidth, height: fallbackHeight };\n}\n\nfunction persistSize(key: string, width: number, height: number) {\n try {\n localStorage.setItem(key, JSON.stringify({ width, height }));\n } catch {\n // Storage unavailable\n }\n}\n\nfunction isMobile(): boolean {\n return typeof window !== 'undefined' && window.innerWidth < 768;\n}\n\n/** Detect which edge/corner the mouse is near */\nfunction detectEdge(\n e: { clientX: number; clientY: number },\n rect: DOMRect,\n): ResizeEdge | null {\n const { clientX: x, clientY: y } = e;\n const nearTop = y - rect.top < EDGE_ZONE;\n const nearBottom = rect.bottom - y < EDGE_ZONE;\n const nearLeft = x - rect.left < EDGE_ZONE;\n const nearRight = rect.right - x < EDGE_ZONE;\n\n if (nearTop && nearLeft) return 'nw';\n if (nearTop && nearRight) return 'ne';\n if (nearBottom && nearLeft) return 'sw';\n if (nearBottom && nearRight) return 'se';\n if (nearTop) return 'n';\n if (nearBottom) return 's';\n if (nearLeft) return 'w';\n if (nearRight) return 'e';\n return null;\n}\n\nexport function useResizableWidget({\n initialWidth = 380,\n initialHeight = 580,\n minWidth = 320,\n minHeight = 400,\n maxWidth = 800,\n maxHeight = 900,\n storageKey = STORAGE_KEY,\n enabled = true,\n}: UseResizableWidgetOptions = {}): UseResizableWidgetReturn {\n const [size, setSize] = useState<{ width: number; height: number }>(() => {\n if (typeof window === 'undefined') return { width: initialWidth, height: initialHeight };\n return readStoredSize(storageKey, initialWidth, initialHeight);\n });\n const [isResizing, setIsResizing] = useState(false);\n const [isNearEdge, setIsNearEdge] = useState(false);\n const [activeEdge, setActiveEdge] = useState<ResizeEdge | null>(null);\n\n const sizeRef = useRef(size);\n sizeRef.current = size;\n\n const dragRef = useRef<{\n edge: ResizeEdge;\n startX: number;\n startY: number;\n startWidth: number;\n startHeight: number;\n } | null>(null);\n\n const containerRef = useRef<HTMLElement | null>(null);\n\n const clamp = useCallback(\n (w: number, h: number) => {\n const mxW = Math.min(maxWidth, window.innerWidth - 24);\n const mxH = Math.min(maxHeight, window.innerHeight - 100);\n return {\n width: Math.round(Math.max(minWidth, Math.min(mxW, w))),\n height: Math.round(Math.max(minHeight, Math.min(mxH, h))),\n };\n },\n [minWidth, minHeight, maxWidth, maxHeight],\n );\n\n /** Calculate new size from drag delta based on which edge is being dragged */\n const calcSize = useCallback(\n (dx: number, dy: number) => {\n if (!dragRef.current) return sizeRef.current;\n const { edge, startWidth, startHeight } = dragRef.current;\n\n let w = startWidth;\n let h = startHeight;\n\n // Horizontal: east edges expand right, west edges expand left (invert delta)\n if (edge.includes('e')) w = startWidth + dx;\n if (edge.includes('w')) w = startWidth - dx;\n\n // Vertical: south edges expand down, north edges expand up (invert delta)\n if (edge.includes('s')) h = startHeight + dy;\n if (edge.includes('n')) h = startHeight - dy;\n\n return clamp(w, h);\n },\n [clamp],\n );\n\n // ─── Mouse handlers ──────────────────────────────────────────────────\n\n const handleDocMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n setSize(calcSize(dx, dy));\n },\n [calcSize],\n );\n\n const handleDocMouseUp = useCallback(\n (e: MouseEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n const final = calcSize(dx, dy);\n persistSize(storageKey, final.width, final.height);\n dragRef.current = null;\n setIsResizing(false);\n setActiveEdge(null);\n document.body.style.cursor = '';\n document.removeEventListener('mousemove', handleDocMouseMove);\n document.removeEventListener('mouseup', handleDocMouseUp);\n },\n [calcSize, storageKey, handleDocMouseMove],\n );\n\n // ─── Touch handlers ──────────────────────────────────────────────────\n\n const handleDocTouchMove = useCallback(\n (e: TouchEvent) => {\n if (!dragRef.current || e.touches.length === 0) return;\n e.preventDefault();\n const t = e.touches[0];\n const dx = t.clientX - dragRef.current.startX;\n const dy = t.clientY - dragRef.current.startY;\n setSize(calcSize(dx, dy));\n },\n [calcSize],\n );\n\n const handleDocTouchEnd = useCallback(\n (e: TouchEvent) => {\n if (!dragRef.current) return;\n const t = e.changedTouches[0];\n if (t) {\n const dx = t.clientX - dragRef.current.startX;\n const dy = t.clientY - dragRef.current.startY;\n const final = calcSize(dx, dy);\n persistSize(storageKey, final.width, final.height);\n }\n dragRef.current = null;\n setIsResizing(false);\n setActiveEdge(null);\n document.removeEventListener('touchmove', handleDocTouchMove);\n document.removeEventListener('touchend', handleDocTouchEnd);\n },\n [calcSize, storageKey, handleDocTouchMove],\n );\n\n // ─── Cleanup ─────────────────────────────────────────────────────────\n\n useEffect(() => {\n return () => {\n document.removeEventListener('mousemove', handleDocMouseMove);\n document.removeEventListener('mouseup', handleDocMouseUp);\n document.removeEventListener('touchmove', handleDocTouchMove);\n document.removeEventListener('touchend', handleDocTouchEnd);\n document.body.style.cursor = '';\n };\n }, [handleDocMouseMove, handleDocMouseUp, handleDocTouchMove, handleDocTouchEnd]);\n\n // ─── Container event props ───────────────────────────────────────────\n\n const onContainerMouseMove = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled || isMobile() || isResizing) return;\n const el = e.currentTarget as HTMLElement;\n containerRef.current = el;\n const rect = el.getBoundingClientRect();\n const edge = detectEdge(e, rect);\n setIsNearEdge(!!edge);\n setActiveEdge(edge);\n el.style.cursor = edge ? CURSOR_MAP[edge] : '';\n },\n [enabled, isResizing],\n );\n\n const onContainerMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled || isMobile() || !activeEdge) return;\n // Only start resize if near an edge\n e.preventDefault();\n e.stopPropagation();\n dragRef.current = {\n edge: activeEdge,\n startX: e.clientX,\n startY: e.clientY,\n startWidth: sizeRef.current.width,\n startHeight: sizeRef.current.height,\n };\n setIsResizing(true);\n document.body.style.cursor = CURSOR_MAP[activeEdge];\n document.addEventListener('mousemove', handleDocMouseMove);\n document.addEventListener('mouseup', handleDocMouseUp);\n },\n [enabled, activeEdge, handleDocMouseMove, handleDocMouseUp],\n );\n\n const onContainerMouseLeave = useCallback(\n (_e: React.MouseEvent) => {\n if (!isResizing) {\n setIsNearEdge(false);\n setActiveEdge(null);\n if (containerRef.current) containerRef.current.style.cursor = '';\n }\n },\n [isResizing],\n );\n\n const onContainerTouchStart = useCallback(\n (e: React.TouchEvent) => {\n if (!enabled || isMobile() || e.touches.length === 0) return;\n const el = e.currentTarget as HTMLElement;\n const rect = el.getBoundingClientRect();\n const t = e.touches[0];\n const edge = detectEdge(t, rect);\n if (!edge) return;\n\n dragRef.current = {\n edge,\n startX: t.clientX,\n startY: t.clientY,\n startWidth: sizeRef.current.width,\n startHeight: sizeRef.current.height,\n };\n setIsResizing(true);\n setActiveEdge(edge);\n document.addEventListener('touchmove', handleDocTouchMove, { passive: false });\n document.addEventListener('touchend', handleDocTouchEnd);\n },\n [enabled, handleDocTouchMove, handleDocTouchEnd],\n );\n\n return {\n width: size.width,\n height: size.height,\n isResizing,\n isNearEdge,\n activeEdge,\n containerResizeProps: {\n onMouseMove: onContainerMouseMove,\n onMouseDown: onContainerMouseDown,\n onMouseLeave: onContainerMouseLeave,\n onTouchStart: onContainerTouchStart,\n },\n };\n}\n","import type { CSSProperties } from 'react';\n\ninterface BrandIconProps {\n size?: number;\n color?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Xcelsior \"X\" symbol mark (from favicon-brand.svg)\n * Reusable across the chat widget — FAB button, avatar, header, etc.\n */\nexport function XcelsiorSymbol({ size = 24, color = 'white', className = '', style }: BrandIconProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n style={style}\n aria-hidden=\"true\"\n >\n <path\n d=\"M20.582 15.027L31.849 0.036H24.808L17.039 10.303L20.582 15.027ZM24.808 31.837H31.849L20.582 16.846L17.039 21.57L24.808 31.837Z\"\n fill={color}\n />\n <path\n d=\"M14.313 15.027H18.402L7.135 0.036H0.185L9.406 12.392C10.587 13.983 12.359 15.027 14.313 15.027Z\"\n fill={color}\n />\n <path\n d=\"M0.185 31.837H7.135L18.402 16.846H14.313C12.359 16.846 10.588 17.891 9.406 19.481L0.185 31.837Z\"\n fill={color}\n />\n </svg>\n );\n}\n\n/**\n * Chat bubble icon for the FAB launcher button.\n * Instantly recognizable as a chat trigger.\n */\nexport function ChatBubbleIcon({ size = 28, color = 'white', className = '', style }: BrandIconProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={color}\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n style={style}\n aria-hidden=\"true\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n/**\n * Xcelsior \"X\" avatar — symbol inside a gradient circle\n * Used as bot avatar in messages and chat header\n */\nexport function XcelsiorAvatar({ size = 40, className = '' }: { size?: number; className?: string }) {\n const iconSize = Math.round(size * 0.55);\n return (\n <div\n className={`flex items-center justify-center rounded-full ${className}`}\n style={{\n width: size,\n height: size,\n background: 'linear-gradient(135deg, #337eff, #005eff)',\n }}\n >\n <XcelsiorSymbol size={iconSize} color=\"white\" />\n </div>\n );\n}\n","import type { IChatTheme, IUser } from '../types';\nimport { XcelsiorSymbol } from './BrandIcons';\n\ninterface ChatHeaderProps {\n agent?: IUser;\n onClose?: () => void;\n onMinimize?: () => void;\n theme?: IChatTheme;\n}\n\nexport function ChatHeader({ agent, onClose, onMinimize, theme }: ChatHeaderProps) {\n return (\n <div\n className=\"relative text-white overflow-hidden\"\n style={{\n flexShrink: 0,\n /* Layered blue smoke/glow effect for premium look */\n background: [\n 'radial-gradient(ellipse at 30% 50%, rgba(0,50,255,0.4) 0%, transparent 60%)',\n 'radial-gradient(ellipse at 70% 30%, rgba(0,80,255,0.3) 0%, transparent 50%)',\n 'radial-gradient(ellipse at 50% 80%, rgba(0,30,200,0.3) 0%, transparent 60%)',\n `linear-gradient(135deg, #0030cc 0%, #001a66 50%, #000d33 100%)`,\n ].join(', '),\n }}\n >\n {/* Top glass highlight — subtle light sweep for depth */}\n <div\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n background:\n 'linear-gradient(180deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 50%)',\n }}\n />\n\n <div className=\"flex items-center justify-between\" style={{ padding: '8px 16px' }}>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n {agent?.avatar ? (\n <img\n src={agent.avatar}\n alt={agent.name}\n className=\"h-10 w-10 rounded-full object-cover\"\n style={{\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n }}\n />\n ) : (\n <div style={{ filter: 'drop-shadow(0 2px 8px rgba(0,0,0,0.3))' }}>\n <XcelsiorSymbol size={28} color=\"white\" />\n </div>\n )}\n {agent?.status === 'online' && (\n <div\n className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full\"\n style={{\n backgroundColor: theme?.statusPositive || '#1ed473',\n border: '2.5px solid rgba(0,50,180,0.9)',\n boxShadow: `0 0 8px ${theme?.statusPositive || '#1ed473'}80`,\n }}\n />\n )}\n </div>\n <div>\n <h3\n className=\"font-semibold leading-tight\"\n style={{\n fontSize: '15px',\n letterSpacing: '-0.01em',\n }}\n >\n {agent?.name || 'Xcelsior Software'}\n </h3>\n <p\n className=\"mt-0.5 leading-tight\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: 'rgba(255,255,255,0.6)',\n }}\n >\n {agent?.status === 'online' ? (\n <span className=\"flex items-center gap-1.5\">\n <span\n className=\"inline-block w-1.5 h-1.5 rounded-full\"\n style={{\n backgroundColor: theme?.statusPositive || '#1ed473',\n boxShadow: `0 0 4px ${theme?.statusPositive || '#1ed473'}60`,\n }}\n />\n Online now\n </span>\n ) : agent?.status === 'away' ? (\n 'Away'\n ) : (\n 'We typically reply within minutes'\n )}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-0.5\">\n {/* Single minimize button — always minimizes back to FAB bubble */}\n {(onMinimize || onClose) && (\n <button\n type=\"button\"\n onClick={onMinimize || onClose}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Minimize chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {/* Bottom edge — subtle gradient line (matches website section dividers) */}\n <div\n className=\"h-px\"\n style={{\n background:\n 'linear-gradient(90deg, transparent 5%, rgba(255,255,255,0.12) 30%, rgba(255,255,255,0.12) 70%, transparent 95%)',\n }}\n />\n </div>\n );\n}\n","import { useCallback, useEffect, useRef } from 'react';\n\nimport { Spinner } from './Spinner';\n\nimport { XcelsiorAvatar, XcelsiorSymbol } from './BrandIcons';\nimport { MessageItem } from './MessageItem';\nimport { ThinkingIndicator } from './ThinkingIndicator';\n\nimport type { IMessage, IUser, IChatTheme } from '../types';\n\ninterface MessageListProps {\n messages: IMessage[];\n currentUser: IUser;\n isLoading?: boolean;\n isTyping?: boolean;\n typingUser?: string;\n autoScroll?: boolean;\n onLoadMore?: () => void;\n hasMore?: boolean;\n isLoadingMore?: boolean;\n theme?: IChatTheme;\n /** Called when a quick-start action button is clicked — sends the text as a message */\n onQuickAction?: (text: string) => void;\n /** True when user sent a message and bot response hasn't arrived yet */\n isBotThinking?: boolean;\n}\n\nexport function MessageList({\n messages,\n currentUser,\n isLoading = false,\n isTyping = false,\n typingUser,\n autoScroll = true,\n onLoadMore,\n hasMore = false,\n isLoadingMore = false,\n theme,\n onQuickAction,\n isBotThinking = false,\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n const loadMoreTriggerRef = useRef<HTMLDivElement>(null);\n const prevScrollHeightRef = useRef(0);\n const hasInitialScrolledRef = useRef(false);\n const isUserScrollingRef = useRef(false);\n\n const bgColor = theme?.background || '#00001a';\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n const primaryColor = theme?.primary || '#337eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (autoScroll && messagesEndRef.current) {\n if (messages.length > prevLengthRef.current && !isLoadingMore) {\n messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });\n }\n prevLengthRef.current = messages.length;\n }\n }, [messages.length, autoScroll, isLoadingMore]);\n\n // Initial scroll to bottom when messages first load\n useEffect(() => {\n if (\n messages.length > 0 &&\n messagesEndRef.current &&\n !isLoading &&\n !hasInitialScrolledRef.current\n ) {\n setTimeout(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'auto' });\n setTimeout(() => {\n isUserScrollingRef.current = true;\n }, 200);\n }, 100);\n hasInitialScrolledRef.current = true;\n } else if (!isLoading && messages.length === 0 && !hasInitialScrolledRef.current) {\n isUserScrollingRef.current = true;\n hasInitialScrolledRef.current = true;\n }\n }, [isLoading, messages.length]);\n\n // Restore scroll position after loading more messages\n useEffect(() => {\n if (isLoadingMore) {\n prevScrollHeightRef.current = containerRef.current?.scrollHeight || 0;\n } else if (prevScrollHeightRef.current > 0 && containerRef.current) {\n const newScrollHeight = containerRef.current.scrollHeight;\n const scrollDiff = newScrollHeight - prevScrollHeightRef.current;\n containerRef.current.scrollTop = scrollDiff;\n prevScrollHeightRef.current = 0;\n }\n }, [isLoadingMore]);\n\n // Infinite scroll: detect when user scrolls near the top\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !onLoadMore || !hasMore || isLoadingMore) return;\n if (!isUserScrollingRef.current) return;\n\n const { scrollTop } = containerRef.current;\n if (scrollTop < 100) {\n onLoadMore();\n }\n }, [onLoadMore, hasMore, isLoadingMore]);\n\n // Set up scroll event listener\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n // Empty state — premium, minimal, matching Xcelsior website feel\n if (messages.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center\" style={{ padding: '40px 32px' }}>\n <h3\n className=\"font-semibold mb-2\"\n style={{\n color: textColor,\n fontSize: '17px',\n letterSpacing: '-0.01em',\n }}\n >\n How can we help?\n </h3>\n <p\n className=\"max-w-[240px]\"\n style={{\n color: textMuted,\n fontSize: '13px',\n lineHeight: '1.5',\n letterSpacing: '0.015em',\n marginBottom: 20,\n }}\n >\n Ask us anything. We are here to help you get the most out of Xcelsior.\n </p>\n\n {/* Quick-start action buttons */}\n <div className=\"flex flex-wrap justify-center gap-2\">\n {[\n { label: 'Our services', message: 'What services does Xcelsior offer?' },\n { label: 'Get a quote', message: 'I would like to get a quote for a project' },\n { label: 'Support', message: 'I need help with something' },\n ].map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={() => onQuickAction?.(action.message)}\n style={{\n padding: '6px 14px',\n borderRadius: '999px',\n cursor: 'pointer',\n transition: 'all 150ms ease',\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n border: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.1)',\n color: isLightTheme\n ? 'rgba(0,0,0,0.6)'\n : 'rgba(247,247,248,0.6)',\n fontSize: '12px',\n letterSpacing: '0.015em',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme\n ? 'rgba(0,0,0,0.08)'\n : 'rgba(255,255,255,0.08)';\n e.currentTarget.style.color = isLightTheme\n ? 'rgba(0,0,0,0.8)'\n : 'rgba(247,247,248,0.8)';\n e.currentTarget.style.borderColor = primaryColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)';\n e.currentTarget.style.color = isLightTheme\n ? 'rgba(0,0,0,0.6)'\n : 'rgba(247,247,248,0.6)';\n e.currentTarget.style.borderColor = isLightTheme\n ? 'rgba(0,0,0,0.1)'\n : 'rgba(255,255,255,0.1)';\n }}\n >\n {action.label}\n </button>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 overflow-y-auto px-4 py-3\"\n style={{ scrollBehavior: 'smooth' }}\n >\n <style>{`\n @keyframes thinkingPulse {\n 0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); }\n 30% { opacity: 1; transform: scale(1); }\n }\n @keyframes cursorBlink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0; }\n }\n `}</style>\n {/* Loading indicator at the top for infinite scroll */}\n {isLoadingMore && (\n <div className=\"flex justify-center py-3\">\n <Spinner size=\"sm\" />\n </div>\n )}\n\n {/* Load more trigger point */}\n <div ref={loadMoreTriggerRef} />\n\n {messages.map((message) => (\n <MessageItem\n key={message.id}\n message={message}\n currentUser={currentUser}\n showAvatar={true}\n showTimestamp={true}\n theme={theme}\n />\n ))}\n\n {/* Typing indicator — matching bot message bubble style */}\n {isTyping && (\n <div className=\"flex gap-2.5 mb-3\">\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n <XcelsiorAvatar size={28} />\n </div>\n <div className=\"flex flex-col items-start\">\n <div\n className=\"px-4 py-3\"\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n borderRadius: '18px 18px 18px 4px',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n }}\n >\n <div className=\"flex gap-1.5 items-center\" style={{ height: 16 }}>\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"rounded-full animate-bounce\"\n style={{\n width: 5,\n height: 5,\n backgroundColor: `${primaryColor}80`,\n animationDelay: `${i * 0.15}s`,\n animationDuration: '0.8s',\n }}\n />\n ))}\n </div>\n </div>\n {typingUser && (\n <span\n className=\"mt-1 px-1\"\n style={{\n color: textMuted,\n fontSize: '11px',\n letterSpacing: '0.019em',\n }}\n >\n {typingUser} is typing...\n </span>\n )}\n </div>\n </div>\n )}\n\n {/* Bot thinking indicator — Claude-like typewriter with rotating phrases */}\n {isBotThinking && !isTyping && (\n <ThinkingIndicator\n theme={theme}\n lastUserMessage={messages.filter((m) => m.senderType === 'customer').pop()?.content}\n />\n )}\n\n <div ref={messagesEndRef} />\n </div>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: 'sm' | 'md' | 'lg';\n color?: string;\n}\n\nconst SIZE_MAP: Record<NonNullable<SpinnerProps['size']>, number> = {\n sm: 16,\n md: 24,\n lg: 36,\n};\n\nconst BORDER_MAP: Record<NonNullable<SpinnerProps['size']>, number> = {\n sm: 2,\n md: 2,\n lg: 3,\n};\n\nexport function Spinner({ size = 'md', color = 'currentColor' }: SpinnerProps) {\n const px = SIZE_MAP[size];\n const border = BORDER_MAP[size];\n\n return (\n <>\n <style>{`\n @keyframes xchat-spin {\n to { transform: rotate(360deg); }\n }\n .xchat-spinner {\n animation: xchat-spin 0.75s linear infinite;\n border-radius: 50%;\n display: inline-block;\n flex-shrink: 0;\n }\n `}</style>\n <span\n className=\"xchat-spinner\"\n role=\"status\"\n aria-label=\"Loading\"\n style={{\n width: px,\n height: px,\n border: `${border}px solid rgba(128,128,128,0.25)`,\n borderTopColor: color,\n }}\n />\n </>\n );\n}\n","import { formatDistanceToNow } from 'date-fns';\nimport type { IMessage, IUser, IChatTheme } from '../types';\nimport { XcelsiorAvatar } from './BrandIcons';\nimport { MarkdownMessage } from './MarkdownMessage';\n\ninterface MessageItemProps {\n message: IMessage;\n currentUser: IUser;\n showAvatar?: boolean;\n showTimestamp?: boolean;\n theme?: IChatTheme;\n}\n\nexport function MessageItem({\n message,\n currentUser,\n showAvatar = true,\n showTimestamp = true,\n theme,\n}: MessageItemProps) {\n const isOwnMessage = message.senderType === currentUser.type;\n const isSystemMessage = message.senderType === 'system';\n const isAIMessage = message.metadata?.isAI === true;\n const isBotMessage = message.senderType === 'bot';\n\n const bgColor = theme?.background || '#00001a';\n const isLightTheme = (() => {\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n })();\n\n const primaryColor = theme?.primary || '#337eff';\n const primaryStrong = theme?.primaryStrong || '#005eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.35)' : 'rgba(247,247,248,0.35)');\n\n // System messages — centered pill with ultra-subtle surface\n if (isSystemMessage) {\n return (\n <div className=\"flex justify-center my-3\">\n <div\n className=\"px-4 py-1.5 rounded-full\"\n style={{\n backgroundColor: isLightTheme ? 'rgba(0,0,0,0.04)' : 'rgba(255,255,255,0.03)',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n }}\n >\n <p\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n {message.content}\n </p>\n </div>\n </div>\n );\n }\n\n // Determine label for non-customer messages\n const getSenderLabel = () => {\n if (isBotMessage || isAIMessage) return 'AI Assistant';\n if (message.senderType === 'agent') {\n return (message.metadata?.agentName as string) || 'Support Agent';\n }\n return null;\n };\n\n const senderLabel = !isOwnMessage ? getSenderLabel() : null;\n\n // Own message: blue gradient pill (matches website primary CTA)\n const ownBubbleStyle: React.CSSProperties = {\n background: `linear-gradient(135deg, ${primaryColor}, ${primaryStrong})`,\n color: '#ffffff',\n borderRadius: '18px 18px 4px 18px',\n boxShadow: `0 2px 12px -3px ${primaryColor}40`,\n };\n\n // Other message: surface with subtle inset border (adapts to theme)\n const otherBubbleStyle: React.CSSProperties = isLightTheme\n ? {\n backgroundColor: 'rgba(0,0,0,0.04)',\n color: textColor,\n borderRadius: '18px 18px 18px 4px',\n boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.06)',\n }\n : {\n backgroundColor: 'rgba(255,255,255,0.04)',\n color: textColor,\n borderRadius: '18px 18px 18px 4px',\n boxShadow:\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n };\n\n return (\n <div\n className={`flex gap-2.5 mb-3 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n {/* Avatar */}\n {showAvatar && !isOwnMessage && (\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n {isBotMessage || isAIMessage ? (\n <XcelsiorAvatar size={28} />\n ) : (\n <div\n className=\"h-7 w-7 rounded-full flex items-center justify-center\"\n style={{\n background: isLightTheme\n ? `linear-gradient(135deg, ${primaryColor}30, rgba(0,0,0,0.04))`\n : `linear-gradient(135deg, ${primaryColor}60, rgba(255,255,255,0.06))`,\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.08)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.1)',\n }}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={isLightTheme ? primaryColor : 'white'}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Agent</title>\n <path d=\"M3 18v-6a9 9 0 0 1 18 0v6\" />\n <path d=\"M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z\" />\n </svg>\n </div>\n )}\n </div>\n )}\n\n {/* Spacer for own messages to maintain alignment */}\n {showAvatar && isOwnMessage && <div className=\"w-7 flex-shrink-0\" />}\n\n <div\n className={`flex flex-col max-w-[75%] ${isOwnMessage ? 'items-end' : 'items-start'}`}\n >\n {/* Sender label */}\n {senderLabel && (\n <span\n className=\"mb-1 px-1 font-medium\"\n style={{\n color: isLightTheme ? 'rgba(0,0,0,0.45)' : 'rgba(247,247,248,0.4)',\n fontSize: '11px',\n letterSpacing: '0.019em',\n }}\n >\n {senderLabel}\n </span>\n )}\n\n {/* Message bubble */}\n <div\n className=\"px-4 py-2.5\"\n style={{\n ...( isOwnMessage ? ownBubbleStyle : otherBubbleStyle ),\n fontSize: '14px',\n lineHeight: '1.5',\n letterSpacing: '0.006em',\n }}\n >\n {message.messageType === 'text' && (\n isOwnMessage ? (\n // User messages: plain text — no markdown parsing\n <span style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>\n {message.content}\n </span>\n ) : (\n // Bot / agent messages: full markdown rendering\n <MarkdownMessage content={message.content} theme={theme} />\n )\n )}\n {message.messageType === 'image' && (\n <div>\n <img\n src={message.content}\n alt=\"Attachment\"\n className=\"max-w-full h-auto rounded-lg\"\n loading=\"lazy\"\n />\n </div>\n )}\n {message.messageType === 'file' && (\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>File</title>\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\" />\n </svg>\n <a\n href={message.content}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n color: isOwnMessage\n ? 'rgba(255,255,255,0.85)'\n : primaryColor,\n textDecoration: 'underline',\n textUnderlineOffset: '2px',\n }}\n >\n {(message.metadata?.fileName as any) || 'Download file'}\n </a>\n </div>\n )}\n </div>\n\n {/* Timestamp + status */}\n {showTimestamp && (\n <div\n className={`flex items-center gap-1.5 mt-1 px-1 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n <span\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n {formatDistanceToNow(new Date(message.createdAt), {\n addSuffix: true,\n })}\n </span>\n {isOwnMessage && message.status && (\n <span style={{ color: textMuted }}>\n {message.status === 'sent' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Sent</title>\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n {message.status === 'delivered' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Delivered</title>\n <polyline points=\"18 6 7 17 2 12\" />\n <polyline points=\"22 6 11 17\" />\n </svg>\n )}\n {message.status === 'read' && (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={primaryColor}\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Read</title>\n <polyline points=\"18 6 7 17 2 12\" />\n <polyline points=\"22 6 11 17\" />\n </svg>\n )}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport type { Components } from 'react-markdown';\nimport type { IChatTheme } from '../types';\nimport { getMarkdownStyles } from '../utils/markdown-styles';\n\ninterface MarkdownMessageProps {\n content: string;\n theme?: IChatTheme;\n}\n\nfunction computeIsLightTheme(theme?: IChatTheme): boolean {\n const bgColor = theme?.background || '#00001a';\n if (!bgColor.startsWith('#')) return false;\n const hex = bgColor.replace('#', '');\n if (hex.length < 6) return false;\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\nexport function MarkdownMessage({ content, theme }: MarkdownMessageProps) {\n const isLightTheme = computeIsLightTheme(theme);\n const styles = getMarkdownStyles(theme, isLightTheme);\n\n // Last paragraph in a message should have no bottom margin to avoid\n // extra space at the bottom of the bubble. We track last child via\n // a wrapper + CSS last-child, but since we use inline styles we\n // strip the margin in the paragraph renderer if the node is the last\n // element. react-markdown does not expose \"is last sibling\" easily,\n // so we use a simple wrapper approach: strip bottom margin on the\n // outermost container's last child by keeping the container style tight\n // and letting natural flow handle it.\n\n const wrapperStyle: CSSProperties = {\n // Collapse bottom margin of the last child to avoid extra padding\n // inside the bubble.\n display: 'block',\n };\n\n return (\n <div style={wrapperStyle}>\n <ReactMarkdown\n components={{\n // Paragraphs\n p: ({ children }) => (\n <p style={styles.paragraph}>{children}</p>\n ),\n\n // Bold\n strong: ({ children }) => (\n <strong style={styles.strong}>{children}</strong>\n ),\n\n // Italic\n em: ({ children }) => (\n <em style={styles.emphasis}>{children}</em>\n ),\n\n // Links — open in new tab\n a: ({ href, children }) => (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={styles.link}\n >\n {children}\n </a>\n ),\n\n // Unordered list\n ul: ({ children }) => (\n <ul style={{ ...styles.list, listStyleType: 'disc' }}>\n {children}\n </ul>\n ),\n\n // Ordered list\n ol: ({ children }) => (\n <ol\n style={{ ...styles.list, listStyleType: 'decimal' }}\n >\n {children}\n </ol>\n ),\n\n // List item\n li: ({ children }) => (\n <li style={styles.listItem}>{children}</li>\n ),\n\n // Inline code vs code block — react-markdown wraps fenced\n // code blocks as <pre><code className=\"language-*\">. The\n // cleanest heuristic: if the className starts with\n // \"language-\" it is a fenced block; otherwise it's inline.\n code: (({ children, className }) => {\n const isBlock = Boolean(\n className?.startsWith('language-'),\n );\n if (isBlock) {\n return (\n <code\n className={className}\n style={styles.codeBlock}\n >\n {children}\n </code>\n );\n }\n return <code style={styles.code}>{children}</code>;\n }) as Components['code'],\n\n // Pre wrapper for code blocks\n pre: ({ children }) => (\n <pre\n style={{\n margin: '8px 0',\n padding: 0,\n backgroundColor: 'transparent',\n border: 'none',\n overflow: 'visible',\n }}\n >\n {children}\n </pre>\n ),\n\n // Headings — h1 through h6 with progressive size reduction\n h1: ({ children }) => (\n <h1\n style={{\n ...styles.heading,\n fontSize: '1.15em',\n }}\n >\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2\n style={{\n ...styles.heading,\n fontSize: '1.1em',\n }}\n >\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3\n style={{\n ...styles.heading,\n fontSize: '1.05em',\n }}\n >\n {children}\n </h3>\n ),\n h4: ({ children }) => (\n <h4 style={{ ...styles.heading, fontSize: '1em' }}>\n {children}\n </h4>\n ),\n h5: ({ children }) => (\n <h5\n style={{\n ...styles.heading,\n fontSize: '0.95em',\n }}\n >\n {children}\n </h5>\n ),\n h6: ({ children }) => (\n <h6\n style={{\n ...styles.heading,\n fontSize: '0.9em',\n }}\n >\n {children}\n </h6>\n ),\n\n // Blockquote\n blockquote: ({ children }) => (\n <blockquote style={styles.blockquote}>\n {children}\n </blockquote>\n ),\n\n // Horizontal rule\n hr: () => <hr style={styles.hr} />,\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\nimport type { IChatTheme } from '../types';\n\nexport interface MarkdownStyles {\n paragraph: CSSProperties;\n strong: CSSProperties;\n emphasis: CSSProperties;\n link: CSSProperties;\n list: CSSProperties;\n listItem: CSSProperties;\n code: CSSProperties;\n codeBlock: CSSProperties;\n heading: CSSProperties;\n blockquote: CSSProperties;\n hr: CSSProperties;\n}\n\nexport function getMarkdownStyles(\n theme?: IChatTheme,\n isLightTheme?: boolean,\n): MarkdownStyles {\n const primaryColor = theme?.primary || '#337eff';\n const textColor = theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n\n // Slightly brightened text for strong elements\n const strongColor = isLightTheme\n ? 'rgba(0,0,0,0.9)'\n : 'rgba(255,255,255,0.95)';\n\n // Subtle background for inline code\n const inlineCodeBg = isLightTheme\n ? 'rgba(0,0,0,0.06)'\n : 'rgba(255,255,255,0.08)';\n\n // Darker background for code blocks\n const codeBlockBg = isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(0,0,0,0.25)';\n\n const codeBlockBorder = isLightTheme\n ? '1px solid rgba(0,0,0,0.08)'\n : '1px solid rgba(255,255,255,0.06)';\n\n const blockquoteBorder = isLightTheme\n ? `3px solid ${primaryColor}60`\n : `3px solid ${primaryColor}80`;\n\n const blockquoteBg = isLightTheme\n ? 'rgba(0,0,0,0.02)'\n : 'rgba(255,255,255,0.02)';\n\n return {\n paragraph: {\n margin: '0 0 8px 0',\n lineHeight: '1.6',\n color: textColor,\n },\n\n strong: {\n fontWeight: 600,\n color: strongColor,\n },\n\n emphasis: {\n fontStyle: 'italic',\n color: textColor,\n },\n\n link: {\n color: primaryColor,\n textDecoration: 'underline',\n textUnderlineOffset: '2px',\n cursor: 'pointer',\n },\n\n list: {\n paddingLeft: '20px',\n margin: '8px 0',\n color: textColor,\n },\n\n listItem: {\n margin: '4px 0',\n lineHeight: '1.5',\n color: textColor,\n },\n\n code: {\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n fontSize: '0.875em',\n backgroundColor: inlineCodeBg,\n padding: '2px 6px',\n borderRadius: '4px',\n color: textColor,\n },\n\n codeBlock: {\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n fontSize: '0.8125em',\n backgroundColor: codeBlockBg,\n border: codeBlockBorder,\n padding: '12px',\n borderRadius: '8px',\n overflowX: 'auto',\n margin: '8px 0',\n color: textColor,\n lineHeight: '1.5',\n display: 'block',\n whiteSpace: 'pre',\n },\n\n heading: {\n fontWeight: 600,\n marginTop: '12px',\n marginBottom: '6px',\n color: strongColor,\n lineHeight: '1.3',\n },\n\n blockquote: {\n borderLeft: blockquoteBorder,\n backgroundColor: blockquoteBg,\n margin: '8px 0',\n padding: '6px 12px',\n borderRadius: '0 4px 4px 0',\n color: textColor,\n fontStyle: 'italic',\n },\n\n hr: {\n border: 'none',\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.08)',\n margin: '12px 0',\n },\n };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { XcelsiorAvatar } from './BrandIcons';\nimport type { IChatTheme } from '../types';\n\n// ─── Phrase Pools ────────────────────────────────────────────────────────────\n// Each pool is tied to a detected conversation context.\n// Phrases should feel casual, human, and short (≤4 words ideal).\n\nconst PHRASE_POOLS: Record<string, string[]> = {\n // ── Greetings & small talk ──\n greeting: [\n 'Hey there!',\n 'Hello!',\n 'Hi! One moment',\n 'Welcome!',\n 'Nice to meet you',\n ],\n farewell: [\n 'Wrapping up',\n 'One last thing',\n 'Almost done',\n ],\n\n // ── Sales & pricing ──\n pricing: [\n 'Crunching numbers',\n 'Checking our plans',\n 'Let me look into that',\n 'Pulling up pricing',\n 'Running the numbers',\n 'Checking options',\n ],\n quote: [\n 'Putting this together',\n 'Working on your quote',\n 'Gathering the details',\n 'Tailoring this for you',\n ],\n\n // ── Scheduling & booking ──\n booking: [\n 'Checking the calendar',\n 'Finding good times',\n 'Pulling up availability',\n 'Let me check slots',\n ],\n\n // ── Technical questions ──\n technical: [\n 'Diving into the docs',\n 'Interesting question',\n 'Let me look that up',\n 'Checking the specs',\n 'Hmm, good one',\n 'Researching this',\n ],\n code: [\n 'Reading the code',\n 'Checking the repo',\n 'Let me trace that',\n 'Debugging in my head',\n ],\n\n // ── Support & issues ──\n support: [\n 'On it!',\n 'Let me help',\n 'Looking into this',\n 'Checking for you',\n 'I got you',\n 'Investigating',\n ],\n frustrated: [\n 'I hear you',\n 'Let me fix this',\n 'Sorry about that',\n 'Working on it now',\n 'Bear with me',\n ],\n\n // ── Services & capabilities ──\n services: [\n 'Great question',\n 'Let me explain',\n 'Pulling up details',\n 'Good to know you ask',\n ],\n portfolio: [\n 'Checking our work',\n 'Pulling up examples',\n 'Let me show you',\n 'Finding case studies',\n ],\n\n // ── About the company ──\n about: [\n 'Glad you asked!',\n 'Let me tell you',\n 'Good question',\n 'Here we go',\n ],\n\n // ── Comparison & decisions ──\n comparison: [\n 'Weighing the options',\n 'Let me compare',\n 'Thinking through this',\n 'Good point',\n ],\n\n // ── Follow-up & continuation ──\n followUp: [\n 'Let me dig deeper',\n 'More details coming',\n 'Building on that',\n 'Expanding on this',\n ],\n\n // ── General / fallback ──\n general: [\n 'Hmm, let me think',\n 'One sec',\n 'On it',\n 'Working on it',\n 'Almost there',\n 'Bear with me',\n 'Let me check',\n 'Good question',\n 'Hang tight',\n 'Looking into it',\n 'Let me see',\n 'Thinking',\n 'Just a moment',\n 'Figuring this out',\n ],\n};\n\n// ─── Context Detection ───────────────────────────────────────────────────────\n// Ordered by specificity — first match wins.\n\ninterface ContextRule {\n key: string;\n pattern: RegExp;\n}\n\nconst CONTEXT_RULES: ContextRule[] = [\n // Frustration / urgency (check first — trumps topic)\n { key: 'frustrated', pattern: /frustrat|angry|annoyed|terrible|worst|useless|waste|stupid|wtf|seriously|ridiculous|unacceptable|disappointing/ },\n\n // Greetings (start of message)\n { key: 'greeting', pattern: /^(hi\\b|hey\\b|hello\\b|good morning|good afternoon|good evening|g'day|howdy|yo\\b|sup\\b|what's up|greetings)/ },\n { key: 'farewell', pattern: /\\b(thanks|thank you|bye|goodbye|cheers|that's all|that's it|no more|all good|perfect thanks)\\b/ },\n\n // Booking & scheduling\n { key: 'booking', pattern: /\\b(book|schedule|meeting|appointment|calendar|available time|free slot|set up a call|arrange|consultation time|when can)\\b/ },\n\n // Pricing & quotes\n { key: 'quote', pattern: /\\b(quote|proposal|estimate|project cost|custom price|tailor|bespoke)\\b/ },\n { key: 'pricing', pattern: /\\b(price|cost|how much|pricing|rate|fee|budget|afford|charge|per hour|hourly|package|plan|tier|subscription)\\b/ },\n\n // Technical / code\n { key: 'code', pattern: /\\b(code|github|repo|commit|deploy|ci\\/cd|docker|aws|lambda|api endpoint|sdk|npm|yarn|pnpm|typescript|react|next\\.?js)\\b/ },\n { key: 'technical', pattern: /\\b(api|integrate|integration|stack|server|database|backend|frontend|infrastructure|architecture|performance|scalab|migration|devops|cloud)\\b/ },\n\n // Support & bugs\n { key: 'support', pattern: /\\b(bug|error|issue|broken|not working|help|support|problem|fix|crash|down|fail|stuck|trouble|can't|cannot|doesn't work|won't)\\b/ },\n\n // Services & portfolio\n { key: 'portfolio', pattern: /\\b(portfolio|case stud|example|previous work|client|project you|showcase|demo|sample)\\b/ },\n { key: 'services', pattern: /\\b(service|what do you|what can you|offer|do you do|capabilit|specializ|expertise|solution|consult|develop|design|build|create)\\b/ },\n\n // About company\n { key: 'about', pattern: /\\b(who are|about you|your team|your company|where are you|location|office|founded|history|values|mission)\\b/ },\n\n // Comparison / decision-making\n { key: 'comparison', pattern: /\\b(compare|vs|versus|difference|better|which one|alternative|competitor|pros and cons|trade.?off|should i|recommend)\\b/ },\n\n // Follow-up patterns (vague follow-ups to prior answers)\n { key: 'followUp', pattern: /\\b(more detail|tell me more|elaborate|explain further|what about|and also|another question|one more|can you also|what else|go on)\\b/ },\n];\n\nfunction detectContext(message?: string): string {\n if (!message) return 'general';\n const lower = message.toLowerCase().trim();\n\n for (const rule of CONTEXT_RULES) {\n if (rule.pattern.test(lower)) return rule.key;\n }\n\n // Short messages (1-3 words) that didn't match anything → likely casual\n if (lower.split(/\\s+/).length <= 3) return 'general';\n\n // Questions tend to be exploratory\n if (lower.endsWith('?')) return 'general';\n\n return 'general';\n}\n\n// ─── Shuffle Utility ─────────────────────────────────────────────────────────\n\nfunction getShuffledPhrases(context: string): string[] {\n const pool = PHRASE_POOLS[context] || PHRASE_POOLS.general;\n const contextPhrases = [...pool];\n\n // Mix in 2-3 general phrases for variety (avoid duplicates)\n const extras = PHRASE_POOLS.general\n .filter((p) => !contextPhrases.includes(p))\n .sort(() => Math.random() - 0.5)\n .slice(0, 3);\n\n const combined = [...contextPhrases, ...extras];\n\n // Fisher-Yates shuffle\n for (let i = combined.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [combined[i], combined[j]] = [combined[j], combined[i]];\n }\n return combined;\n}\n\n// ─── Theme Helpers ───────────────────────────────────────────────────────────\n\nfunction computeIsLightTheme(bg?: string): boolean {\n if (!bg?.startsWith('#')) return false;\n const hex = bg.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport interface ThinkingIndicatorProps {\n /** Last message the user sent — used to pick contextual phrases */\n lastUserMessage?: string;\n /** Chat theme for color matching */\n theme?: IChatTheme;\n /** Show avatar next to the indicator */\n showAvatar?: boolean;\n}\n\nexport function ThinkingIndicator({\n lastUserMessage,\n theme,\n showAvatar = true,\n}: ThinkingIndicatorProps) {\n const isLightTheme = computeIsLightTheme(theme?.background);\n const primaryColor = theme?.primary || '#337eff';\n const textMuted = theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n\n const [phraseIndex, setPhraseIndex] = useState(0);\n const [displayText, setDisplayText] = useState('');\n const [isDeleting, setIsDeleting] = useState(false);\n const phrasesRef = useRef<string[]>(getShuffledPhrases(detectContext(lastUserMessage)));\n\n // Re-shuffle when user sends a new message\n useEffect(() => {\n phrasesRef.current = getShuffledPhrases(detectContext(lastUserMessage));\n setPhraseIndex(0);\n setDisplayText('');\n setIsDeleting(false);\n }, [lastUserMessage]);\n\n // Typewriter effect\n useEffect(() => {\n const phrases = phrasesRef.current;\n const phrase = phrases[phraseIndex % phrases.length];\n let timeout: NodeJS.Timeout;\n\n if (!isDeleting) {\n if (displayText.length < phrase.length) {\n // Typing forward — variable speed for natural feel\n timeout = setTimeout(\n () => setDisplayText(phrase.slice(0, displayText.length + 1)),\n 30 + Math.random() * 30,\n );\n } else {\n // Pause at full phrase before deleting\n timeout = setTimeout(() => setIsDeleting(true), 1800);\n }\n } else {\n if (displayText.length > 0) {\n // Deleting — faster than typing\n timeout = setTimeout(\n () => setDisplayText(displayText.slice(0, -1)),\n 18,\n );\n } else {\n // Advance to next phrase\n setIsDeleting(false);\n setPhraseIndex((prev) => (prev + 1) % phrasesRef.current.length);\n }\n }\n\n return () => clearTimeout(timeout);\n }, [displayText, isDeleting, phraseIndex]);\n\n return (\n <div\n className=\"flex gap-2.5 mb-3\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Xcelsior is thinking\"\n >\n {showAvatar && (\n <div className=\"flex-shrink-0 mt-auto mb-5\">\n <XcelsiorAvatar size={28} />\n </div>\n )}\n <div className=\"flex flex-col items-start\">\n <div\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(0,0,0,0.04)'\n : 'rgba(255,255,255,0.04)',\n borderRadius: '18px 18px 18px 4px',\n boxShadow: isLightTheme\n ? 'inset 0 0 0 1px rgba(0,0,0,0.06)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.08)',\n padding: '12px 16px',\n minWidth: 160,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {/* Pulsing dots */}\n <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: 5,\n height: 5,\n borderRadius: '50%',\n backgroundColor: primaryColor,\n display: 'inline-block',\n animation: `thinkingPulse 1.4s ease-in-out ${i * 0.2}s infinite`,\n }}\n />\n ))}\n </div>\n\n {/* Typewriter text + blinking cursor */}\n <span\n style={{\n fontSize: 12,\n color: textMuted,\n letterSpacing: '0.015em',\n fontStyle: 'italic',\n }}\n >\n {displayText}\n <span\n style={{\n display: 'inline-block',\n width: 1,\n height: 13,\n backgroundColor: textMuted,\n marginLeft: 1,\n animation: 'cursorBlink 0.8s step-end infinite',\n verticalAlign: 'text-bottom',\n }}\n />\n </span>\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport Picker from '@emoji-mart/react';\nimport type { IChatConfig } from '../types';\nimport type { UseFileUploadReturn } from '../hooks/useFileUpload';\n\n/** Detect if a hex/rgb color is \"light\" (luminance > 0.5) */\nfunction isLightColor(color: string): boolean {\n let r = 0, g = 0, b = 0;\n if (color.startsWith('#')) {\n const hex = color.replace('#', '');\n r = parseInt(hex.substring(0, 2), 16);\n g = parseInt(hex.substring(2, 4), 16);\n b = parseInt(hex.substring(4, 6), 16);\n }\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 > 0.5;\n}\n\ninterface ChatInputProps {\n onSend: (message: string) => void;\n onTyping?: (isTyping: boolean) => void;\n config: IChatConfig;\n fileUpload: UseFileUploadReturn;\n disabled?: boolean;\n}\n\nexport function ChatInput({\n onSend,\n onTyping,\n config,\n fileUpload,\n disabled = false,\n}: ChatInputProps) {\n const [message, setMessage] = useState('');\n const [showEmojiPicker, setShowEmojiPicker] = useState(false);\n const [emojiData, setEmojiData] = useState<any>();\n const [emojiPickerPosition, setEmojiPickerPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const [isFocused, setIsFocused] = useState(false);\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\n const emojiPickerRef = useRef<HTMLDivElement>(null);\n const emojiButtonRef = useRef<HTMLButtonElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const startTypingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const isTypingRef = useRef<boolean>(false);\n\n const enableEmoji = config.enableEmoji ?? true;\n const enableFileUpload = config.enableFileUpload ?? true;\n\n // Theme tokens — aligned with Xcelsior website design system\n const bgColor = config.theme?.background || '#00001a';\n const isLightTheme = isLightColor(bgColor);\n const textColor = config.theme?.text || (isLightTheme ? '#1a1a2e' : '#f7f7f8');\n const textMuted = config.theme?.textMuted || (isLightTheme ? 'rgba(0,0,0,0.4)' : 'rgba(247,247,248,0.45)');\n const primaryColor = config.theme?.primary || '#337eff';\n\n // Load emoji data\n useEffect(() => {\n if (!enableEmoji) return;\n (async () => {\n try {\n const response = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data');\n setEmojiData(await response.json());\n } catch (error) {\n console.error('Failed to load emoji data:', error);\n }\n })();\n }, [enableEmoji]);\n\n // Handle click outside emoji picker\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(event.target as Node)) {\n setShowEmojiPicker(false);\n }\n };\n\n if (showEmojiPicker) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [showEmojiPicker]);\n\n // Cleanup typing timeouts on unmount\n useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n };\n }, []);\n\n // Update emoji picker position on window resize/scroll\n useEffect(() => {\n if (!showEmojiPicker) return;\n\n const updatePosition = () => {\n if (emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 370,\n left: rect.left - 300,\n });\n }\n };\n\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [showEmojiPicker]);\n\n const handleTyping = (value: string) => {\n setMessage(value);\n\n // Send typing indicator with debouncing\n if (onTyping && config.enableTypingIndicator !== false) {\n // Clear any pending \"start typing\" timeout\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n\n // Clear any pending \"stop typing\" timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // If not already typing, debounce the start typing event\n if (!isTypingRef.current) {\n startTypingTimeoutRef.current = setTimeout(() => {\n onTyping(true);\n isTypingRef.current = true;\n }, 300);\n }\n\n // Set timeout to stop typing indicator after inactivity\n typingTimeoutRef.current = setTimeout(() => {\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }, 1500);\n }\n };\n\n const handleSend = () => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage || disabled) return;\n\n onSend(trimmedMessage);\n setMessage('');\n setShowEmojiPicker(false);\n\n // Stop typing indicator\n if (onTyping) {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }\n\n // Focus back on textarea\n textAreaRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const insertAtCursor = (text: string) => {\n const textarea = textAreaRef.current;\n if (!textarea) {\n setMessage((prev) => prev + text);\n return;\n }\n\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const newValue = message.slice(0, start) + text + message.slice(end);\n setMessage(newValue);\n\n // Set cursor position after inserted text\n setTimeout(() => {\n const newCursorPos = start + text.length;\n textarea.setSelectionRange(newCursorPos, newCursorPos);\n textarea.focus();\n }, 0);\n };\n\n const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n const file = files[0];\n try {\n config.toast?.info('Uploading file...');\n const uploadedFile = await fileUpload.uploadFile(file);\n if (uploadedFile?.markdown) {\n insertAtCursor(`\\n${uploadedFile.markdown}\\n`);\n config.toast?.success('File uploaded successfully');\n }\n } catch (error: any) {\n console.error('File upload failed:', error);\n config.toast?.error(error.message);\n } finally {\n // Clear the file input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n }\n };\n\n const canSend = message.trim().length > 0 && !disabled;\n\n const placeholderColor = isLightTheme ? 'rgba(0,0,0,0.35)' : 'rgba(247,247,248,0.3)';\n\n return (\n <div\n className=\"px-4 py-3\"\n style={{\n borderTop: isLightTheme\n ? '1px solid rgba(0,0,0,0.06)'\n : '1px solid rgba(255,255,255,0.06)',\n }}\n >\n <div\n className=\"relative flex items-center rounded-full transition-all duration-200\"\n style={{\n backgroundColor: isLightTheme\n ? 'rgba(112,115,124,0.08)'\n : 'rgba(112,115,124,0.12)',\n outline: isFocused ? `2px solid ${primaryColor}` : 'none',\n outlineOffset: '-1px',\n border: isLightTheme\n ? '1px solid rgba(0,0,0,0.1)'\n : '1px solid rgba(255,255,255,0.08)',\n backdropFilter: 'blur(32px)',\n }}\n >\n {/* Placeholder color via inline style element */}\n <style>{`.xchat-input::placeholder { color: ${placeholderColor}; }`}</style>\n <textarea\n ref={textAreaRef}\n value={message}\n onChange={(e) => handleTyping(e.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n placeholder=\"Type a message...\"\n rows={1}\n className=\"xchat-input flex-1 resize-none bg-transparent\"\n style={{\n color: textColor,\n border: 'none',\n outline: 'none',\n boxShadow: 'none',\n WebkitAppearance: 'none',\n padding: '10px 0 10px 20px',\n minHeight: '42px',\n maxHeight: '120px',\n caretColor: primaryColor,\n fontSize: '14px',\n lineHeight: '20px',\n letterSpacing: '0.006em',\n }}\n disabled={disabled}\n />\n\n {/* Action buttons row */}\n <div className=\"flex items-center gap-1 px-2 shrink-0\">\n {enableEmoji && (\n <button\n ref={emojiButtonRef}\n type=\"button\"\n onClick={() => {\n if (!showEmojiPicker && emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 450,\n left: rect.left - 290,\n });\n }\n setShowEmojiPicker((v) => !v);\n }}\n className=\"p-1.5 rounded-lg transition-all duration-150\"\n style={{\n color: textMuted,\n backgroundColor: 'transparent',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isLightTheme ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)';\n e.currentTarget.style.color = textColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = textMuted;\n }}\n disabled={disabled}\n aria-label=\"Add emoji\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Emoji</title>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n <line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\" />\n <line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\" />\n </svg>\n </button>\n )}\n\n {enableFileUpload && fileUpload.canUpload && (\n <>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n className=\"p-1.5 rounded-lg transition-all duration-150\"\n style={{\n color: textMuted,\n backgroundColor: 'transparent',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.06)';\n e.currentTarget.style.color = textColor;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = textMuted;\n }}\n disabled={disabled || fileUpload.isUploading}\n aria-label=\"Attach file\"\n >\n {fileUpload.isUploading ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n className=\"animate-spin\"\n aria-hidden=\"true\"\n >\n <title>Uploading</title>\n <path d=\"M21 12a9 9 0 11-6.219-8.56\" />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Attach file</title>\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\" />\n </svg>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*,application/pdf,.doc,.docx\"\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </>\n )}\n\n {/* Send button — gradient pill matching website CTA style */}\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-1.5 rounded-lg transition-all duration-200\"\n style={{\n background: canSend\n ? `linear-gradient(135deg, ${primaryColor}, ${config.theme?.primaryStrong || '#005eff'})`\n : 'transparent',\n color: canSend ? '#ffffff' : textMuted,\n opacity: canSend ? 1 : 0.35,\n cursor: canSend ? 'pointer' : 'default',\n boxShadow: canSend\n ? `0 2px 8px -2px ${primaryColor}60`\n : 'none',\n }}\n aria-label=\"Send message\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <title>Send</title>\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Upload progress */}\n {fileUpload.isUploading && (\n <div className=\"mt-2 px-1\">\n <div\n className=\"w-full rounded-full overflow-hidden\"\n style={{\n height: 3,\n backgroundColor: isLightTheme ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)',\n }}\n >\n <div\n className=\"h-full rounded-full transition-all duration-300\"\n style={{\n width: `${fileUpload.uploadProgress}%`,\n background: `linear-gradient(90deg, ${primaryColor}, ${config.theme?.primaryStrong || '#005eff'})`,\n }}\n />\n </div>\n <p\n className=\"mt-1\"\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: textMuted,\n }}\n >\n Uploading... {fileUpload.uploadProgress}%\n </p>\n </div>\n )}\n\n {/* Emoji picker portal */}\n {showEmojiPicker &&\n emojiData &&\n emojiPickerPosition &&\n typeof document !== 'undefined' &&\n createPortal(\n <div\n ref={emojiPickerRef}\n className=\"fixed rounded-xl overflow-hidden\"\n style={{\n top: `${emojiPickerPosition.top}px`,\n left: `${emojiPickerPosition.left}px`,\n zIndex: 9999,\n boxShadow: [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.1)',\n '0 16px 48px -8px rgba(0,0,0,0.5)',\n ].join(', '),\n }}\n >\n <Picker\n data={emojiData}\n onEmojiSelect={(emoji: any) => {\n insertAtCursor(emoji.native || emoji.shortcodes || '');\n setShowEmojiPicker(false);\n }}\n previewPosition=\"none\"\n skinTonePosition=\"none\"\n navPosition=\"bottom\"\n perLine={8}\n searchPosition=\"sticky\"\n theme=\"dark\"\n />\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { ChatWidget } from './ChatWidget';\nimport { PreChatForm } from './PreChatForm';\nimport { ChatBubbleIcon } from './BrandIcons';\nimport { useDraggablePosition } from '../hooks/useDraggablePosition';\nimport type { IChatConfig, IUser } from '../types';\nimport { useChatWidgetState } from '../hooks/useChatWidgetState';\nimport type { ChatWidgetState } from '../hooks/useChatWidgetState';\n\ninterface ChatWidgetWrapperProps {\n config: Omit<IChatConfig, 'conversationId'> & {\n conversationId?: string;\n };\n className?: string;\n storageKeyPrefix?: string;\n onPreChatSubmit?: (user: IUser) => void;\n state?: ChatWidgetState;\n defaultState?: ChatWidgetState;\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\ninterface StoredUserData {\n name: string;\n email: string;\n conversationId: string;\n timestamp: number;\n}\n\nfunction generateSessionId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\nexport function Chat({\n config,\n className = '',\n storageKeyPrefix = 'xcelsior_chat',\n onPreChatSubmit,\n state,\n defaultState = 'minimized',\n onStateChange,\n}: ChatWidgetWrapperProps) {\n const [userInfo, setUserInfo] = useState<IUser | null>(null);\n const [conversationId, setConversationId] = useState<string>('');\n const [isLoading, setIsLoading] = useState(true);\n const [isAnimating, setIsAnimating] = useState(false);\n const [showWidget, setShowWidget] = useState(false);\n\n const identityMode = config.identityCollection || 'progressive';\n const { position, isDragging, showHint, handlers } = useDraggablePosition(config.position);\n\n const { currentState, setState: setStateRaw } = useChatWidgetState({\n state,\n defaultState,\n onStateChange,\n });\n\n // Wrap setState with animation handling\n const setState = useCallback(\n (newState: ChatWidgetState) => {\n if (newState === 'open' && currentState === 'minimized') {\n // Opening: show widget immediately, trigger animation\n setShowWidget(true);\n setIsAnimating(true);\n setStateRaw(newState);\n // Let the animation class apply on next frame\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setIsAnimating(false);\n });\n });\n } else if (\n (newState === 'minimized' || newState === 'closed') &&\n currentState === 'open'\n ) {\n // Closing: animate out, then change state\n setIsAnimating(true);\n setTimeout(() => {\n setShowWidget(false);\n setIsAnimating(false);\n setStateRaw(newState);\n }, 200);\n } else {\n setStateRaw(newState);\n }\n },\n [currentState, setStateRaw]\n );\n\n // Sync showWidget with state\n useEffect(() => {\n if (currentState === 'open') {\n setShowWidget(true);\n }\n }, [currentState]);\n\n // Initialize session\n useEffect(() => {\n const initializeSession = () => {\n try {\n if (config.currentUser?.email && config.currentUser?.name) {\n const convId = config.conversationId || generateSessionId();\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: config.currentUser.status,\n };\n setUserInfo(user);\n setConversationId(convId);\n setIsLoading(false);\n return;\n }\n\n const storedDataJson = localStorage.getItem(`${storageKeyPrefix}_user`);\n if (storedDataJson) {\n const storedData: StoredUserData = JSON.parse(storedDataJson);\n const isExpired = Date.now() - storedData.timestamp > 24 * 60 * 60 * 1000;\n\n if (!isExpired && storedData.email && storedData.name) {\n const user: IUser = {\n name: storedData.name,\n email: storedData.email,\n type: 'customer',\n status: 'online',\n };\n setUserInfo(user);\n setConversationId(storedData.conversationId);\n setIsLoading(false);\n return;\n }\n }\n\n const convId = config.conversationId || generateSessionId();\n setConversationId(convId);\n\n if (identityMode === 'progressive' || identityMode === 'none') {\n setUserInfo(null);\n }\n } catch (error) {\n console.error('Error initializing chat session:', error);\n setConversationId(config.conversationId || generateSessionId());\n } finally {\n setIsLoading(false);\n }\n };\n\n initializeSession();\n }, [config, storageKeyPrefix, identityMode]);\n\n const handlePreChatSubmit = useCallback(\n (name: string, email: string) => {\n const convId = conversationId || generateSessionId();\n const user: IUser = { name, email, type: 'customer', status: 'online' };\n\n const storageData: StoredUserData = {\n name,\n email,\n conversationId: convId,\n timestamp: Date.now(),\n };\n\n try {\n localStorage.setItem(`${storageKeyPrefix}_user`, JSON.stringify(storageData));\n } catch {\n // Storage unavailable\n }\n\n setUserInfo(user);\n setConversationId(convId);\n onPreChatSubmit?.(user);\n },\n [conversationId, storageKeyPrefix, onPreChatSubmit]\n );\n\n if (isLoading) return null;\n if (currentState === 'closed') return null;\n\n const positionClass = position === 'left' ? 'left-4' : 'right-4';\n const primaryColor = config.theme?.primary || '#337eff';\n const primaryStrong = config.theme?.primaryStrong || '#005eff';\n\n // FAB button — only show when minimized\n if (currentState === 'minimized') {\n return (\n <div className={`fixed bottom-5 ${positionClass} z-50 ${className}`}>\n <button\n type=\"button\"\n onClick={() => setState('open')}\n className={`group relative rounded-full text-white transition-all duration-300 flex items-center justify-center touch-none select-none ${\n showHint ? 'animate-bounce' : ''\n } ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`}\n onMouseEnter={(e) => { e.currentTarget.style.transform = 'scale(1.08)'; }}\n onMouseLeave={(e) => { e.currentTarget.style.transform = isDragging ? 'scale(1.1)' : 'scale(1)'; }}\n style={{\n width: 64,\n height: 64,\n background: `linear-gradient(135deg, ${primaryColor}, ${primaryStrong})`,\n boxShadow: [\n `0 4px 24px 0 ${primaryColor}80`,\n `0 8px 32px -4px rgba(0,0,0,0.3)`,\n `inset 0 1px 0 0 rgba(255,255,255,0.2)`,\n ].join(', '),\n }}\n aria-label=\"Open chat\"\n {...handlers}\n >\n <ChatBubbleIcon size={28} color=\"white\" className=\"pointer-events-none\" />\n\n {/* Pulse ring — subtle blue glow */}\n <span\n className=\"absolute inset-0 rounded-full animate-ping pointer-events-none\"\n style={{\n backgroundColor: primaryColor,\n opacity: 0.15,\n animationDuration: '2.5s',\n }}\n />\n </button>\n </div>\n );\n }\n\n // Open state — pre-chat form (form mode only)\n if (identityMode === 'form' && (!userInfo || !userInfo.email || !userInfo.name)) {\n return (\n <PreChatForm\n onSubmit={handlePreChatSubmit}\n className={className}\n initialName={config.currentUser?.name}\n initialEmail={config.currentUser?.email}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n }\n\n // Open state — chat widget\n const fullConfig: IChatConfig = {\n ...config,\n conversationId,\n currentUser: userInfo || undefined,\n };\n\n // Animation styles for open/close\n const widgetAnimationStyle: React.CSSProperties =\n showWidget && !isAnimating\n ? {\n opacity: 1,\n transform: 'translateY(0) scale(1)',\n transition: 'opacity 0.25s ease-out, transform 0.25s ease-out',\n }\n : {\n opacity: 0,\n transform: 'translateY(12px) scale(0.97)',\n transition: 'opacity 0.2s ease-in, transform 0.2s ease-in',\n };\n\n return (\n <div style={widgetAnimationStyle}>\n <ChatWidget\n config={fullConfig}\n className={className}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n resolvedPosition={position}\n />\n </div>\n );\n}\n","import { useState } from 'react';\n\ninterface PreChatFormProps {\n onSubmit: (name: string, email: string) => void;\n className?: string;\n initialName?: string;\n initialEmail?: string;\n /**\n * Callback when user wants to minimize the form\n */\n onMinimize: () => void;\n /**\n * Callback when user wants to close the form\n */\n onClose: () => void;\n}\n\n/**\n * PreChatForm component for collecting user information before starting chat.\n * Styled to match the Xcelsior website design system.\n */\nexport function PreChatForm({\n onSubmit,\n className = '',\n initialName = '',\n initialEmail = '',\n onMinimize,\n onClose,\n}: PreChatFormProps) {\n const [name, setName] = useState(initialName);\n const [email, setEmail] = useState(initialEmail);\n const [errors, setErrors] = useState<{ name?: string; email?: string }>({});\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [focusedField, setFocusedField] = useState<string | null>(null);\n\n const validateForm = (): boolean => {\n const newErrors: { name?: string; email?: string } = {};\n\n // Validate name\n if (!name.trim()) {\n newErrors.name = 'Name is required';\n } else if (name.trim().length < 2) {\n newErrors.name = 'Name must be at least 2 characters';\n }\n\n // Validate email\n if (!email.trim()) {\n newErrors.email = 'Email is required';\n } else {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n newErrors.email = 'Please enter a valid email address';\n }\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n setIsSubmitting(true);\n try {\n onSubmit(name.trim(), email.trim());\n } catch (error) {\n console.error('Error submitting form:', error);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const inputStyle = (fieldName: string, hasError: boolean): React.CSSProperties => ({\n width: '100%',\n padding: '10px 16px',\n fontSize: '14px',\n lineHeight: '20px',\n letterSpacing: '0.006em',\n color: '#f7f7f8',\n backgroundColor: 'rgba(255,255,255,0.04)',\n border: 'none',\n borderRadius: '12px',\n outline: 'none',\n boxShadow: hasError\n ? 'inset 0 0 0 1px rgba(255,99,99,0.5)'\n : focusedField === fieldName\n ? 'inset 0 0 0 1px rgba(51,126,255,0.4), 0 0 0 3px rgba(51,126,255,0.15)'\n : 'inset 0 0 0 0.5px rgba(255,255,255,0.08)',\n transition: 'box-shadow 0.2s ease',\n caretColor: '#337eff',\n });\n\n return (\n <div\n className={`fixed bottom-4 right-4 z-50 flex flex-col overflow-hidden ${className}`}\n style={{\n width: 380,\n maxHeight: 'calc(100vh - 2rem)',\n backgroundColor: '#00001a',\n borderRadius: 16,\n boxShadow: [\n 'inset 0 0 0 0.5px rgba(255,255,255,0.06)',\n 'inset 0 1px 0 0 rgba(255,255,255,0.12)',\n '0 25px 60px -12px rgba(0,0,0,0.6)',\n '0 0 40px -8px rgba(51,126,255,0.15)',\n ].join(', '),\n /* Dot grid texture */\n backgroundImage:\n 'radial-gradient(circle, rgba(255,255,255,0.03) 1px, transparent 1px)',\n backgroundSize: '24px 24px',\n }}\n >\n {/* Header — matching ChatHeader gradient */}\n <div\n className=\"relative text-white overflow-hidden\"\n style={{\n background: 'linear-gradient(135deg, #337eff 0%, #005eff 50%, #001a66 100%)',\n }}\n >\n {/* Glass overlay */}\n <div\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n background:\n 'linear-gradient(180deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 40%)',\n }}\n />\n <div className=\"relative px-5 py-4\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h2\n className=\"font-semibold\"\n style={{\n fontSize: '17px',\n letterSpacing: '-0.01em',\n }}\n >\n Start a Conversation\n </h2>\n <p\n className=\"mt-1\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(255,255,255,0.6)',\n }}\n >\n Please provide your details to continue\n </p>\n </div>\n <div className=\"flex gap-1 ml-2\">\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Minimize chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 rounded-lg transition-all duration-150\"\n style={{ backgroundColor: 'transparent' }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n 'rgba(255,255,255,0.1)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n aria-label=\"Close chat\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Close</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n </div>\n {/* Bottom edge line */}\n <div\n className=\"h-px\"\n style={{\n background:\n 'linear-gradient(90deg, transparent 5%, rgba(255,255,255,0.12) 30%, rgba(255,255,255,0.12) 70%, transparent 95%)',\n }}\n />\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"p-5 flex flex-col gap-4\">\n {/* Name Input */}\n <div>\n <label\n htmlFor=\"chat-name\"\n className=\"block mb-2 font-medium\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.72)',\n }}\n >\n Name <span style={{ color: '#ff6363' }}>*</span>\n </label>\n <input\n type=\"text\"\n id=\"chat-name\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (errors.name) {\n setErrors((prev) => ({ ...prev, name: undefined }));\n }\n }}\n onFocus={() => setFocusedField('name')}\n onBlur={() => setFocusedField(null)}\n style={inputStyle('name', !!errors.name)}\n placeholder=\"John Doe\"\n disabled={isSubmitting}\n autoComplete=\"name\"\n />\n {errors.name && (\n <p\n className=\"mt-1.5\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: '#ff6363',\n }}\n role=\"alert\"\n >\n {errors.name}\n </p>\n )}\n </div>\n\n {/* Email Input */}\n <div>\n <label\n htmlFor=\"chat-email\"\n className=\"block mb-2 font-medium\"\n style={{\n fontSize: '13px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.72)',\n }}\n >\n Email <span style={{ color: '#ff6363' }}>*</span>\n </label>\n <input\n type=\"email\"\n id=\"chat-email\"\n value={email}\n onChange={(e) => {\n setEmail(e.target.value);\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }));\n }\n }}\n onFocus={() => setFocusedField('email')}\n onBlur={() => setFocusedField(null)}\n style={inputStyle('email', !!errors.email)}\n placeholder=\"john@example.com\"\n disabled={isSubmitting}\n autoComplete=\"email\"\n />\n {errors.email && (\n <p\n className=\"mt-1.5\"\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: '#ff6363',\n }}\n role=\"alert\"\n >\n {errors.email}\n </p>\n )}\n </div>\n\n {/* Submit Button — gradient pill matching website CTA */}\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className=\"w-full py-2.5 rounded-xl font-semibold text-white transition-all duration-200\"\n style={{\n fontSize: '14px',\n letterSpacing: '0.006em',\n background: 'linear-gradient(135deg, #337eff, #005eff)',\n boxShadow: '0 4px 16px -4px rgba(51,126,255,0.4)',\n opacity: isSubmitting ? 0.6 : 1,\n cursor: isSubmitting ? 'not-allowed' : 'pointer',\n }}\n onMouseEnter={(e) => {\n if (!isSubmitting) {\n e.currentTarget.style.boxShadow =\n '0 6px 20px -4px rgba(51,126,255,0.5)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.boxShadow =\n '0 4px 16px -4px rgba(51,126,255,0.4)';\n }}\n >\n {isSubmitting ? (\n <span className=\"flex items-center justify-center gap-2\">\n <svg\n className=\"animate-spin\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n aria-label=\"Loading\"\n >\n <title>Loading</title>\n <path d=\"M21 12a9 9 0 11-6.219-8.56\" />\n </svg>\n Starting Chat...\n </span>\n ) : (\n 'Start Chat'\n )}\n </button>\n\n {/* Privacy Notice */}\n <p\n className=\"text-center\"\n style={{\n fontSize: '11px',\n letterSpacing: '0.019em',\n color: 'rgba(247,247,248,0.28)',\n }}\n >\n We respect your privacy. Your information will only be used to assist you.\n </p>\n </form>\n\n {/* Footer */}\n <div\n className=\"px-4 py-1.5 text-center\"\n style={{\n borderTop: '1px solid rgba(255,255,255,0.06)',\n backgroundColor: 'rgba(0,0,0,0.2)',\n }}\n >\n <p\n style={{\n fontSize: '10px',\n letterSpacing: '0.025em',\n color: 'rgba(247,247,248,0.28)',\n }}\n >\n Powered by{' '}\n <span style={{ fontWeight: 600, color: 'rgba(247,247,248,0.45)' }}>\n Xcelsior\n </span>\n </p>\n </div>\n </div>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport type { WidgetPosition } from '../types';\n\nconst STORAGE_KEY = 'xcelsior-chat-position';\n\nfunction getStoredPosition(): 'left' | 'right' {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored === 'left' || stored === 'right') return stored;\n } catch {\n // localStorage not available\n }\n return 'right';\n}\n\nfunction storePosition(position: 'left' | 'right') {\n try {\n localStorage.setItem(STORAGE_KEY, position);\n } catch {\n // localStorage not available\n }\n}\n\nexport function useDraggablePosition(configPosition: WidgetPosition = 'auto') {\n const resolvedDefault = configPosition === 'auto' ? getStoredPosition() : configPosition;\n const [position, setPosition] = useState<'left' | 'right'>(resolvedDefault);\n const [isDragging, setIsDragging] = useState(false);\n const dragStartX = useRef(0);\n const fabRef = useRef<HTMLButtonElement>(null);\n const hasShownHint = useRef(false);\n const [showHint, setShowHint] = useState(false);\n\n // Show bounce hint on first visit\n useEffect(() => {\n try {\n const hasVisited = localStorage.getItem('xcelsior-chat-hint-shown');\n if (!hasVisited && !hasShownHint.current) {\n hasShownHint.current = true;\n setShowHint(true);\n const timer = setTimeout(() => {\n setShowHint(false);\n localStorage.setItem('xcelsior-chat-hint-shown', 'true');\n }, 2000);\n return () => clearTimeout(timer);\n }\n } catch {\n // localStorage not available\n }\n }, []);\n\n const handlePointerDown = useCallback((e: React.PointerEvent) => {\n dragStartX.current = e.clientX;\n setIsDragging(true);\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n }, []);\n\n const handlePointerMove = useCallback((_e: React.PointerEvent) => {\n // Visual feedback could be added here (e.g., opacity change)\n }, []);\n\n const handlePointerUp = useCallback(\n (e: React.PointerEvent) => {\n setIsDragging(false);\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n\n const deltaX = e.clientX - dragStartX.current;\n // Only snap if dragged more than 50px horizontally\n if (Math.abs(deltaX) > 50) {\n const screenMid = window.innerWidth / 2;\n const newPosition = e.clientX < screenMid ? 'left' : 'right';\n if (newPosition !== position) {\n setPosition(newPosition);\n storePosition(newPosition);\n }\n }\n },\n [position]\n );\n\n return {\n position,\n isDragging,\n showHint,\n fabRef,\n handlers: {\n onPointerDown: handlePointerDown,\n onPointerMove: handlePointerMove,\n onPointerUp: handlePointerUp,\n },\n };\n}\n","import { useCallback, useState } from 'react';\n\nexport type ChatWidgetState = 'open' | 'minimized' | 'closed' | 'undefined';\n\nexport interface UseChatWidgetStateOptions {\n /**\n * Controlled state. When provided, the component is controlled.\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\nexport interface UseChatWidgetStateReturn {\n /**\n * Current state of the widget\n */\n currentState: ChatWidgetState;\n /**\n * Function to update the state\n */\n setState: (newState: ChatWidgetState) => void;\n /**\n * Whether the state is controlled\n */\n isControlled: boolean;\n}\n\n/**\n * Hook to manage chat widget state (controlled vs uncontrolled)\n * Encapsulates the logic for handling both controlled and uncontrolled state patterns\n */\nexport function useChatWidgetState({\n state: controlledState,\n defaultState = 'minimized',\n onStateChange,\n}: UseChatWidgetStateOptions): UseChatWidgetStateReturn {\n // Handle controlled vs uncontrolled state\n const [uncontrolledState, setUncontrolledState] = useState<ChatWidgetState>(defaultState);\n const isControlled = controlledState !== undefined && controlledState !== 'undefined';\n const currentState = isControlled ? controlledState : uncontrolledState;\n\n // State setter that works for both controlled and uncontrolled modes\n const setState = useCallback(\n (newValue: ChatWidgetState) => {\n // Update internal state if uncontrolled\n if (!isControlled) {\n setUncontrolledState(newValue);\n }\n // Always call the change handler if provided\n onStateChange?.(newValue);\n },\n [isControlled, onStateChange]\n );\n\n return {\n currentState,\n setState,\n isControlled,\n };\n}\n","interface TypingIndicatorProps {\n isTyping: boolean;\n userName?: string;\n}\n\nexport function TypingIndicator({ isTyping, userName }: TypingIndicatorProps) {\n if (!isTyping) {\n return null;\n }\n\n return (\n <div\n className=\"px-4 py-2\"\n style={{\n borderTop: '1px solid rgba(255,255,255,0.06)',\n backgroundColor: 'rgba(0,0,0,0.15)',\n }}\n >\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"rounded-full animate-bounce\"\n style={{\n width: 5,\n height: 5,\n backgroundColor: 'rgba(51,126,255,0.6)',\n animationDelay: `${i * 0.1}s`,\n animationDuration: '0.8s',\n }}\n />\n ))}\n </div>\n <span\n style={{\n fontSize: '12px',\n letterSpacing: '0.015em',\n color: 'rgba(247,247,248,0.45)',\n }}\n >\n {userName ? `${userName} is typing...` : 'Someone is typing...'}\n </span>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","error","useCallback","useEffect","useState","useState","useEffect","error","useCallback","useState","axios","error","useEffect","useState","useCallback","useEffect","useRef","useState","jsx","jsxs","useCallback","useEffect","useRef","jsx","jsxs","jsx","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","computeIsLightTheme","useState","useRef","useEffect","jsx","jsxs","useRef","useEffect","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","jsx","jsxs","useCallback","isTyping","useEffect","useCallback","useEffect","useState","useState","jsx","jsxs","useState","useCallback","useRef","useEffect","STORAGE_KEY","useCallback","useState","jsx","jsxs","useState","useCallback","useEffect","convId","jsx","jsxs"]}