@rag-widget/chat-widget 0.1.2 → 0.1.3

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,"file":"index.umd.js","sources":["../src/hooks/useChatWidget.ts","../src/components/ChatBubble.tsx","../src/components/ChatWindow.tsx","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ChatWidget.tsx","../src/providers/ChatWidgetProvider.tsx"],"sourcesContent":["import { useState, useCallback, useRef, useEffect } from 'react';\r\nimport type { Message, WidgetConfig, ChatSession, ApiResponse } from '../types';\r\n\r\ninterface UseChatWidgetOptions {\r\n apiKey: string;\r\n widgetId: string;\r\n apiBaseUrl: string;\r\n onError?: (error: Error) => void;\r\n onMessageSent?: (message: string) => void;\r\n onMessageReceived?: (message: Message) => void;\r\n}\r\n\r\ninterface UseChatWidgetReturn {\r\n messages: Message[];\r\n isLoading: boolean;\r\n isConnected: boolean;\r\n config: WidgetConfig | null;\r\n error: Error | null;\r\n sendMessage: (content: string) => Promise<void>;\r\n clearMessages: () => void;\r\n retry: () => void;\r\n}\r\n\r\nexport function useChatWidget(options: UseChatWidgetOptions): UseChatWidgetReturn {\r\n const { apiKey, widgetId, apiBaseUrl, onError, onMessageSent, onMessageReceived } = options;\r\n\r\n const [messages, setMessages] = useState<Message[]>([]);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [isConnected, setIsConnected] = useState(false);\r\n const [config, setConfig] = useState<WidgetConfig | null>(null);\r\n const [error, setError] = useState<Error | null>(null);\r\n const [session, setSession] = useState<ChatSession | null>(null);\r\n\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n // Fetch widget configuration on mount\r\n useEffect(() => {\r\n fetchConfig();\r\n return () => {\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n };\r\n }, [apiKey, widgetId]);\r\n\r\n const fetchConfig = useCallback(async () => {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/config`, {\r\n headers: {\r\n 'X-API-Key': apiKey\r\n }\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch config: ${response.status}`);\r\n }\r\n\r\n const result: ApiResponse<WidgetConfig> = await response.json();\r\n\r\n if (result.status === 'success' && result.data) {\r\n setConfig(result.data);\r\n setIsConnected(true);\r\n setError(null);\r\n } else {\r\n throw new Error(result.message || 'Failed to load widget configuration');\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Unknown error');\r\n setError(error);\r\n setIsConnected(false);\r\n onError?.(error);\r\n }\r\n }, [apiKey, widgetId, apiBaseUrl, onError]);\r\n\r\n const createSession = useCallback(async (): Promise<ChatSession> => {\r\n const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/sessions`, {\r\n method: 'POST',\r\n headers: {\r\n 'X-API-Key': apiKey,\r\n 'Content-Type': 'application/json'\r\n }\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to create session: ${response.status}`);\r\n }\r\n\r\n const result: ApiResponse<ChatSession> = await response.json();\r\n\r\n if (result.status === 'success' && result.data) {\r\n return result.data;\r\n }\r\n\r\n throw new Error(result.message || 'Failed to create session');\r\n }, [apiKey, widgetId, apiBaseUrl]);\r\n\r\n const sendMessage = useCallback(async (content: string) => {\r\n if (!content.trim() || isLoading) return;\r\n\r\n // Cancel any ongoing request\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n abortControllerRef.current = new AbortController();\r\n\r\n const userMessage: Message = {\r\n id: `msg-${Date.now()}`,\r\n role: 'user',\r\n content: content.trim(),\r\n timestamp: new Date()\r\n };\r\n\r\n setMessages(prev => [...prev, userMessage]);\r\n setIsLoading(true);\r\n setError(null);\r\n onMessageSent?.(content);\r\n\r\n try {\r\n // Ensure we have a session\r\n let currentSession = session;\r\n if (!currentSession || new Date() > new Date(currentSession.expiresAt)) {\r\n currentSession = await createSession();\r\n setSession(currentSession);\r\n }\r\n\r\n // Create placeholder for assistant message\r\n const assistantMessageId = `msg-${Date.now()}-assistant`;\r\n const assistantMessage: Message = {\r\n id: assistantMessageId,\r\n role: 'assistant',\r\n content: '',\r\n timestamp: new Date(),\r\n isStreaming: true\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n\r\n // Send message with SSE streaming\r\n const response = await fetch(\r\n `${apiBaseUrl}/api/v1/widget/${widgetId}/sessions/${currentSession.sessionId}/messages`,\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'X-API-Key': apiKey,\r\n 'Content-Type': 'application/json',\r\n 'Accept': 'text/event-stream'\r\n },\r\n body: JSON.stringify({ message: content }),\r\n signal: abortControllerRef.current.signal\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to send message: ${response.status}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n const decoder = new TextDecoder();\r\n let fullContent = '';\r\n\r\n if (reader) {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n const chunk = decoder.decode(value, { stream: true });\r\n const lines = chunk.split('\\n');\r\n\r\n for (const line of lines) {\r\n if (line.startsWith('data: ')) {\r\n try {\r\n const data = JSON.parse(line.slice(6));\r\n\r\n if (data.type === 'chunk') {\r\n fullContent += data.content;\r\n setMessages(prev =>\r\n prev.map(msg =>\r\n msg.id === assistantMessageId\r\n ? { ...msg, content: fullContent }\r\n : msg\r\n )\r\n );\r\n } else if (data.type === 'done') {\r\n setMessages(prev =>\r\n prev.map(msg =>\r\n msg.id === assistantMessageId\r\n ? { ...msg, isStreaming: false, sources: data.sources }\r\n : msg\r\n )\r\n );\r\n\r\n const finalMessage: Message = {\r\n id: assistantMessageId,\r\n role: 'assistant',\r\n content: fullContent,\r\n timestamp: new Date(),\r\n sources: data.sources\r\n };\r\n onMessageReceived?.(finalMessage);\r\n }\r\n } catch {\r\n // Ignore parse errors for partial SSE data\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n if ((err as Error).name === 'AbortError') {\r\n // Request was cancelled, ignore\r\n return;\r\n }\r\n\r\n const error = err instanceof Error ? err : new Error('Failed to send message');\r\n setError(error);\r\n onError?.(error);\r\n\r\n // Remove the incomplete assistant message\r\n setMessages(prev => prev.filter(msg => !msg.isStreaming));\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [apiKey, widgetId, apiBaseUrl, session, isLoading, createSession, onError, onMessageSent, onMessageReceived]);\r\n\r\n const clearMessages = useCallback(() => {\r\n setMessages([]);\r\n setSession(null);\r\n }, []);\r\n\r\n const retry = useCallback(() => {\r\n setError(null);\r\n fetchConfig();\r\n }, [fetchConfig]);\r\n\r\n return {\r\n messages,\r\n isLoading,\r\n isConnected,\r\n config,\r\n error,\r\n sendMessage,\r\n clearMessages,\r\n retry\r\n };\r\n}\r\n","import React from 'react';\r\nimport type { ChatBubbleProps } from '../types';\r\n\r\nconst ChatIcon: React.FC = () => (\r\n <svg\r\n className=\"rag-chat-bubble-icon\"\r\n viewBox=\"0 0 24 24\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H5.17L4 17.17V4h16v12z\" />\r\n <path d=\"M7 9h10v2H7zm0-3h10v2H7z\" />\r\n </svg>\r\n);\r\n\r\nconst CloseIcon: React.FC = () => (\r\n <svg\r\n className=\"rag-chat-bubble-icon\"\r\n viewBox=\"0 0 24 24\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n);\r\n\r\nexport const ChatBubble: React.FC<ChatBubbleProps> = ({\r\n isOpen,\r\n onClick,\r\n primaryColor = '#007bff',\r\n position = 'bottom-right',\r\n unreadCount = 0\r\n}) => {\r\n return (\r\n <button\r\n className={`rag-chat-bubble ${position}`}\r\n onClick={onClick}\r\n style={{ backgroundColor: primaryColor }}\r\n aria-label={isOpen ? 'Close chat' : 'Open chat'}\r\n type=\"button\"\r\n >\r\n {isOpen ? <CloseIcon /> : <ChatIcon />}\r\n {!isOpen && unreadCount > 0 && (\r\n <span className=\"rag-chat-bubble-badge\">\r\n {unreadCount > 9 ? '9+' : unreadCount}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n};\r\n\r\nexport default ChatBubble;\r\n","import React, { useState, useRef, useEffect } from 'react';\r\nimport type { ChatWindowProps, Message } from '../types';\r\n\r\nconst CloseIcon: React.FC = () => (\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\r\n />\r\n </svg>\r\n);\r\n\r\nconst SendIcon: React.FC = () => (\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\r\n </svg>\r\n);\r\n\r\nconst LoadingDots: React.FC = () => (\r\n <div className=\"rag-chat-loading\">\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n </div>\r\n);\r\n\r\ninterface MessageBubbleProps {\r\n message: Message;\r\n}\r\n\r\nconst MessageBubble: React.FC<MessageBubbleProps> = ({ message }) => (\r\n <div className={`rag-chat-message ${message.role}`}>\r\n {message.isStreaming && !message.content ? (\r\n <LoadingDots />\r\n ) : (\r\n <p className=\"rag-chat-message-content\">{message.content}</p>\r\n )}\r\n {message.sources && message.sources.length > 0 && (\r\n <div className=\"rag-chat-message-sources\">\r\n <div className=\"rag-chat-message-sources-title\">Sources:</div>\r\n {message.sources.map((source, index) => (\r\n <div key={index} className=\"rag-chat-message-source\">\r\n {source.title}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n);\r\n\r\nexport const ChatWindow: React.FC<ChatWindowProps> = ({\r\n isOpen,\r\n onClose,\r\n config,\r\n messages,\r\n isLoading,\r\n onSendMessage\r\n}) => {\r\n const [inputValue, setInputValue] = useState('');\r\n const messagesEndRef = useRef<HTMLDivElement>(null);\r\n const inputRef = useRef<HTMLTextAreaElement>(null);\r\n\r\n // Scroll to bottom when new messages arrive\r\n useEffect(() => {\r\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\r\n }, [messages]);\r\n\r\n // Focus input when window opens\r\n useEffect(() => {\r\n if (isOpen) {\r\n inputRef.current?.focus();\r\n }\r\n }, [isOpen]);\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (inputValue.trim() && !isLoading) {\r\n onSendMessage(inputValue.trim());\r\n setInputValue('');\r\n }\r\n };\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n handleSubmit(e);\r\n }\r\n };\r\n\r\n if (!isOpen) return null;\r\n\r\n const position = config?.position || 'bottom-right';\r\n const primaryColor = config?.primaryColor || '#007bff';\r\n\r\n return (\r\n <div\r\n className={`rag-chat-window ${position}`}\r\n style={{ '--rag-primary-color': primaryColor } as React.CSSProperties}\r\n >\r\n <div className=\"rag-chat-header\" style={{ backgroundColor: primaryColor }}>\r\n <h3 className=\"rag-chat-header-title\">{config?.name || 'Chat'}</h3>\r\n <button\r\n className=\"rag-chat-header-close\"\r\n onClick={onClose}\r\n aria-label=\"Close chat\"\r\n type=\"button\"\r\n >\r\n <CloseIcon />\r\n </button>\r\n </div>\r\n\r\n <div className=\"rag-chat-messages\">\r\n {messages.length === 0 && (config?.uspText || config?.greeting) && (\r\n <div className=\"rag-chat-greeting\">\r\n {config?.uspText && (\r\n <p className=\"rag-chat-usp-text\">{config.uspText}</p>\r\n )}\r\n {config?.greeting && (\r\n <p className=\"rag-chat-greeting-text\">{config.greeting}</p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {messages.map(message => (\r\n <MessageBubble key={message.id} message={message} />\r\n ))}\r\n\r\n <div ref={messagesEndRef} />\r\n </div>\r\n\r\n <form className=\"rag-chat-input-container\" onSubmit={handleSubmit}>\r\n <textarea\r\n ref={inputRef}\r\n className=\"rag-chat-input\"\r\n value={inputValue}\r\n onChange={e => setInputValue(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n placeholder={config?.placeholder || 'Type a message...'}\r\n rows={1}\r\n maxLength={config?.allowedMessageLength || 2000}\r\n disabled={isLoading}\r\n />\r\n <button\r\n type=\"submit\"\r\n className=\"rag-chat-send-button\"\r\n disabled={!inputValue.trim() || isLoading}\r\n style={{ backgroundColor: primaryColor }}\r\n aria-label=\"Send message\"\r\n >\r\n <SendIcon />\r\n </button>\r\n </form>\r\n\r\n {config?.showPoweredBy && (\r\n <div className=\"rag-chat-powered-by\">\r\n Powered by <a href=\"https://rag-widget.com\" target=\"_blank\" rel=\"noopener noreferrer\">RAG Widget</a>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default ChatWindow;\r\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import React, { useState } from 'react';\r\nimport { useChatWidget } from '../hooks/useChatWidget';\r\nimport { ChatBubble } from './ChatBubble';\r\nimport { ChatWindow } from './ChatWindow';\r\nimport type { ChatWidgetProps } from '../types';\r\nimport '../styles/widget.css';\r\n\r\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl = '',\r\n position,\r\n primaryColor,\r\n greeting,\r\n placeholder,\r\n showPoweredBy,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n}) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n // Determine the API base URL\r\n const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\r\n\r\n const {\r\n messages,\r\n isLoading,\r\n isConnected,\r\n config,\r\n error,\r\n sendMessage,\r\n retry\r\n } = useChatWidget({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl: baseUrl,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n });\r\n\r\n // Merge props with fetched config (props take precedence)\r\n const mergedConfig = config ? {\r\n ...config,\r\n position: position || config.position,\r\n primaryColor: primaryColor || config.primaryColor,\r\n greeting: greeting || config.greeting,\r\n placeholder: placeholder || config.placeholder,\r\n showPoweredBy: showPoweredBy !== undefined ? showPoweredBy : config.showPoweredBy\r\n } : null;\r\n\r\n const handleToggle = () => {\r\n setIsOpen(prev => !prev);\r\n };\r\n\r\n const handleClose = () => {\r\n setIsOpen(false);\r\n };\r\n\r\n // Show error state in the window if there's an error\r\n if (error && isOpen) {\r\n return (\r\n <div className=\"rag-chat-widget\">\r\n <ChatBubble\r\n isOpen={isOpen}\r\n onClick={handleToggle}\r\n primaryColor={primaryColor || '#007bff'}\r\n position={position || 'bottom-right'}\r\n />\r\n <div className={`rag-chat-window ${position || 'bottom-right'}`}>\r\n <div className=\"rag-chat-header\" style={{ backgroundColor: primaryColor || '#007bff' }}>\r\n <h3 className=\"rag-chat-header-title\">Chat</h3>\r\n <button className=\"rag-chat-header-close\" onClick={handleClose} type=\"button\">\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\r\n />\r\n </svg>\r\n </button>\r\n </div>\r\n <div className=\"rag-chat-error\">\r\n <p className=\"rag-chat-error-message\">\r\n {error.message || 'Unable to connect. Please try again.'}\r\n </p>\r\n <button className=\"rag-chat-error-retry\" onClick={retry} type=\"button\">\r\n Retry\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"rag-chat-widget\">\r\n <ChatBubble\r\n isOpen={isOpen}\r\n onClick={handleToggle}\r\n primaryColor={mergedConfig?.primaryColor || primaryColor || '#007bff'}\r\n position={mergedConfig?.position || position || 'bottom-right'}\r\n />\r\n {mergedConfig && (\r\n <ChatWindow\r\n isOpen={isOpen}\r\n onClose={handleClose}\r\n config={mergedConfig}\r\n messages={messages}\r\n isLoading={isLoading}\r\n onSendMessage={sendMessage}\r\n />\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default ChatWidget;\r\n","import React, { createContext, useContext, useMemo } from 'react';\r\nimport type { ChatWidgetProps, WidgetConfig, Message } from '../types';\r\nimport { useChatWidget } from '../hooks/useChatWidget';\r\n\r\ninterface ChatWidgetContextValue {\r\n messages: Message[];\r\n isLoading: boolean;\r\n isConnected: boolean;\r\n config: WidgetConfig | null;\r\n error: Error | null;\r\n sendMessage: (content: string) => Promise<void>;\r\n clearMessages: () => void;\r\n retry: () => void;\r\n}\r\n\r\nconst ChatWidgetContext = createContext<ChatWidgetContextValue | null>(null);\r\n\r\nexport interface ChatWidgetProviderProps extends Omit<ChatWidgetProps, 'position' | 'primaryColor' | 'greeting' | 'placeholder' | 'showPoweredBy'> {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const ChatWidgetProvider: React.FC<ChatWidgetProviderProps> = ({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl = '',\r\n onError,\r\n onMessageSent,\r\n onMessageReceived,\r\n children\r\n}) => {\r\n const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\r\n\r\n const chatWidget = useChatWidget({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl: baseUrl,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n });\r\n\r\n const value = useMemo(() => ({\r\n messages: chatWidget.messages,\r\n isLoading: chatWidget.isLoading,\r\n isConnected: chatWidget.isConnected,\r\n config: chatWidget.config,\r\n error: chatWidget.error,\r\n sendMessage: chatWidget.sendMessage,\r\n clearMessages: chatWidget.clearMessages,\r\n retry: chatWidget.retry\r\n }), [chatWidget]);\r\n\r\n return (\r\n <ChatWidgetContext.Provider value={value}>\r\n {children}\r\n </ChatWidgetContext.Provider>\r\n );\r\n};\r\n\r\nexport const useChatWidgetContext = (): ChatWidgetContextValue => {\r\n const context = useContext(ChatWidgetContext);\r\n if (!context) {\r\n throw new Error('useChatWidgetContext must be used within a ChatWidgetProvider');\r\n }\r\n return context;\r\n};\r\n\r\nexport default ChatWidgetProvider;\r\n"],"names":["useChatWidget","options","apiKey","widgetId","apiBaseUrl","onError","onMessageSent","onMessageReceived","messages","setMessages","useState","isLoading","setIsLoading","isConnected","setIsConnected","config","setConfig","error","setError","session","setSession","abortControllerRef","useRef","useEffect","fetchConfig","current","abort","useCallback","async","response","fetch","headers","ok","Error","status","result","json","data","message","err","createSession","method","sendMessage","content","trim","AbortController","userMessage","id","Date","now","role","timestamp","prev","currentSession","expiresAt","assistantMessageId","assistantMessage","isStreaming","sessionId","Accept","body","JSON","stringify","signal","reader","_a","getReader","decoder","TextDecoder","fullContent","done","value","read","lines","decode","stream","split","line","startsWith","parse","slice","type","map","msg","sources","finalMessage","_b","name","filter","clearMessages","retry","ChatIcon","_jsxs","className","viewBox","xmlns","children","_jsx","d","CloseIcon","ChatBubble","isOpen","onClick","primaryColor","position","unreadCount","style","backgroundColor","fill","SendIcon","LoadingDots","MessageBubble","length","source","index","title","ChatWindow","onClose","onSendMessage","inputValue","setInputValue","messagesEndRef","inputRef","scrollIntoView","behavior","focus","handleSubmit","e","preventDefault","uspText","greeting","ref","onSubmit","onChange","target","onKeyDown","key","shiftKey","placeholder","rows","maxLength","allowedMessageLength","disabled","showPoweredBy","href","rel","css","insertAt","document","head","getElementsByTagName","createElement","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","ChatWidget","setIsOpen","baseUrl","window","location","origin","mergedConfig","undefined","handleToggle","handleClose","ChatWidgetContext","createContext","chatWidget","useMemo","Provider","context","useContext"],"mappings":"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","x_google_ignoreList":[3]}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/hooks/useChatWidget.ts","../src/hooks/useViewNavigation.ts","../src/components/ChatBubble.tsx","../src/components/home/HeaderSection.tsx","../src/components/home/StartChatCard.tsx","../src/components/home/TicketCategoryList.tsx","../src/components/home/BookmarksRow.tsx","../src/components/views/HomeView.tsx","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ChatWidget.tsx","../src/components/ChatWindow.tsx","../src/providers/ChatWidgetProvider.tsx"],"sourcesContent":["import { useState, useCallback, useRef, useEffect } from 'react';\r\nimport type { Message, WidgetConfig, ChatSession, ApiResponse } from '../types';\r\n\r\ninterface UseChatWidgetOptions {\r\n apiKey: string;\r\n widgetId: string;\r\n apiBaseUrl: string;\r\n onError?: (error: Error) => void;\r\n onMessageSent?: (message: string) => void;\r\n onMessageReceived?: (message: Message) => void;\r\n}\r\n\r\ninterface UseChatWidgetReturn {\r\n messages: Message[];\r\n isLoading: boolean;\r\n isConnected: boolean;\r\n config: WidgetConfig | null;\r\n error: Error | null;\r\n sendMessage: (content: string) => Promise<void>;\r\n clearMessages: () => void;\r\n retry: () => void;\r\n}\r\n\r\nexport function useChatWidget(options: UseChatWidgetOptions): UseChatWidgetReturn {\r\n const { apiKey, widgetId, apiBaseUrl, onError, onMessageSent, onMessageReceived } = options;\r\n\r\n const [messages, setMessages] = useState<Message[]>([]);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [isConnected, setIsConnected] = useState(false);\r\n const [config, setConfig] = useState<WidgetConfig | null>(null);\r\n const [error, setError] = useState<Error | null>(null);\r\n const [session, setSession] = useState<ChatSession | null>(null);\r\n\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n // Fetch widget configuration on mount\r\n useEffect(() => {\r\n fetchConfig();\r\n return () => {\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n };\r\n }, [apiKey, widgetId]);\r\n\r\n const fetchConfig = useCallback(async () => {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/config`, {\r\n headers: {\r\n 'X-API-Key': apiKey\r\n }\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch config: ${response.status}`);\r\n }\r\n\r\n const result: ApiResponse<WidgetConfig> = await response.json();\r\n\r\n if (result.status === 'success' && result.data) {\r\n setConfig(result.data);\r\n setIsConnected(true);\r\n setError(null);\r\n } else {\r\n throw new Error(result.message || 'Failed to load widget configuration');\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Unknown error');\r\n setError(error);\r\n setIsConnected(false);\r\n onError?.(error);\r\n }\r\n }, [apiKey, widgetId, apiBaseUrl, onError]);\r\n\r\n const createSession = useCallback(async (): Promise<ChatSession> => {\r\n const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/sessions`, {\r\n method: 'POST',\r\n headers: {\r\n 'X-API-Key': apiKey,\r\n 'Content-Type': 'application/json'\r\n }\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to create session: ${response.status}`);\r\n }\r\n\r\n const result: ApiResponse<ChatSession> = await response.json();\r\n\r\n if (result.status === 'success' && result.data) {\r\n return result.data;\r\n }\r\n\r\n throw new Error(result.message || 'Failed to create session');\r\n }, [apiKey, widgetId, apiBaseUrl]);\r\n\r\n const sendMessage = useCallback(async (content: string) => {\r\n if (!content.trim() || isLoading) return;\r\n\r\n // Cancel any ongoing request\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n abortControllerRef.current = new AbortController();\r\n\r\n const userMessage: Message = {\r\n id: `msg-${Date.now()}`,\r\n role: 'user',\r\n content: content.trim(),\r\n timestamp: new Date()\r\n };\r\n\r\n setMessages(prev => [...prev, userMessage]);\r\n setIsLoading(true);\r\n setError(null);\r\n onMessageSent?.(content);\r\n\r\n try {\r\n // Ensure we have a session\r\n let currentSession = session;\r\n if (!currentSession || new Date() > new Date(currentSession.expiresAt)) {\r\n currentSession = await createSession();\r\n setSession(currentSession);\r\n }\r\n\r\n // Create placeholder for assistant message\r\n const assistantMessageId = `msg-${Date.now()}-assistant`;\r\n const assistantMessage: Message = {\r\n id: assistantMessageId,\r\n role: 'assistant',\r\n content: '',\r\n timestamp: new Date(),\r\n isStreaming: true\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n\r\n // Send message with SSE streaming\r\n const response = await fetch(\r\n `${apiBaseUrl}/api/v1/widget/${widgetId}/sessions/${currentSession.sessionId}/messages`,\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'X-API-Key': apiKey,\r\n 'Content-Type': 'application/json',\r\n 'Accept': 'text/event-stream'\r\n },\r\n body: JSON.stringify({ message: content }),\r\n signal: abortControllerRef.current.signal\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to send message: ${response.status}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n const decoder = new TextDecoder();\r\n let fullContent = '';\r\n\r\n if (reader) {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n const chunk = decoder.decode(value, { stream: true });\r\n const lines = chunk.split('\\n');\r\n\r\n for (const line of lines) {\r\n if (line.startsWith('data: ')) {\r\n try {\r\n const data = JSON.parse(line.slice(6));\r\n\r\n if (data.type === 'chunk') {\r\n fullContent += data.content;\r\n setMessages(prev =>\r\n prev.map(msg =>\r\n msg.id === assistantMessageId\r\n ? { ...msg, content: fullContent }\r\n : msg\r\n )\r\n );\r\n } else if (data.type === 'done') {\r\n setMessages(prev =>\r\n prev.map(msg =>\r\n msg.id === assistantMessageId\r\n ? { ...msg, isStreaming: false, sources: data.sources }\r\n : msg\r\n )\r\n );\r\n\r\n const finalMessage: Message = {\r\n id: assistantMessageId,\r\n role: 'assistant',\r\n content: fullContent,\r\n timestamp: new Date(),\r\n sources: data.sources\r\n };\r\n onMessageReceived?.(finalMessage);\r\n }\r\n } catch {\r\n // Ignore parse errors for partial SSE data\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n if ((err as Error).name === 'AbortError') {\r\n // Request was cancelled, ignore\r\n return;\r\n }\r\n\r\n const error = err instanceof Error ? err : new Error('Failed to send message');\r\n setError(error);\r\n onError?.(error);\r\n\r\n // Remove the incomplete assistant message\r\n setMessages(prev => prev.filter(msg => !msg.isStreaming));\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [apiKey, widgetId, apiBaseUrl, session, isLoading, createSession, onError, onMessageSent, onMessageReceived]);\r\n\r\n const clearMessages = useCallback(() => {\r\n setMessages([]);\r\n setSession(null);\r\n }, []);\r\n\r\n const retry = useCallback(() => {\r\n setError(null);\r\n fetchConfig();\r\n }, [fetchConfig]);\r\n\r\n return {\r\n messages,\r\n isLoading,\r\n isConnected,\r\n config,\r\n error,\r\n sendMessage,\r\n clearMessages,\r\n retry\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\nimport type { WidgetView } from '../types';\r\n\r\ninterface ViewNavigationState {\r\n currentView: WidgetView;\r\n previousView: WidgetView | null;\r\n}\r\n\r\nexport interface UseViewNavigationReturn {\r\n currentView: WidgetView;\r\n previousView: WidgetView | null;\r\n canGoBack: boolean;\r\n navigateToChat: () => void;\r\n navigateToHome: () => void;\r\n goBack: () => void;\r\n}\r\n\r\nexport const useViewNavigation = (\r\n initialView: WidgetView = 'home'\r\n): UseViewNavigationReturn => {\r\n const [state, setState] = useState<ViewNavigationState>({\r\n currentView: initialView,\r\n previousView: null,\r\n });\r\n\r\n const navigateToChat = useCallback(() => {\r\n setState((prev) => ({\r\n currentView: 'chat',\r\n previousView: prev.currentView,\r\n }));\r\n }, []);\r\n\r\n const navigateToHome = useCallback(() => {\r\n setState((prev) => ({\r\n currentView: 'home',\r\n previousView: prev.currentView,\r\n }));\r\n }, []);\r\n\r\n const goBack = useCallback(() => {\r\n if (state.currentView !== 'home') {\r\n setState((prev) => ({\r\n currentView: 'home',\r\n previousView: prev.currentView,\r\n }));\r\n }\r\n }, [state.currentView]);\r\n\r\n const canGoBack = state.currentView !== 'home';\r\n\r\n return {\r\n currentView: state.currentView,\r\n previousView: state.previousView,\r\n canGoBack,\r\n navigateToChat,\r\n navigateToHome,\r\n goBack,\r\n };\r\n};\r\n","import React from 'react';\r\nimport type { ChatBubbleProps } from '../types';\r\n\r\nconst ChatIcon: React.FC = () => (\r\n <svg\r\n className=\"rag-chat-bubble-icon\"\r\n viewBox=\"0 0 24 24\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H5.17L4 17.17V4h16v12z\" />\r\n <path d=\"M7 9h10v2H7zm0-3h10v2H7z\" />\r\n </svg>\r\n);\r\n\r\nconst CloseIcon: React.FC = () => (\r\n <svg\r\n className=\"rag-chat-bubble-icon\"\r\n viewBox=\"0 0 24 24\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n);\r\n\r\nexport const ChatBubble: React.FC<ChatBubbleProps> = ({\r\n isOpen,\r\n onClick,\r\n primaryColor = '#007bff',\r\n position = 'bottom-right',\r\n unreadCount = 0\r\n}) => {\r\n return (\r\n <button\r\n className={`rag-chat-bubble ${position}`}\r\n onClick={onClick}\r\n style={{ backgroundColor: primaryColor }}\r\n aria-label={isOpen ? 'Close chat' : 'Open chat'}\r\n type=\"button\"\r\n >\r\n {isOpen ? <CloseIcon /> : <ChatIcon />}\r\n {!isOpen && unreadCount > 0 && (\r\n <span className=\"rag-chat-bubble-badge\">\r\n {unreadCount > 9 ? '9+' : unreadCount}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n};\r\n\r\nexport default ChatBubble;\r\n","import React from 'react';\r\n\r\nexport interface HeaderSectionProps {\r\n greeting: string;\r\n logoUrl?: string;\r\n}\r\n\r\nexport const HeaderSection: React.FC<HeaderSectionProps> = ({\r\n greeting,\r\n logoUrl,\r\n}) => {\r\n return (\r\n <div className=\"rag-home-header\">\r\n {logoUrl && (\r\n <img\r\n src={logoUrl}\r\n alt=\"Logo\"\r\n className=\"rag-home-logo\"\r\n />\r\n )}\r\n <h2 className=\"rag-home-greeting\">{greeting}</h2>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\n\r\nexport interface StartChatCardProps {\r\n onStartChat: () => void;\r\n subtitle?: string;\r\n}\r\n\r\nconst ChatIcon: React.FC = () => (\r\n <svg\r\n data-testid=\"chat-icon\"\r\n className=\"rag-start-chat-card__icon\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n);\r\n\r\nconst ArrowIcon: React.FC = () => (\r\n <svg\r\n data-testid=\"arrow-icon\"\r\n className=\"rag-start-chat-card__arrow\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M9 18l6-6-6-6\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n);\r\n\r\nexport const StartChatCard = React.forwardRef<HTMLButtonElement, StartChatCardProps>(({\r\n onStartChat,\r\n subtitle,\r\n}, ref) => {\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n onStartChat();\r\n }\r\n };\r\n\r\n return (\r\n <button\r\n ref={ref}\r\n type=\"button\"\r\n className=\"rag-start-chat-card\"\r\n onClick={onStartChat}\r\n onKeyDown={handleKeyDown}\r\n aria-label=\"Start new chat conversation\"\r\n >\r\n <ChatIcon />\r\n <div className=\"rag-start-chat-card__content\">\r\n <div className=\"rag-start-chat-card__title\">Start new chat</div>\r\n {subtitle && (\r\n <div className=\"rag-start-chat-card__subtitle\">{subtitle}</div>\r\n )}\r\n </div>\r\n <ArrowIcon />\r\n </button>\r\n );\r\n});\r\n\r\n// Display name for debugging\r\nStartChatCard.displayName = 'StartChatCard';\r\n","import React from 'react';\r\nimport type { TicketCategory } from '../../types';\r\n\r\nexport interface TicketCategoryListProps {\r\n categories: TicketCategory[];\r\n onCategoryClick: (categoryId: string) => void;\r\n}\r\n\r\nconst ChevronIcon: React.FC = () => (\r\n <svg\r\n className=\"rag-ticket-category__chevron\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M9 18l6-6-6-6\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n);\r\n\r\nexport const TicketCategoryList: React.FC<TicketCategoryListProps> = ({\r\n categories,\r\n onCategoryClick,\r\n}) => {\r\n const enabledCategories = categories.filter((cat) => cat.enabled);\r\n\r\n if (enabledCategories.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div className=\"rag-ticket-section\">\r\n <div className=\"rag-ticket-section__title\">Submit a ticket</div>\r\n <div className=\"rag-ticket-list\">\r\n {enabledCategories.map((category) => (\r\n <button\r\n key={category.id}\r\n type=\"button\"\r\n className=\"rag-ticket-category\"\r\n onClick={() => onCategoryClick(category.id)}\r\n aria-label={`Submit ${category.label} ticket`}\r\n >\r\n <span className=\"rag-ticket-category__icon\">{category.icon}</span>\r\n <span className=\"rag-ticket-category__label\">{category.label}</span>\r\n <ChevronIcon />\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { Bookmark } from '../../types';\r\n\r\nexport interface BookmarksRowProps {\r\n bookmarks: Bookmark[];\r\n}\r\n\r\nexport const BookmarksRow: React.FC<BookmarksRowProps> = ({ bookmarks }) => {\r\n if (bookmarks.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <nav className=\"rag-bookmarks-section\" role=\"navigation\" aria-label=\"Quick links\">\r\n <div className=\"rag-bookmarks-section__title\" id=\"bookmarks-title\">Bookmarks</div>\r\n <div className=\"rag-bookmarks-row\" aria-labelledby=\"bookmarks-title\">\r\n {bookmarks.map((bookmark) => (\r\n <a\r\n key={bookmark.id}\r\n href={bookmark.url}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"rag-bookmark\"\r\n aria-label={`${bookmark.label} - opens in new tab`}\r\n >\r\n <span className=\"rag-bookmark__icon\" aria-hidden=\"true\">{bookmark.icon}</span>\r\n <span className=\"rag-bookmark__label\">{bookmark.label}</span>\r\n </a>\r\n ))}\r\n </div>\r\n </nav>\r\n );\r\n};\r\n","import React, { useEffect, useRef } from 'react';\r\nimport type { WidgetConfig } from '../../types';\r\nimport { HeaderSection } from '../home/HeaderSection';\r\nimport { StartChatCard } from '../home/StartChatCard';\r\nimport { TicketCategoryList } from '../home/TicketCategoryList';\r\nimport { BookmarksRow } from '../home/BookmarksRow';\r\n\r\nexport interface HomeViewProps {\r\n config: WidgetConfig;\r\n onStartChat: () => void;\r\n onTicketCategoryClick?: (categoryId: string) => void;\r\n autoFocus?: boolean;\r\n}\r\n\r\nexport const HomeView: React.FC<HomeViewProps> = ({\r\n config,\r\n onStartChat,\r\n onTicketCategoryClick,\r\n autoFocus = false,\r\n}) => {\r\n const homeConfig = config.homeView;\r\n const startChatRef = useRef<HTMLButtonElement>(null);\r\n\r\n // Auto-focus first interactive element when autoFocus is enabled\r\n useEffect(() => {\r\n if (autoFocus && startChatRef.current) {\r\n startChatRef.current.focus();\r\n }\r\n }, [autoFocus]);\r\n\r\n // Don't render if home view is not enabled or missing\r\n if (!homeConfig?.enabled) {\r\n return null;\r\n }\r\n\r\n // Use homeView greeting, fallback to widget greeting\r\n const greeting = homeConfig.greeting || config.greeting;\r\n\r\n const handleTicketCategoryClick = (categoryId: string) => {\r\n if (onTicketCategoryClick) {\r\n onTicketCategoryClick(categoryId);\r\n } else {\r\n // Default behavior: log \"Coming soon\" message\r\n console.log('Ticket category clicked (Coming soon):', categoryId);\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"rag-home-view\" role=\"region\" aria-label=\"Help Center Home\">\r\n <HeaderSection\r\n greeting={greeting}\r\n logoUrl={homeConfig.logoUrl}\r\n />\r\n\r\n {homeConfig.showStartChat && (\r\n <StartChatCard\r\n ref={startChatRef}\r\n onStartChat={onStartChat}\r\n subtitle=\"How can we help you?\"\r\n />\r\n )}\r\n\r\n {homeConfig.ticketCategories && homeConfig.ticketCategories.length > 0 && (\r\n <TicketCategoryList\r\n categories={homeConfig.ticketCategories}\r\n onCategoryClick={handleTicketCategoryClick}\r\n />\r\n )}\r\n\r\n {homeConfig.bookmarks && homeConfig.bookmarks.length > 0 && (\r\n <BookmarksRow bookmarks={homeConfig.bookmarks} />\r\n )}\r\n\r\n {config.showPoweredBy && (\r\n <div className=\"rag-home-footer\">\r\n Powered by <a href=\"https://rag-widget.com\" target=\"_blank\" rel=\"noopener noreferrer\">RAG Widget</a>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import React, { useState, useEffect } from 'react';\r\nimport { useChatWidget } from '../hooks/useChatWidget';\r\nimport { useViewNavigation } from '../hooks/useViewNavigation';\r\nimport { ChatBubble } from './ChatBubble';\r\nimport { ChatWindow } from './ChatWindow';\r\nimport { HomeView } from './views/HomeView';\r\nimport type { ChatWidgetProps, WidgetView } from '../types';\r\nimport '../styles/widget.css';\r\n\r\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl = '',\r\n position,\r\n primaryColor,\r\n greeting,\r\n placeholder,\r\n showPoweredBy,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n}) => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n // Determine the API base URL\r\n const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\r\n\r\n const {\r\n messages,\r\n isLoading,\r\n config,\r\n error,\r\n sendMessage,\r\n retry\r\n } = useChatWidget({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl: baseUrl,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n });\r\n\r\n // Merge props with fetched config (props take precedence)\r\n const mergedConfig = config ? {\r\n ...config,\r\n position: position || config.position,\r\n primaryColor: primaryColor || config.primaryColor,\r\n greeting: greeting || config.greeting,\r\n placeholder: placeholder || config.placeholder,\r\n showPoweredBy: showPoweredBy !== undefined ? showPoweredBy : config.showPoweredBy\r\n } : null;\r\n\r\n // Determine initial view based on home view configuration\r\n const homeViewEnabled = mergedConfig?.homeView?.enabled ?? false;\r\n const initialView: WidgetView = homeViewEnabled ? 'home' : 'chat';\r\n\r\n const {\r\n currentView,\r\n canGoBack,\r\n navigateToChat,\r\n navigateToHome,\r\n } = useViewNavigation(initialView);\r\n\r\n // Update view when config loads - fixes race condition where config isn't\r\n // available on first render but homeView.enabled is true\r\n useEffect(() => {\r\n if (mergedConfig?.homeView?.enabled && currentView === 'chat') {\r\n navigateToHome();\r\n }\r\n }, [mergedConfig?.homeView?.enabled]);\r\n\r\n const handleToggle = () => {\r\n setIsOpen(prev => !prev);\r\n };\r\n\r\n const handleClose = () => {\r\n setIsOpen(false);\r\n };\r\n\r\n const handleStartChat = () => {\r\n navigateToChat();\r\n };\r\n\r\n const handleBack = () => {\r\n navigateToHome();\r\n };\r\n\r\n const effectivePrimaryColor = mergedConfig?.primaryColor || primaryColor || '#007bff';\r\n const effectivePosition = mergedConfig?.position || position || 'bottom-right';\r\n\r\n // Show error state in the window if there's an error\r\n if (error && isOpen) {\r\n return (\r\n <div className=\"rag-chat-widget\">\r\n <ChatBubble\r\n isOpen={isOpen}\r\n onClick={handleToggle}\r\n primaryColor={effectivePrimaryColor}\r\n position={effectivePosition}\r\n />\r\n <div className={`rag-chat-window ${effectivePosition}`}>\r\n <div className=\"rag-chat-header\" style={{ backgroundColor: effectivePrimaryColor }}>\r\n <h3 className=\"rag-chat-header-title\">Chat</h3>\r\n <button\r\n className=\"rag-chat-header-close\"\r\n onClick={handleClose}\r\n type=\"button\"\r\n aria-label=\"Close chat\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\r\n />\r\n </svg>\r\n </button>\r\n </div>\r\n <div className=\"rag-chat-error\">\r\n <p className=\"rag-chat-error-message\">\r\n {error.message || 'Unable to connect. Please try again.'}\r\n </p>\r\n <button className=\"rag-chat-error-retry\" onClick={retry} type=\"button\">\r\n Retry\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Determine which view to render\r\n const shouldShowHomeView = currentView === 'home' && homeViewEnabled && mergedConfig;\r\n const shouldShowChatView = currentView === 'chat' || !homeViewEnabled;\r\n\r\n return (\r\n <div className=\"rag-chat-widget\">\r\n <ChatBubble\r\n isOpen={isOpen}\r\n onClick={handleToggle}\r\n primaryColor={effectivePrimaryColor}\r\n position={effectivePosition}\r\n />\r\n {isOpen && mergedConfig && (\r\n <div\r\n className={`rag-chat-window ${effectivePosition}`}\r\n style={{ '--rag-primary-color': effectivePrimaryColor } as React.CSSProperties}\r\n >\r\n {/* Header */}\r\n <div className=\"rag-chat-header\" style={{ backgroundColor: effectivePrimaryColor }}>\r\n <div className=\"rag-chat-header-left\">\r\n {canGoBack && (\r\n <button\r\n className=\"rag-chat-header-back\"\r\n onClick={handleBack}\r\n type=\"button\"\r\n aria-label=\"Back to home\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z\"\r\n />\r\n </svg>\r\n </button>\r\n )}\r\n <h3 className=\"rag-chat-header-title\">{mergedConfig.name || 'Chat'}</h3>\r\n </div>\r\n <button\r\n className=\"rag-chat-header-close\"\r\n onClick={handleClose}\r\n aria-label=\"Close chat\"\r\n type=\"button\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\r\n />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n {/* View Container */}\r\n <div className=\"rag-view-container\">\r\n {shouldShowHomeView && (\r\n <HomeView\r\n config={mergedConfig}\r\n onStartChat={handleStartChat}\r\n />\r\n )}\r\n {shouldShowChatView && (\r\n <ChatWindowContent\r\n config={mergedConfig}\r\n messages={messages}\r\n isLoading={isLoading}\r\n onSendMessage={sendMessage}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n// Extracted chat window content (without header)\r\ninterface ChatWindowContentProps {\r\n config: NonNullable<ReturnType<typeof useChatWidget>['config']>;\r\n messages: ReturnType<typeof useChatWidget>['messages'];\r\n isLoading: boolean;\r\n onSendMessage: (message: string) => Promise<void>;\r\n}\r\n\r\nconst ChatWindowContent: React.FC<ChatWindowContentProps> = ({\r\n config,\r\n messages,\r\n isLoading,\r\n onSendMessage,\r\n}) => {\r\n const [inputValue, setInputValue] = React.useState('');\r\n const messagesEndRef = React.useRef<HTMLDivElement>(null);\r\n const inputRef = React.useRef<HTMLTextAreaElement>(null);\r\n\r\n // Scroll to bottom when new messages arrive\r\n React.useEffect(() => {\r\n if (messagesEndRef.current && typeof messagesEndRef.current.scrollIntoView === 'function') {\r\n messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });\r\n }\r\n }, [messages]);\r\n\r\n // Focus input when content mounts\r\n React.useEffect(() => {\r\n inputRef.current?.focus();\r\n }, []);\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (inputValue.trim() && !isLoading) {\r\n onSendMessage(inputValue.trim());\r\n setInputValue('');\r\n }\r\n };\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n handleSubmit(e);\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n <div className=\"rag-chat-messages\">\r\n {messages.length === 0 && (config.uspText || config.greeting) && (\r\n <div className=\"rag-chat-greeting\">\r\n {config.uspText && (\r\n <p className=\"rag-chat-usp-text\">{config.uspText}</p>\r\n )}\r\n {config.greeting && (\r\n <p className=\"rag-chat-greeting-text\">{config.greeting}</p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {messages.map(message => (\r\n <div key={message.id} className={`rag-chat-message ${message.role}`}>\r\n {message.isStreaming && !message.content ? (\r\n <div className=\"rag-chat-loading\">\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n </div>\r\n ) : (\r\n <p className=\"rag-chat-message-content\">{message.content}</p>\r\n )}\r\n {message.sources && message.sources.length > 0 && (\r\n <div className=\"rag-chat-message-sources\">\r\n <div className=\"rag-chat-message-sources-title\">Sources:</div>\r\n {message.sources.map((source, index) => (\r\n <div key={index} className=\"rag-chat-message-source\">\r\n {source.title}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n\r\n <div ref={messagesEndRef} />\r\n </div>\r\n\r\n <form className=\"rag-chat-input-container\" onSubmit={handleSubmit}>\r\n <textarea\r\n ref={inputRef}\r\n className=\"rag-chat-input\"\r\n value={inputValue}\r\n onChange={e => setInputValue(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n placeholder={config.placeholder || 'Type a message...'}\r\n rows={1}\r\n maxLength={config.allowedMessageLength || 2000}\r\n disabled={isLoading}\r\n />\r\n <button\r\n type=\"submit\"\r\n className=\"rag-chat-send-button\"\r\n disabled={!inputValue.trim() || isLoading}\r\n style={{ backgroundColor: config.primaryColor }}\r\n aria-label=\"Send message\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\r\n </svg>\r\n </button>\r\n </form>\r\n\r\n {config.showPoweredBy && (\r\n <div className=\"rag-chat-powered-by\">\r\n Powered by <a href=\"https://rag-widget.com\" target=\"_blank\" rel=\"noopener noreferrer\">RAG Widget</a>\r\n </div>\r\n )}\r\n </>\r\n );\r\n};\r\n\r\nexport default ChatWidget;\r\n","import React, { useState, useRef, useEffect } from 'react';\r\nimport type { ChatWindowProps, Message } from '../types';\r\n\r\nconst CloseIcon: React.FC = () => (\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\r\n />\r\n </svg>\r\n);\r\n\r\nconst SendIcon: React.FC = () => (\r\n <svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\r\n </svg>\r\n);\r\n\r\nconst LoadingDots: React.FC = () => (\r\n <div className=\"rag-chat-loading\">\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n <div className=\"rag-chat-loading-dot\" />\r\n </div>\r\n);\r\n\r\ninterface MessageBubbleProps {\r\n message: Message;\r\n}\r\n\r\nconst MessageBubble: React.FC<MessageBubbleProps> = ({ message }) => (\r\n <div className={`rag-chat-message ${message.role}`}>\r\n {message.isStreaming && !message.content ? (\r\n <LoadingDots />\r\n ) : (\r\n <p className=\"rag-chat-message-content\">{message.content}</p>\r\n )}\r\n {message.sources && message.sources.length > 0 && (\r\n <div className=\"rag-chat-message-sources\">\r\n <div className=\"rag-chat-message-sources-title\">Sources:</div>\r\n {message.sources.map((source, index) => (\r\n <div key={index} className=\"rag-chat-message-source\">\r\n {source.title}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n);\r\n\r\nexport const ChatWindow: React.FC<ChatWindowProps> = ({\r\n isOpen,\r\n onClose,\r\n config,\r\n messages,\r\n isLoading,\r\n onSendMessage\r\n}) => {\r\n const [inputValue, setInputValue] = useState('');\r\n const messagesEndRef = useRef<HTMLDivElement>(null);\r\n const inputRef = useRef<HTMLTextAreaElement>(null);\r\n\r\n // Scroll to bottom when new messages arrive\r\n useEffect(() => {\r\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\r\n }, [messages]);\r\n\r\n // Focus input when window opens\r\n useEffect(() => {\r\n if (isOpen) {\r\n inputRef.current?.focus();\r\n }\r\n }, [isOpen]);\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (inputValue.trim() && !isLoading) {\r\n onSendMessage(inputValue.trim());\r\n setInputValue('');\r\n }\r\n };\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n handleSubmit(e);\r\n }\r\n };\r\n\r\n if (!isOpen) return null;\r\n\r\n const position = config?.position || 'bottom-right';\r\n const primaryColor = config?.primaryColor || '#007bff';\r\n\r\n return (\r\n <div\r\n className={`rag-chat-window ${position}`}\r\n style={{ '--rag-primary-color': primaryColor } as React.CSSProperties}\r\n >\r\n <div className=\"rag-chat-header\" style={{ backgroundColor: primaryColor }}>\r\n <h3 className=\"rag-chat-header-title\">{config?.name || 'Chat'}</h3>\r\n <button\r\n className=\"rag-chat-header-close\"\r\n onClick={onClose}\r\n aria-label=\"Close chat\"\r\n type=\"button\"\r\n >\r\n <CloseIcon />\r\n </button>\r\n </div>\r\n\r\n <div className=\"rag-chat-messages\">\r\n {messages.length === 0 && (config?.uspText || config?.greeting) && (\r\n <div className=\"rag-chat-greeting\">\r\n {config?.uspText && (\r\n <p className=\"rag-chat-usp-text\">{config.uspText}</p>\r\n )}\r\n {config?.greeting && (\r\n <p className=\"rag-chat-greeting-text\">{config.greeting}</p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {messages.map(message => (\r\n <MessageBubble key={message.id} message={message} />\r\n ))}\r\n\r\n <div ref={messagesEndRef} />\r\n </div>\r\n\r\n <form className=\"rag-chat-input-container\" onSubmit={handleSubmit}>\r\n <textarea\r\n ref={inputRef}\r\n className=\"rag-chat-input\"\r\n value={inputValue}\r\n onChange={e => setInputValue(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n placeholder={config?.placeholder || 'Type a message...'}\r\n rows={1}\r\n maxLength={config?.allowedMessageLength || 2000}\r\n disabled={isLoading}\r\n />\r\n <button\r\n type=\"submit\"\r\n className=\"rag-chat-send-button\"\r\n disabled={!inputValue.trim() || isLoading}\r\n style={{ backgroundColor: primaryColor }}\r\n aria-label=\"Send message\"\r\n >\r\n <SendIcon />\r\n </button>\r\n </form>\r\n\r\n {config?.showPoweredBy && (\r\n <div className=\"rag-chat-powered-by\">\r\n Powered by <a href=\"https://rag-widget.com\" target=\"_blank\" rel=\"noopener noreferrer\">RAG Widget</a>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default ChatWindow;\r\n","import React, { createContext, useContext, useMemo } from 'react';\r\nimport type { ChatWidgetProps, WidgetConfig, Message, WidgetView } from '../types';\r\nimport { useChatWidget } from '../hooks/useChatWidget';\r\nimport { useViewNavigation } from '../hooks/useViewNavigation';\r\n\r\ninterface ChatWidgetContextValue {\r\n // Chat state\r\n messages: Message[];\r\n isLoading: boolean;\r\n isConnected: boolean;\r\n config: WidgetConfig | null;\r\n error: Error | null;\r\n sendMessage: (content: string) => Promise<void>;\r\n clearMessages: () => void;\r\n retry: () => void;\r\n // View navigation\r\n currentView: WidgetView;\r\n previousView: WidgetView | null;\r\n canGoBack: boolean;\r\n navigateToChat: () => void;\r\n navigateToHome: () => void;\r\n goBack: () => void;\r\n}\r\n\r\nconst ChatWidgetContext = createContext<ChatWidgetContextValue | null>(null);\r\n\r\nexport interface ChatWidgetProviderProps extends Omit<ChatWidgetProps, 'position' | 'primaryColor' | 'greeting' | 'placeholder' | 'showPoweredBy'> {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const ChatWidgetProvider: React.FC<ChatWidgetProviderProps> = ({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl = '',\r\n onError,\r\n onMessageSent,\r\n onMessageReceived,\r\n children\r\n}) => {\r\n const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\r\n\r\n const chatWidget = useChatWidget({\r\n apiKey,\r\n widgetId,\r\n apiBaseUrl: baseUrl,\r\n onError,\r\n onMessageSent,\r\n onMessageReceived\r\n });\r\n\r\n // Determine initial view based on config\r\n // If homeView is enabled, start with home; otherwise start with chat\r\n const homeViewEnabled = chatWidget.config?.homeView?.enabled ?? false;\r\n const initialView: WidgetView = homeViewEnabled ? 'home' : 'chat';\r\n\r\n const viewNavigation = useViewNavigation(initialView);\r\n\r\n const value = useMemo(() => ({\r\n // Chat state\r\n messages: chatWidget.messages,\r\n isLoading: chatWidget.isLoading,\r\n isConnected: chatWidget.isConnected,\r\n config: chatWidget.config,\r\n error: chatWidget.error,\r\n sendMessage: chatWidget.sendMessage,\r\n clearMessages: chatWidget.clearMessages,\r\n retry: chatWidget.retry,\r\n // View navigation\r\n currentView: viewNavigation.currentView,\r\n previousView: viewNavigation.previousView,\r\n canGoBack: viewNavigation.canGoBack,\r\n navigateToChat: viewNavigation.navigateToChat,\r\n navigateToHome: viewNavigation.navigateToHome,\r\n goBack: viewNavigation.goBack,\r\n }), [chatWidget, viewNavigation]);\r\n\r\n return (\r\n <ChatWidgetContext.Provider value={value}>\r\n {children}\r\n </ChatWidgetContext.Provider>\r\n );\r\n};\r\n\r\nexport const useChatWidgetContext = (): ChatWidgetContextValue => {\r\n const context = useContext(ChatWidgetContext);\r\n if (!context) {\r\n throw new Error('useChatWidgetContext must be used within a ChatWidgetProvider');\r\n }\r\n return context;\r\n};\r\n\r\nexport default ChatWidgetProvider;\r\n"],"names":["useChatWidget","options","apiKey","widgetId","apiBaseUrl","onError","onMessageSent","onMessageReceived","messages","setMessages","useState","isLoading","setIsLoading","isConnected","setIsConnected","config","setConfig","error","setError","session","setSession","abortControllerRef","useRef","useEffect","fetchConfig","current","abort","useCallback","async","response","fetch","headers","ok","Error","status","result","json","data","message","err","createSession","method","sendMessage","content","trim","AbortController","userMessage","id","Date","now","role","timestamp","prev","currentSession","expiresAt","assistantMessageId","assistantMessage","isStreaming","sessionId","Accept","body","JSON","stringify","signal","reader","_a","getReader","decoder","TextDecoder","fullContent","done","value","read","lines","decode","stream","split","line","startsWith","parse","slice","type","map","msg","sources","finalMessage","_b","name","filter","clearMessages","retry","useViewNavigation","initialView","state","setState","currentView","previousView","navigateToChat","navigateToHome","goBack","canGoBack","ChatIcon","_jsxs","className","viewBox","xmlns","children","_jsx","d","CloseIcon","ChatBubble","isOpen","onClick","primaryColor","position","unreadCount","style","backgroundColor","HeaderSection","greeting","logoUrl","src","alt","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","ArrowIcon","StartChatCard","React","forwardRef","onStartChat","subtitle","ref","onKeyDown","e","key","preventDefault","displayName","ChevronIcon","TicketCategoryList","categories","onCategoryClick","enabledCategories","cat","enabled","length","category","label","icon","BookmarksRow","bookmarks","bookmark","href","url","target","rel","HomeView","onTicketCategoryClick","autoFocus","homeConfig","homeView","startChatRef","focus","showStartChat","ticketCategories","categoryId","console","log","showPoweredBy","css","insertAt","document","head","getElementsByTagName","createElement","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","ChatWidget","placeholder","setIsOpen","baseUrl","window","location","origin","mergedConfig","undefined","homeViewEnabled","_c","handleToggle","handleClose","effectivePrimaryColor","effectivePosition","shouldShowHomeView","shouldShowChatView","ChatWindowContent","onSendMessage","inputValue","setInputValue","messagesEndRef","inputRef","scrollIntoView","behavior","handleSubmit","_Fragment","uspText","source","index","title","onSubmit","onChange","shiftKey","rows","maxLength","allowedMessageLength","disabled","SendIcon","LoadingDots","MessageBubble","ChatWidgetContext","createContext","chatWidget","viewNavigation","useMemo","Provider","onClose","context","useContext"],"mappings":"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","x_google_ignoreList":[8]}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { ChatWidgetProps, WidgetConfig, Message } from '../types';
2
+ import type { ChatWidgetProps, WidgetConfig, Message, WidgetView } from '../types';
3
3
  interface ChatWidgetContextValue {
4
4
  messages: Message[];
5
5
  isLoading: boolean;
@@ -9,6 +9,12 @@ interface ChatWidgetContextValue {
9
9
  sendMessage: (content: string) => Promise<void>;
10
10
  clearMessages: () => void;
11
11
  retry: () => void;
12
+ currentView: WidgetView;
13
+ previousView: WidgetView | null;
14
+ canGoBack: boolean;
15
+ navigateToChat: () => void;
16
+ navigateToHome: () => void;
17
+ goBack: () => void;
12
18
  }
13
19
  export interface ChatWidgetProviderProps extends Omit<ChatWidgetProps, 'position' | 'primaryColor' | 'greeting' | 'placeholder' | 'showPoweredBy'> {
14
20
  children: React.ReactNode;
@@ -0,0 +1 @@
1
+ export {};
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- .rag-chat-widget{--rag-primary-color:#007bff;--rag-bg-color:#fff;--rag-text-color:#333;--rag-border-color:#e0e0e0;--rag-shadow:0 4px 12px rgba(0,0,0,.15);--rag-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,sans-serif;box-sizing:border-box;font-family:var(--rag-font-family);font-size:14px;line-height:1.5}.rag-chat-widget *,.rag-chat-widget :after,.rag-chat-widget :before{box-sizing:inherit}.rag-chat-bubble{align-items:center;background-color:var(--rag-primary-color);border:none;border-radius:50%;box-shadow:var(--rag-shadow);cursor:pointer;display:flex;height:60px;justify-content:center;position:fixed;transition:transform .2s ease,box-shadow .2s ease;width:60px;z-index:9998}.rag-chat-bubble:hover{box-shadow:0 6px 16px rgba(0,0,0,.2);transform:scale(1.05)}.rag-chat-bubble:active{transform:scale(.95)}.rag-chat-bubble.bottom-right{bottom:20px;right:20px}.rag-chat-bubble.bottom-left{bottom:20px;left:20px}.rag-chat-bubble.top-right{right:20px;top:20px}.rag-chat-bubble.top-left{left:20px;top:20px}.rag-chat-bubble-icon{fill:#fff;height:28px;width:28px}.rag-chat-bubble-badge{align-items:center;background-color:#f44;border-radius:10px;color:#fff;display:flex;font-size:12px;font-weight:700;height:20px;justify-content:center;min-width:20px;padding:0 6px;position:absolute;right:-5px;top:-5px}.rag-chat-window{animation:rag-slide-up .3s ease;background-color:var(--rag-bg-color);border-radius:12px;box-shadow:var(--rag-shadow);display:flex;flex-direction:column;height:520px;max-height:80vh;overflow:hidden;position:fixed;width:380px;z-index:9999}@keyframes rag-slide-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.rag-chat-window.bottom-right{bottom:90px;right:20px}.rag-chat-window.bottom-left{bottom:90px;left:20px}.rag-chat-window.top-right{right:20px;top:90px}.rag-chat-window.top-left{left:20px;top:90px}.rag-chat-header{align-items:center;background-color:var(--rag-primary-color);color:#fff;display:flex;justify-content:space-between;padding:16px}.rag-chat-header-title{font-size:16px;font-weight:600;margin:0}.rag-chat-header-close{align-items:center;background:none;border:none;border-radius:4px;color:#fff;cursor:pointer;display:flex;justify-content:center;padding:4px;transition:background-color .2s ease}.rag-chat-header-close:hover{background-color:hsla(0,0%,100%,.2)}.rag-chat-header-close svg{height:20px;width:20px}.rag-chat-messages{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.rag-chat-message{word-wrap:break-word;border-radius:12px;max-width:85%;padding:10px 14px}.rag-chat-message.user{align-self:flex-end;background-color:var(--rag-primary-color);border-bottom-right-radius:4px;color:#fff}.rag-chat-message.assistant{align-self:flex-start;background-color:#f0f0f0;border-bottom-left-radius:4px;color:var(--rag-text-color)}.rag-chat-message-content{margin:0;white-space:pre-wrap}.rag-chat-message-sources{border-top:1px solid rgba(0,0,0,.1);color:#666;font-size:12px;margin-top:8px;padding-top:8px}.rag-chat-message-sources-title{font-weight:600;margin-bottom:4px}.rag-chat-message-source{margin:2px 0}.rag-chat-loading{align-self:flex-start;background-color:#f0f0f0;border-radius:12px;display:flex;gap:4px;padding:10px 14px}.rag-chat-loading-dot{animation:rag-bounce 1.4s ease-in-out infinite both;background-color:#999;border-radius:50%;height:8px;width:8px}.rag-chat-loading-dot:first-child{animation-delay:-.32s}.rag-chat-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes rag-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.rag-chat-input-container{align-items:flex-end;border-top:1px solid var(--rag-border-color);display:flex;gap:8px;padding:12px 16px}.rag-chat-input{border:1px solid var(--rag-border-color);border-radius:20px;flex:1;font-family:inherit;font-size:14px;max-height:100px;outline:none;padding:10px 14px;resize:none;transition:border-color .2s ease}.rag-chat-input:focus{border-color:var(--rag-primary-color)}.rag-chat-input::-moz-placeholder{color:#999}.rag-chat-input::placeholder{color:#999}.rag-chat-send-button{align-items:center;background-color:var(--rag-primary-color);border:none;border-radius:50%;cursor:pointer;display:flex;height:40px;justify-content:center;transition:background-color .2s ease,transform .1s ease;width:40px}.rag-chat-send-button:hover:not(:disabled){filter:brightness(1.1)}.rag-chat-send-button:active:not(:disabled){transform:scale(.95)}.rag-chat-send-button:disabled{cursor:not-allowed;opacity:.5}.rag-chat-send-button svg{fill:#fff;height:20px;width:20px}.rag-chat-powered-by{background-color:#fafafa;color:#999;font-size:11px;padding:8px;text-align:center}.rag-chat-powered-by a{color:#666;text-decoration:none}.rag-chat-powered-by a:hover{text-decoration:underline}.rag-chat-error{color:#dc3545;padding:20px;text-align:center}.rag-chat-error-message{margin-bottom:12px}.rag-chat-error-retry{background-color:var(--rag-primary-color);border:none;border-radius:4px;color:#fff;cursor:pointer;font-size:14px;padding:8px 16px}.rag-chat-greeting{color:#666;padding:20px;text-align:center}.rag-chat-usp-text{color:#333;font-weight:700;margin:0 0 12px}.rag-chat-greeting-text{margin:0}@media (max-width:480px){.rag-chat-window{border-radius:12px;bottom:10px!important;height:calc(100vh - 100px);left:10px!important;max-height:none;right:10px!important;top:auto!important;width:calc(100vw - 20px)}.rag-chat-bubble{height:56px;width:56px}}
1
+ .rag-chat-widget{--rag-primary-color:#007bff;--rag-bg-color:#fff;--rag-text-color:#333;--rag-border-color:#e0e0e0;--rag-shadow:0 4px 12px rgba(0,0,0,.15);--rag-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,sans-serif;box-sizing:border-box;font-family:var(--rag-font-family);font-size:14px;line-height:1.5}.rag-chat-widget *,.rag-chat-widget :after,.rag-chat-widget :before{box-sizing:inherit}.rag-chat-bubble{align-items:center;background-color:var(--rag-primary-color);border:none;border-radius:50%;box-shadow:var(--rag-shadow);cursor:pointer;display:flex;height:60px;justify-content:center;position:fixed;transition:transform .2s ease,box-shadow .2s ease;width:60px;z-index:9998}.rag-chat-bubble:hover{box-shadow:0 6px 16px rgba(0,0,0,.2);transform:scale(1.05)}.rag-chat-bubble:active{transform:scale(.95)}.rag-chat-bubble.bottom-right{bottom:20px;right:20px}.rag-chat-bubble.bottom-left{bottom:20px;left:20px}.rag-chat-bubble.top-right{right:20px;top:20px}.rag-chat-bubble.top-left{left:20px;top:20px}.rag-chat-bubble-icon{fill:#fff;height:28px;width:28px}.rag-chat-bubble-badge{align-items:center;background-color:#f44;border-radius:10px;color:#fff;display:flex;font-size:12px;font-weight:700;height:20px;justify-content:center;min-width:20px;padding:0 6px;position:absolute;right:-5px;top:-5px}.rag-chat-window{animation:rag-slide-up .3s ease;background-color:var(--rag-bg-color);border-radius:12px;box-shadow:var(--rag-shadow);display:flex;flex-direction:column;height:520px;max-height:80vh;overflow:hidden;position:fixed;width:380px;z-index:9999}@keyframes rag-slide-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.rag-chat-window.bottom-right{bottom:90px;right:20px}.rag-chat-window.bottom-left{bottom:90px;left:20px}.rag-chat-window.top-right{right:20px;top:90px}.rag-chat-window.top-left{left:20px;top:90px}.rag-chat-header{align-items:center;background-color:var(--rag-primary-color);color:#fff;display:flex;justify-content:space-between;padding:16px}.rag-chat-header-title{font-size:16px;font-weight:600;margin:0}.rag-chat-header-close{align-items:center;background:none;border:none;border-radius:4px;color:#fff;cursor:pointer;display:flex;justify-content:center;padding:4px;transition:background-color .2s ease}.rag-chat-header-close:hover{background-color:hsla(0,0%,100%,.2)}.rag-chat-header-close svg{height:20px;width:20px}.rag-chat-messages{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.rag-chat-message{word-wrap:break-word;border-radius:12px;max-width:85%;padding:10px 14px}.rag-chat-message.user{align-self:flex-end;background-color:var(--rag-primary-color);border-bottom-right-radius:4px;color:#fff}.rag-chat-message.assistant{align-self:flex-start;background-color:#f0f0f0;border-bottom-left-radius:4px;color:var(--rag-text-color)}.rag-chat-message-content{margin:0;white-space:pre-wrap}.rag-chat-message-sources{border-top:1px solid rgba(0,0,0,.1);color:#666;font-size:12px;margin-top:8px;padding-top:8px}.rag-chat-message-sources-title{font-weight:600;margin-bottom:4px}.rag-chat-message-source{margin:2px 0}.rag-chat-loading{align-self:flex-start;background-color:#f0f0f0;border-radius:12px;display:flex;gap:4px;padding:10px 14px}.rag-chat-loading-dot{animation:rag-bounce 1.4s ease-in-out infinite both;background-color:#999;border-radius:50%;height:8px;width:8px}.rag-chat-loading-dot:first-child{animation-delay:-.32s}.rag-chat-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes rag-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.rag-chat-input-container{align-items:flex-end;border-top:1px solid var(--rag-border-color);display:flex;gap:8px;padding:12px 16px}.rag-chat-input{border:1px solid var(--rag-border-color);border-radius:20px;flex:1;font-family:inherit;font-size:14px;max-height:100px;outline:none;padding:10px 14px;resize:none;transition:border-color .2s ease}.rag-chat-input:focus{border-color:var(--rag-primary-color)}.rag-chat-input::-moz-placeholder{color:#999}.rag-chat-input::placeholder{color:#999}.rag-chat-send-button{align-items:center;background-color:var(--rag-primary-color);border:none;border-radius:50%;cursor:pointer;display:flex;height:40px;justify-content:center;transition:background-color .2s ease,transform .1s ease;width:40px}.rag-chat-send-button:hover:not(:disabled){filter:brightness(1.1)}.rag-chat-send-button:active:not(:disabled){transform:scale(.95)}.rag-chat-send-button:disabled{cursor:not-allowed;opacity:.5}.rag-chat-send-button svg{fill:#fff;height:20px;width:20px}.rag-chat-powered-by{background-color:#fafafa;color:#999;font-size:11px;padding:8px;text-align:center}.rag-chat-powered-by a{color:#666;text-decoration:none}.rag-chat-powered-by a:hover{text-decoration:underline}.rag-chat-error{color:#dc3545;padding:20px;text-align:center}.rag-chat-error-message{margin-bottom:12px}.rag-chat-error-retry{background-color:var(--rag-primary-color);border:none;border-radius:4px;color:#fff;cursor:pointer;font-size:14px;padding:8px 16px}.rag-chat-greeting{color:#666;padding:20px;text-align:center}.rag-chat-usp-text{color:#333;font-weight:700;margin:0 0 12px}.rag-chat-greeting-text{margin:0}.rag-home-view{gap:20px;height:100%;overflow-y:auto;padding:24px 20px}.rag-home-header,.rag-home-view{display:flex;flex-direction:column}.rag-home-header{gap:8px}.rag-home-logo{height:40px;-o-object-fit:contain;object-fit:contain;width:40px}.rag-home-greeting{color:var(--rag-text-color);font-size:24px;font-weight:600;margin:0}.rag-start-chat-card{align-items:center;background:var(--rag-bg-color);border:1px solid var(--rag-border-color);border-radius:12px;cursor:pointer;display:flex;padding:16px;text-align:left;transition:box-shadow .2s ease,border-color .2s ease;width:100%}.rag-start-chat-card:hover{border-color:var(--rag-primary-color);box-shadow:0 4px 12px rgba(0,0,0,.1)}.rag-start-chat-card:focus{outline:2px solid var(--rag-primary-color);outline-offset:2px}.rag-start-chat-card__icon{color:var(--rag-primary-color);flex-shrink:0;height:40px;margin-right:12px;width:40px}.rag-start-chat-card__content{flex:1;min-width:0}.rag-start-chat-card__title{color:var(--rag-text-color);font-size:15px;font-weight:600}.rag-start-chat-card__subtitle{color:#666;font-size:13px;margin-top:2px}.rag-start-chat-card__arrow{color:var(--rag-primary-color);flex-shrink:0;height:20px;width:20px}.rag-ticket-section{display:flex;flex-direction:column}.rag-ticket-section__title{color:#666;font-size:12px;font-weight:500;letter-spacing:.5px;margin-bottom:8px;text-transform:uppercase}.rag-ticket-list{display:flex;flex-direction:column}.rag-ticket-category{align-items:center;background:transparent;border:none;border-bottom:1px solid var(--rag-border-color);cursor:pointer;display:flex;padding:12px 0;text-align:left;transition:background-color .2s ease;width:100%}.rag-ticket-category:last-child{border-bottom:none}.rag-ticket-category:hover{background-color:#f8f9fa}.rag-ticket-category:focus{outline:2px solid var(--rag-primary-color);outline-offset:-2px}.rag-ticket-category__icon{color:#666;font-size:14px;margin-right:12px;width:20px}.rag-ticket-category__label{color:var(--rag-text-color);flex:1;font-size:14px;font-weight:500}.rag-ticket-category__chevron{color:#999;height:16px;width:16px}.rag-bookmarks-section{display:flex;flex-direction:column}.rag-bookmarks-section__title{color:#666;font-size:12px;font-weight:500;letter-spacing:.5px;margin-bottom:12px;text-transform:uppercase}.rag-bookmarks-row{display:flex;flex-wrap:wrap;gap:10px}.rag-bookmark{align-items:center;background:#f5f5f5;border-radius:6px;color:var(--rag-text-color);display:inline-flex;font-size:13px;gap:6px;padding:8px 12px;text-decoration:none;transition:background-color .2s ease}.rag-bookmark:hover{background:#e8e8e8}.rag-bookmark:focus{outline:2px solid var(--rag-primary-color);outline-offset:2px}.rag-bookmark__icon{font-size:14px}.rag-bookmark__label{font-weight:500}.rag-home-footer{color:#999;font-size:11px;margin-top:auto;padding-top:16px;text-align:center}.rag-home-footer a{color:#666;text-decoration:none}.rag-home-footer a:hover{text-decoration:underline}.rag-view-container{height:100%;overflow:hidden;position:relative}.rag-view-enter{animation:rag-slide-in-right .25s ease-out}.rag-view-exit{animation:rag-slide-out-left .2s ease-in}.rag-view-enter-back{animation:rag-slide-in-left .25s ease-out}.rag-view-exit-back{animation:rag-slide-out-right .2s ease-in}@keyframes rag-slide-in-right{0%{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes rag-slide-out-left{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(-100%)}}@keyframes rag-slide-in-left{0%{opacity:0;transform:translateX(-100%)}to{opacity:1;transform:translateX(0)}}@keyframes rag-slide-out-right{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(100%)}}.rag-chat-header-back{align-items:center;background:none;border:none;border-radius:4px;color:#fff;cursor:pointer;display:flex;justify-content:center;margin-right:8px;padding:4px;transition:background-color .2s ease}.rag-chat-header-back:hover{background-color:hsla(0,0%,100%,.2)}.rag-chat-header-back svg{height:20px;width:20px}.rag-chat-header-left{align-items:center;display:flex}@media (prefers-reduced-motion:reduce){.rag-bookmark,.rag-chat-bubble,.rag-chat-header-back,.rag-chat-header-close,.rag-chat-send-button,.rag-chat-window,.rag-start-chat-card,.rag-ticket-category{transition:none}.rag-chat-loading-dot,.rag-chat-window,.rag-view-enter,.rag-view-enter-back,.rag-view-exit,.rag-view-exit-back{animation:none}}@media (max-width:480px){.rag-chat-window{border-radius:12px;bottom:10px!important;height:calc(100vh - 100px);left:10px!important;max-height:none;right:10px!important;top:auto!important;width:calc(100vw - 20px)}.rag-chat-bubble{height:56px;width:56px}.rag-home-view{gap:16px;padding:16px}.rag-home-greeting{font-size:20px}.rag-bookmarks-row{gap:8px}.rag-bookmark{font-size:12px;padding:6px 10px}}
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,24 @@
1
+ export type WidgetView = 'home' | 'chat';
2
+ export interface TicketCategory {
3
+ id: string;
4
+ label: string;
5
+ icon: string;
6
+ enabled: boolean;
7
+ }
8
+ export interface Bookmark {
9
+ id: string;
10
+ label: string;
11
+ icon: string;
12
+ url: string;
13
+ }
14
+ export interface HomeViewConfig {
15
+ enabled: boolean;
16
+ greeting: string;
17
+ logoUrl?: string;
18
+ showStartChat: boolean;
19
+ ticketCategories: TicketCategory[];
20
+ bookmarks: Bookmark[];
21
+ }
1
22
  export interface WidgetConfig {
2
23
  widgetId: string;
3
24
  name: string;
@@ -11,6 +32,7 @@ export interface WidgetConfig {
11
32
  channelName: string;
12
33
  allowedMessageLength: number;
13
34
  maxMessagesPerSession: number;
35
+ homeView?: HomeViewConfig;
14
36
  }
15
37
  export interface Message {
16
38
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rag-widget/chat-widget",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Embeddable chat widget for RAG-powered knowledge bases",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -12,7 +12,10 @@
12
12
  "build": "rollup -c",
13
13
  "build:watch": "rollup -c -w",
14
14
  "clean": "rm -rf dist",
15
- "prepublishOnly": "npm run clean && npm run build"
15
+ "prepublishOnly": "npm run clean && npm run build",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:coverage": "vitest run --coverage"
16
19
  },
17
20
  "peerDependencies": {
18
21
  "react": ">=17.0.0",
@@ -21,15 +24,21 @@
21
24
  "devDependencies": {
22
25
  "@rollup/plugin-commonjs": "^25.0.7",
23
26
  "@rollup/plugin-node-resolve": "^15.2.3",
27
+ "@rollup/plugin-terser": "^0.4.4",
24
28
  "@rollup/plugin-typescript": "^11.1.6",
29
+ "@testing-library/jest-dom": "^6.9.1",
30
+ "@testing-library/react": "^16.3.2",
31
+ "@testing-library/user-event": "^14.6.1",
25
32
  "@types/react": "^18.2.0",
26
33
  "@types/react-dom": "^18.2.0",
34
+ "@vitejs/plugin-react": "^5.1.2",
35
+ "jsdom": "^27.4.0",
27
36
  "postcss": "^8.4.35",
28
37
  "rollup": "^4.12.0",
29
38
  "rollup-plugin-postcss": "^4.0.2",
30
- "@rollup/plugin-terser": "^0.4.4",
31
39
  "tslib": "^2.6.2",
32
- "typescript": "^5.3.3"
40
+ "typescript": "^5.3.3",
41
+ "vitest": "^4.0.18"
33
42
  },
34
43
  "keywords": [
35
44
  "react",