@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.
- package/dist/__tests__/accessibility.test.d.ts +1 -0
- package/dist/components/ChatWidget.test.d.ts +1 -0
- package/dist/components/home/BookmarksRow.d.ts +6 -0
- package/dist/components/home/BookmarksRow.test.d.ts +1 -0
- package/dist/components/home/HeaderSection.d.ts +6 -0
- package/dist/components/home/HeaderSection.test.d.ts +1 -0
- package/dist/components/home/StartChatCard.d.ts +6 -0
- package/dist/components/home/StartChatCard.test.d.ts +1 -0
- package/dist/components/home/TicketCategoryList.d.ts +7 -0
- package/dist/components/home/TicketCategoryList.test.d.ts +1 -0
- package/dist/components/home/index.d.ts +8 -0
- package/dist/components/views/HomeView.d.ts +9 -0
- package/dist/components/views/HomeView.test.d.ts +1 -0
- package/dist/components/views/index.d.ts +2 -0
- package/dist/hooks/useViewNavigation.d.ts +10 -0
- package/dist/hooks/useViewNavigation.test.d.ts +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.esm.js +206 -41
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +229 -58
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/providers/ChatWidgetProvider.d.ts +7 -1
- package/dist/providers/ChatWidgetProvider.test.d.ts +1 -0
- package/dist/styles.css +1 -1
- package/dist/test/setup.d.ts +1 -0
- package/dist/types/homeView.test.d.ts +1 -0
- package/dist/types/index.d.ts +22 -0
- package/package.json +13 -4
package/dist/index.umd.js.map
CHANGED
|
@@ -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 {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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.
|
|
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",
|