@rag-widget/chat-widget 0.1.0

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/index.js ADDED
@@ -0,0 +1,315 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var react = require('react');
7
+
8
+ function useChatWidget(options) {
9
+ const { apiKey, widgetId, apiBaseUrl, onError, onMessageSent, onMessageReceived } = options;
10
+ const [messages, setMessages] = react.useState([]);
11
+ const [isLoading, setIsLoading] = react.useState(false);
12
+ const [isConnected, setIsConnected] = react.useState(false);
13
+ const [config, setConfig] = react.useState(null);
14
+ const [error, setError] = react.useState(null);
15
+ const [session, setSession] = react.useState(null);
16
+ const abortControllerRef = react.useRef(null);
17
+ // Fetch widget configuration on mount
18
+ react.useEffect(() => {
19
+ fetchConfig();
20
+ return () => {
21
+ if (abortControllerRef.current) {
22
+ abortControllerRef.current.abort();
23
+ }
24
+ };
25
+ }, [apiKey, widgetId]);
26
+ const fetchConfig = react.useCallback(async () => {
27
+ try {
28
+ const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/config`, {
29
+ headers: {
30
+ 'X-API-Key': apiKey
31
+ }
32
+ });
33
+ if (!response.ok) {
34
+ throw new Error(`Failed to fetch config: ${response.status}`);
35
+ }
36
+ const result = await response.json();
37
+ if (result.status === 'success' && result.data) {
38
+ setConfig(result.data);
39
+ setIsConnected(true);
40
+ setError(null);
41
+ }
42
+ else {
43
+ throw new Error(result.message || 'Failed to load widget configuration');
44
+ }
45
+ }
46
+ catch (err) {
47
+ const error = err instanceof Error ? err : new Error('Unknown error');
48
+ setError(error);
49
+ setIsConnected(false);
50
+ onError === null || onError === void 0 ? void 0 : onError(error);
51
+ }
52
+ }, [apiKey, widgetId, apiBaseUrl, onError]);
53
+ const createSession = react.useCallback(async () => {
54
+ const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/sessions`, {
55
+ method: 'POST',
56
+ headers: {
57
+ 'X-API-Key': apiKey,
58
+ 'Content-Type': 'application/json'
59
+ }
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error(`Failed to create session: ${response.status}`);
63
+ }
64
+ const result = await response.json();
65
+ if (result.status === 'success' && result.data) {
66
+ return result.data;
67
+ }
68
+ throw new Error(result.message || 'Failed to create session');
69
+ }, [apiKey, widgetId, apiBaseUrl]);
70
+ const sendMessage = react.useCallback(async (content) => {
71
+ var _a;
72
+ if (!content.trim() || isLoading)
73
+ return;
74
+ // Cancel any ongoing request
75
+ if (abortControllerRef.current) {
76
+ abortControllerRef.current.abort();
77
+ }
78
+ abortControllerRef.current = new AbortController();
79
+ const userMessage = {
80
+ id: `msg-${Date.now()}`,
81
+ role: 'user',
82
+ content: content.trim(),
83
+ timestamp: new Date()
84
+ };
85
+ setMessages(prev => [...prev, userMessage]);
86
+ setIsLoading(true);
87
+ setError(null);
88
+ onMessageSent === null || onMessageSent === void 0 ? void 0 : onMessageSent(content);
89
+ try {
90
+ // Ensure we have a session
91
+ let currentSession = session;
92
+ if (!currentSession || new Date() > new Date(currentSession.expiresAt)) {
93
+ currentSession = await createSession();
94
+ setSession(currentSession);
95
+ }
96
+ // Create placeholder for assistant message
97
+ const assistantMessageId = `msg-${Date.now()}-assistant`;
98
+ const assistantMessage = {
99
+ id: assistantMessageId,
100
+ role: 'assistant',
101
+ content: '',
102
+ timestamp: new Date(),
103
+ isStreaming: true
104
+ };
105
+ setMessages(prev => [...prev, assistantMessage]);
106
+ // Send message with SSE streaming
107
+ const response = await fetch(`${apiBaseUrl}/api/v1/widget/${widgetId}/sessions/${currentSession.sessionId}/messages`, {
108
+ method: 'POST',
109
+ headers: {
110
+ 'X-API-Key': apiKey,
111
+ 'Content-Type': 'application/json',
112
+ 'Accept': 'text/event-stream'
113
+ },
114
+ body: JSON.stringify({ message: content }),
115
+ signal: abortControllerRef.current.signal
116
+ });
117
+ if (!response.ok) {
118
+ throw new Error(`Failed to send message: ${response.status}`);
119
+ }
120
+ const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
121
+ const decoder = new TextDecoder();
122
+ let fullContent = '';
123
+ if (reader) {
124
+ while (true) {
125
+ const { done, value } = await reader.read();
126
+ if (done)
127
+ break;
128
+ const chunk = decoder.decode(value, { stream: true });
129
+ const lines = chunk.split('\n');
130
+ for (const line of lines) {
131
+ if (line.startsWith('data: ')) {
132
+ try {
133
+ const data = JSON.parse(line.slice(6));
134
+ if (data.type === 'chunk') {
135
+ fullContent += data.content;
136
+ setMessages(prev => prev.map(msg => msg.id === assistantMessageId
137
+ ? { ...msg, content: fullContent }
138
+ : msg));
139
+ }
140
+ else if (data.type === 'done') {
141
+ setMessages(prev => prev.map(msg => msg.id === assistantMessageId
142
+ ? { ...msg, isStreaming: false, sources: data.sources }
143
+ : msg));
144
+ const finalMessage = {
145
+ id: assistantMessageId,
146
+ role: 'assistant',
147
+ content: fullContent,
148
+ timestamp: new Date(),
149
+ sources: data.sources
150
+ };
151
+ onMessageReceived === null || onMessageReceived === void 0 ? void 0 : onMessageReceived(finalMessage);
152
+ }
153
+ }
154
+ catch (_b) {
155
+ // Ignore parse errors for partial SSE data
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ catch (err) {
163
+ if (err.name === 'AbortError') {
164
+ // Request was cancelled, ignore
165
+ return;
166
+ }
167
+ const error = err instanceof Error ? err : new Error('Failed to send message');
168
+ setError(error);
169
+ onError === null || onError === void 0 ? void 0 : onError(error);
170
+ // Remove the incomplete assistant message
171
+ setMessages(prev => prev.filter(msg => !msg.isStreaming));
172
+ }
173
+ finally {
174
+ setIsLoading(false);
175
+ }
176
+ }, [apiKey, widgetId, apiBaseUrl, session, isLoading, createSession, onError, onMessageSent, onMessageReceived]);
177
+ const clearMessages = react.useCallback(() => {
178
+ setMessages([]);
179
+ setSession(null);
180
+ }, []);
181
+ const retry = react.useCallback(() => {
182
+ setError(null);
183
+ fetchConfig();
184
+ }, [fetchConfig]);
185
+ return {
186
+ messages,
187
+ isLoading,
188
+ isConnected,
189
+ config,
190
+ error,
191
+ sendMessage,
192
+ clearMessages,
193
+ retry
194
+ };
195
+ }
196
+
197
+ const ChatIcon = () => (jsxRuntime.jsxs("svg", { className: "rag-chat-bubble-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsx("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" }), jsxRuntime.jsx("path", { d: "M7 9h10v2H7zm0-3h10v2H7z" })] }));
198
+ const CloseIcon$1 = () => (jsxRuntime.jsx("svg", { className: "rag-chat-bubble-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("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" }) }));
199
+ const ChatBubble = ({ isOpen, onClick, primaryColor = '#007bff', position = 'bottom-right', unreadCount = 0 }) => {
200
+ return (jsxRuntime.jsxs("button", { className: `rag-chat-bubble ${position}`, onClick: onClick, style: { backgroundColor: primaryColor }, "aria-label": isOpen ? 'Close chat' : 'Open chat', type: "button", children: [isOpen ? jsxRuntime.jsx(CloseIcon$1, {}) : jsxRuntime.jsx(ChatIcon, {}), !isOpen && unreadCount > 0 && (jsxRuntime.jsx("span", { className: "rag-chat-bubble-badge", children: unreadCount > 9 ? '9+' : unreadCount }))] }));
201
+ };
202
+
203
+ const CloseIcon = () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { fill: "currentColor", 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" }) }));
204
+ const SendIcon = () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }));
205
+ const LoadingDots = () => (jsxRuntime.jsxs("div", { className: "rag-chat-loading", children: [jsxRuntime.jsx("div", { className: "rag-chat-loading-dot" }), jsxRuntime.jsx("div", { className: "rag-chat-loading-dot" }), jsxRuntime.jsx("div", { className: "rag-chat-loading-dot" })] }));
206
+ const MessageBubble = ({ message }) => (jsxRuntime.jsxs("div", { className: `rag-chat-message ${message.role}`, children: [jsxRuntime.jsx("p", { className: "rag-chat-message-content", children: message.content }), message.sources && message.sources.length > 0 && (jsxRuntime.jsxs("div", { className: "rag-chat-message-sources", children: [jsxRuntime.jsx("div", { className: "rag-chat-message-sources-title", children: "Sources:" }), message.sources.map((source, index) => (jsxRuntime.jsx("div", { className: "rag-chat-message-source", children: source.title }, index)))] }))] }));
207
+ const ChatWindow = ({ isOpen, onClose, config, messages, isLoading, onSendMessage }) => {
208
+ const [inputValue, setInputValue] = react.useState('');
209
+ const messagesEndRef = react.useRef(null);
210
+ const inputRef = react.useRef(null);
211
+ // Scroll to bottom when new messages arrive
212
+ react.useEffect(() => {
213
+ var _a;
214
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
215
+ }, [messages]);
216
+ // Focus input when window opens
217
+ react.useEffect(() => {
218
+ var _a;
219
+ if (isOpen) {
220
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
221
+ }
222
+ }, [isOpen]);
223
+ const handleSubmit = (e) => {
224
+ e.preventDefault();
225
+ if (inputValue.trim() && !isLoading) {
226
+ onSendMessage(inputValue.trim());
227
+ setInputValue('');
228
+ }
229
+ };
230
+ const handleKeyDown = (e) => {
231
+ if (e.key === 'Enter' && !e.shiftKey) {
232
+ e.preventDefault();
233
+ handleSubmit(e);
234
+ }
235
+ };
236
+ if (!isOpen)
237
+ return null;
238
+ const position = (config === null || config === void 0 ? void 0 : config.position) || 'bottom-right';
239
+ const primaryColor = (config === null || config === void 0 ? void 0 : config.primaryColor) || '#007bff';
240
+ return (jsxRuntime.jsxs("div", { className: `rag-chat-window ${position}`, style: { '--rag-primary-color': primaryColor }, children: [jsxRuntime.jsxs("div", { className: "rag-chat-header", style: { backgroundColor: primaryColor }, children: [jsxRuntime.jsx("h3", { className: "rag-chat-header-title", children: (config === null || config === void 0 ? void 0 : config.name) || 'Chat' }), jsxRuntime.jsx("button", { className: "rag-chat-header-close", onClick: onClose, "aria-label": "Close chat", type: "button", children: jsxRuntime.jsx(CloseIcon, {}) })] }), jsxRuntime.jsxs("div", { className: "rag-chat-messages", children: [messages.length === 0 && (config === null || config === void 0 ? void 0 : config.greeting) && (jsxRuntime.jsx("div", { className: "rag-chat-greeting", children: config.greeting })), messages.map(message => (jsxRuntime.jsx(MessageBubble, { message: message }, message.id))), isLoading && jsxRuntime.jsx(LoadingDots, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }), jsxRuntime.jsxs("form", { className: "rag-chat-input-container", onSubmit: handleSubmit, children: [jsxRuntime.jsx("textarea", { ref: inputRef, className: "rag-chat-input", value: inputValue, onChange: e => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder: (config === null || config === void 0 ? void 0 : config.placeholder) || 'Type a message...', rows: 1, maxLength: (config === null || config === void 0 ? void 0 : config.allowedMessageLength) || 2000, disabled: isLoading }), jsxRuntime.jsx("button", { type: "submit", className: "rag-chat-send-button", disabled: !inputValue.trim() || isLoading, style: { backgroundColor: primaryColor }, "aria-label": "Send message", children: jsxRuntime.jsx(SendIcon, {}) })] }), (config === null || config === void 0 ? void 0 : config.showPoweredBy) && (jsxRuntime.jsxs("div", { className: "rag-chat-powered-by", children: ["Powered by ", jsxRuntime.jsx("a", { href: "https://rag-widget.com", target: "_blank", rel: "noopener noreferrer", children: "RAG Widget" })] }))] }));
241
+ };
242
+
243
+ const ChatWidget = ({ apiKey, widgetId, apiBaseUrl = '', position, primaryColor, greeting, placeholder, showPoweredBy, onError, onMessageSent, onMessageReceived }) => {
244
+ const [isOpen, setIsOpen] = react.useState(false);
245
+ // Determine the API base URL
246
+ const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
247
+ const { messages, isLoading, isConnected, config, error, sendMessage, retry } = useChatWidget({
248
+ apiKey,
249
+ widgetId,
250
+ apiBaseUrl: baseUrl,
251
+ onError,
252
+ onMessageSent,
253
+ onMessageReceived
254
+ });
255
+ // Merge props with fetched config (props take precedence)
256
+ const mergedConfig = config ? {
257
+ ...config,
258
+ position: position || config.position,
259
+ primaryColor: primaryColor || config.primaryColor,
260
+ greeting: greeting || config.greeting,
261
+ placeholder: placeholder || config.placeholder,
262
+ showPoweredBy: showPoweredBy !== undefined ? showPoweredBy : config.showPoweredBy
263
+ } : null;
264
+ const handleToggle = () => {
265
+ setIsOpen(prev => !prev);
266
+ };
267
+ const handleClose = () => {
268
+ setIsOpen(false);
269
+ };
270
+ // Show error state in the window if there's an error
271
+ if (error && isOpen) {
272
+ return (jsxRuntime.jsxs("div", { className: "rag-chat-widget", children: [jsxRuntime.jsx(ChatBubble, { isOpen: isOpen, onClick: handleToggle, primaryColor: primaryColor || '#007bff', position: position || 'bottom-right' }), jsxRuntime.jsxs("div", { className: `rag-chat-window ${position || 'bottom-right'}`, children: [jsxRuntime.jsxs("div", { className: "rag-chat-header", style: { backgroundColor: primaryColor || '#007bff' }, children: [jsxRuntime.jsx("h3", { className: "rag-chat-header-title", children: "Chat" }), jsxRuntime.jsx("button", { className: "rag-chat-header-close", onClick: handleClose, type: "button", children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { fill: "currentColor", 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" }) }) })] }), jsxRuntime.jsxs("div", { className: "rag-chat-error", children: [jsxRuntime.jsx("p", { className: "rag-chat-error-message", children: error.message || 'Unable to connect. Please try again.' }), jsxRuntime.jsx("button", { className: "rag-chat-error-retry", onClick: retry, type: "button", children: "Retry" })] })] })] }));
273
+ }
274
+ return (jsxRuntime.jsxs("div", { className: "rag-chat-widget", children: [jsxRuntime.jsx(ChatBubble, { isOpen: isOpen, onClick: handleToggle, primaryColor: (mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.primaryColor) || primaryColor || '#007bff', position: (mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.position) || position || 'bottom-right' }), mergedConfig && (jsxRuntime.jsx(ChatWindow, { isOpen: isOpen, onClose: handleClose, config: mergedConfig, messages: messages, isLoading: isLoading, onSendMessage: sendMessage }))] }));
275
+ };
276
+
277
+ const ChatWidgetContext = react.createContext(null);
278
+ const ChatWidgetProvider = ({ apiKey, widgetId, apiBaseUrl = '', onError, onMessageSent, onMessageReceived, children }) => {
279
+ const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
280
+ const chatWidget = useChatWidget({
281
+ apiKey,
282
+ widgetId,
283
+ apiBaseUrl: baseUrl,
284
+ onError,
285
+ onMessageSent,
286
+ onMessageReceived
287
+ });
288
+ const value = react.useMemo(() => ({
289
+ messages: chatWidget.messages,
290
+ isLoading: chatWidget.isLoading,
291
+ isConnected: chatWidget.isConnected,
292
+ config: chatWidget.config,
293
+ error: chatWidget.error,
294
+ sendMessage: chatWidget.sendMessage,
295
+ clearMessages: chatWidget.clearMessages,
296
+ retry: chatWidget.retry
297
+ }), [chatWidget]);
298
+ return (jsxRuntime.jsx(ChatWidgetContext.Provider, { value: value, children: children }));
299
+ };
300
+ const useChatWidgetContext = () => {
301
+ const context = react.useContext(ChatWidgetContext);
302
+ if (!context) {
303
+ throw new Error('useChatWidgetContext must be used within a ChatWidgetProvider');
304
+ }
305
+ return context;
306
+ };
307
+
308
+ exports.ChatBubble = ChatBubble;
309
+ exports.ChatWidget = ChatWidget;
310
+ exports.ChatWidgetProvider = ChatWidgetProvider;
311
+ exports.ChatWindow = ChatWindow;
312
+ exports.default = ChatWidget;
313
+ exports.useChatWidget = useChatWidget;
314
+ exports.useChatWidgetContext = useChatWidgetContext;
315
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/hooks/useChatWidget.ts","../src/components/ChatBubble.tsx","../src/components/ChatWindow.tsx","../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 <p className=\"rag-chat-message-content\">{message.content}</p>\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?.greeting && (\r\n <div className=\"rag-chat-greeting\">{config.greeting}</div>\r\n )}\r\n\r\n {messages.map(message => (\r\n <MessageBubble key={message.id} message={message} />\r\n ))}\r\n\r\n {isLoading && <LoadingDots />}\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, { 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":["useState","useRef","useEffect","useCallback","_jsxs","_jsx","CloseIcon","createContext","useMemo","useContext"],"mappings":";;;;;;;AAuBM,SAAU,aAAa,CAAC,OAA6B,EAAA;AACzD,IAAA,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,OAAO;IAE3F,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAGA,cAAQ,CAAY,EAAE,CAAC;IACvD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAGA,cAAQ,CAAC,KAAK,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAGA,cAAQ,CAAC,KAAK,CAAC;IACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAGA,cAAQ,CAAsB,IAAI,CAAC;IAC/D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAGA,cAAQ,CAAe,IAAI,CAAC;IACtD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAGA,cAAQ,CAAqB,IAAI,CAAC;AAEhE,IAAA,MAAM,kBAAkB,GAAGC,YAAM,CAAyB,IAAI,CAAC;;IAG/DC,eAAS,CAAC,MAAK;AACb,QAAA,WAAW,EAAE;AACb,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,kBAAkB,CAAC,OAAO,EAAE;AAC9B,gBAAA,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE;YACpC;AACF,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEtB,IAAA,MAAM,WAAW,GAAGC,iBAAW,CAAC,YAAW;AACzC,QAAA,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,CAAA,eAAA,EAAkB,QAAQ,CAAA,OAAA,CAAS,EAAE;AAC7E,gBAAA,OAAO,EAAE;AACP,oBAAA,WAAW,EAAE;AACd;AACF,aAAA,CAAC;AAEF,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,IAAI,KAAK,CAAC,CAAA,wBAAA,EAA2B,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;YAC/D;AAEA,YAAA,MAAM,MAAM,GAA8B,MAAM,QAAQ,CAAC,IAAI,EAAE;YAE/D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE;AAC9C,gBAAA,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;gBACtB,cAAc,CAAC,IAAI,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC;YAChB;iBAAO;gBACL,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,qCAAqC,CAAC;YAC1E;QACF;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC;YACrE,QAAQ,CAAC,KAAK,CAAC;YACf,cAAc,CAAC,KAAK,CAAC;AACrB,YAAA,OAAO,aAAP,OAAO,KAAA,MAAA,GAAA,MAAA,GAAP,OAAO,CAAG,KAAK,CAAC;QAClB;IACF,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAE3C,IAAA,MAAM,aAAa,GAAGA,iBAAW,CAAC,YAAiC;QACjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,CAAA,eAAA,EAAkB,QAAQ,CAAA,SAAA,CAAW,EAAE;AAC/E,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,OAAO,EAAE;AACP,gBAAA,WAAW,EAAE,MAAM;AACnB,gBAAA,cAAc,EAAE;AACjB;AACF,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,CAAA,0BAAA,EAA6B,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;QACjE;AAEA,QAAA,MAAM,MAAM,GAA6B,MAAM,QAAQ,CAAC,IAAI,EAAE;QAE9D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE;YAC9C,OAAO,MAAM,CAAC,IAAI;QACpB;QAEA,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,0BAA0B,CAAC;IAC/D,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAElC,MAAM,WAAW,GAAGA,iBAAW,CAAC,OAAO,OAAe,KAAI;;AACxD,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,SAAS;YAAE;;AAGlC,QAAA,IAAI,kBAAkB,CAAC,OAAO,EAAE;AAC9B,YAAA,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE;QACpC;AACA,QAAA,kBAAkB,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE;AAElD,QAAA,MAAM,WAAW,GAAY;AAC3B,YAAA,EAAE,EAAE,CAAA,IAAA,EAAO,IAAI,CAAC,GAAG,EAAE,CAAA,CAAE;AACvB,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;YACvB,SAAS,EAAE,IAAI,IAAI;SACpB;AAED,QAAA,WAAW,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC;QAC3C,YAAY,CAAC,IAAI,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC;AACd,QAAA,aAAa,aAAb,aAAa,KAAA,MAAA,GAAA,MAAA,GAAb,aAAa,CAAG,OAAO,CAAC;AAExB,QAAA,IAAI;;YAEF,IAAI,cAAc,GAAG,OAAO;AAC5B,YAAA,IAAI,CAAC,cAAc,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE;AACtE,gBAAA,cAAc,GAAG,MAAM,aAAa,EAAE;gBACtC,UAAU,CAAC,cAAc,CAAC;YAC5B;;YAGA,MAAM,kBAAkB,GAAG,CAAA,IAAA,EAAO,IAAI,CAAC,GAAG,EAAE,YAAY;AACxD,YAAA,MAAM,gBAAgB,GAAY;AAChC,gBAAA,EAAE,EAAE,kBAAkB;AACtB,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,OAAO,EAAE,EAAE;gBACX,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,gBAAA,WAAW,EAAE;aACd;AACD,YAAA,WAAW,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,gBAAgB,CAAC,CAAC;;AAGhD,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,CAAA,EAAG,UAAU,CAAA,eAAA,EAAkB,QAAQ,CAAA,UAAA,EAAa,cAAc,CAAC,SAAS,WAAW,EACvF;AACE,gBAAA,MAAM,EAAE,MAAM;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA,WAAW,EAAE,MAAM;AACnB,oBAAA,cAAc,EAAE,kBAAkB;AAClC,oBAAA,QAAQ,EAAE;AACX,iBAAA;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC1C,gBAAA,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC;AACpC,aAAA,CACF;AAED,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,IAAI,KAAK,CAAC,CAAA,wBAAA,EAA2B,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;YAC/D;YAEA,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,QAAQ,CAAC,IAAI,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,SAAS,EAAE;AACzC,YAAA,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE;YACjC,IAAI,WAAW,GAAG,EAAE;YAEpB,IAAI,MAAM,EAAE;gBACV,OAAO,IAAI,EAAE;oBACX,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE;AAC3C,oBAAA,IAAI,IAAI;wBAAE;AAEV,oBAAA,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;oBACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;AAE/B,oBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,wBAAA,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AAC7B,4BAAA,IAAI;AACF,gCAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEtC,gCAAA,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;AACzB,oCAAA,WAAW,IAAI,IAAI,CAAC,OAAO;AAC3B,oCAAA,WAAW,CAAC,IAAI,IACd,IAAI,CAAC,GAAG,CAAC,GAAG,IACV,GAAG,CAAC,EAAE,KAAK;0CACP,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,WAAW;AAChC,0CAAE,GAAG,CACR,CACF;gCACH;AAAO,qCAAA,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE;AAC/B,oCAAA,WAAW,CAAC,IAAI,IACd,IAAI,CAAC,GAAG,CAAC,GAAG,IACV,GAAG,CAAC,EAAE,KAAK;AACT,0CAAE,EAAE,GAAG,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO;AACrD,0CAAE,GAAG,CACR,CACF;AAED,oCAAA,MAAM,YAAY,GAAY;AAC5B,wCAAA,EAAE,EAAE,kBAAkB;AACtB,wCAAA,IAAI,EAAE,WAAW;AACjB,wCAAA,OAAO,EAAE,WAAW;wCACpB,SAAS,EAAE,IAAI,IAAI,EAAE;wCACrB,OAAO,EAAE,IAAI,CAAC;qCACf;AACD,oCAAA,iBAAiB,aAAjB,iBAAiB,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAjB,iBAAiB,CAAG,YAAY,CAAC;gCACnC;4BACF;AAAE,4BAAA,OAAA,EAAA,EAAM;;4BAER;wBACF;oBACF;gBACF;YACF;QACF;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,IAAK,GAAa,CAAC,IAAI,KAAK,YAAY,EAAE;;gBAExC;YACF;AAEA,YAAA,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,wBAAwB,CAAC;YAC9E,QAAQ,CAAC,KAAK,CAAC;AACf,YAAA,OAAO,aAAP,OAAO,KAAA,MAAA,GAAA,MAAA,GAAP,OAAO,CAAG,KAAK,CAAC;;AAGhB,YAAA,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC3D;gBAAU;YACR,YAAY,CAAC,KAAK,CAAC;QACrB;IACF,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;AAEhH,IAAA,MAAM,aAAa,GAAGA,iBAAW,CAAC,MAAK;QACrC,WAAW,CAAC,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,KAAK,GAAGA,iBAAW,CAAC,MAAK;QAC7B,QAAQ,CAAC,IAAI,CAAC;AACd,QAAA,WAAW,EAAE;AACf,IAAA,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAEjB,OAAO;QACL,QAAQ;QACR,SAAS;QACT,WAAW;QACX,MAAM;QACN,KAAK;QACL,WAAW;QACX,aAAa;QACb;KACD;AACH;;AChPA,MAAM,QAAQ,GAAa,OACzBC,eAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,sBAAsB,EAChC,OAAO,EAAC,WAAW,EACnB,KAAK,EAAC,4BAA4B,EAAA,QAAA,EAAA,CAElCC,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,+FAA+F,EAAA,CAAG,EAC1GA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,0BAA0B,EAAA,CAAG,CAAA,EAAA,CACjC,CACP;AAED,MAAMC,WAAS,GAAa,OAC1BD,cAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,sBAAsB,EAChC,OAAO,EAAC,WAAW,EACnB,KAAK,EAAC,4BAA4B,EAAA,QAAA,EAElCA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,uGAAuG,EAAA,CAAG,EAAA,CAC9G,CACP;MAEY,UAAU,GAA8B,CAAC,EACpD,MAAM,EACN,OAAO,EACP,YAAY,GAAG,SAAS,EACxB,QAAQ,GAAG,cAAc,EACzB,WAAW,GAAG,CAAC,EAChB,KAAI;AACH,IAAA,QACED,eAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAE,CAAA,gBAAA,EAAmB,QAAQ,CAAA,CAAE,EACxC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE,EAAA,YAAA,EAC5B,MAAM,GAAG,YAAY,GAAG,WAAW,EAC/C,IAAI,EAAC,QAAQ,EAAA,QAAA,EAAA,CAEZ,MAAM,GAAGC,cAAA,CAACC,WAAS,KAAG,GAAGD,cAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,EACrC,CAAC,MAAM,IAAI,WAAW,GAAG,CAAC,KACzBA,cAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,uBAAuB,YACpC,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,WAAW,EAAA,CAChC,CACR,CAAA,EAAA,CACM;AAEb;;AC5CA,MAAM,SAAS,GAAa,OAC1BA,cAAA,CAAA,KAAA,EAAA,EAAK,OAAO,EAAC,WAAW,EAAC,KAAK,EAAC,4BAA4B,EAAA,QAAA,EACzDA,cAAA,CAAA,MAAA,EAAA,EACE,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,uGAAuG,EAAA,CACzG,EAAA,CACE,CACP;AAED,MAAM,QAAQ,GAAa,OACzBA,cAAA,CAAA,KAAA,EAAA,EAAK,OAAO,EAAC,WAAW,EAAC,KAAK,EAAC,4BAA4B,YACzDA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,uCAAuC,EAAA,CAAG,EAAA,CAC9C,CACP;AAED,MAAM,WAAW,GAAa,OAC5BD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,EAAA,QAAA,EAAA,CAC/BC,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sBAAsB,EAAA,CAAG,EACxCA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sBAAsB,EAAA,CAAG,EACxCA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sBAAsB,EAAA,CAAG,CAAA,EAAA,CACpC,CACP;AAMD,MAAM,aAAa,GAAiC,CAAC,EAAE,OAAO,EAAE,MAC9DD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,CAAA,iBAAA,EAAoB,OAAO,CAAC,IAAI,EAAE,EAAA,QAAA,EAAA,CAChDC,cAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,0BAA0B,EAAA,QAAA,EAAE,OAAO,CAAC,OAAO,EAAA,CAAK,EAC5D,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,KAC5CD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,0BAA0B,EAAA,QAAA,EAAA,CACvCC,wBAAK,SAAS,EAAC,gCAAgC,EAAA,QAAA,EAAA,UAAA,EAAA,CAAe,EAC7D,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,MACjCA,cAAA,CAAA,KAAA,EAAA,EAAiB,SAAS,EAAC,yBAAyB,EAAA,QAAA,EACjD,MAAM,CAAC,KAAK,EAAA,EADL,KAAK,CAET,CACP,CAAC,IACE,CACP,CAAA,EAAA,CACG,CACP;AAEM,MAAM,UAAU,GAA8B,CAAC,EACpD,MAAM,EACN,OAAO,EACP,MAAM,EACN,QAAQ,EACR,SAAS,EACT,aAAa,EACd,KAAI;IACH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAGL,cAAQ,CAAC,EAAE,CAAC;AAChD,IAAA,MAAM,cAAc,GAAGC,YAAM,CAAiB,IAAI,CAAC;AACnD,IAAA,MAAM,QAAQ,GAAGA,YAAM,CAAsB,IAAI,CAAC;;IAGlDC,eAAS,CAAC,MAAK;;AACb,QAAA,CAAA,EAAA,GAAA,cAAc,CAAC,OAAO,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAChE,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;;IAGdA,eAAS,CAAC,MAAK;;QACb,IAAI,MAAM,EAAE;AACV,YAAA,CAAA,EAAA,GAAA,QAAQ,CAAC,OAAO,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAE,KAAK,EAAE;QAC3B;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,YAAY,GAAG,CAAC,CAAkB,KAAI;QAC1C,CAAC,CAAC,cAAc,EAAE;QAClB,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE;AACnC,YAAA,aAAa,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YAChC,aAAa,CAAC,EAAE,CAAC;QACnB;AACF,IAAA,CAAC;AAED,IAAA,MAAM,aAAa,GAAG,CAAC,CAA2C,KAAI;QACpE,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;YACpC,CAAC,CAAC,cAAc,EAAE;YAClB,YAAY,CAAC,CAAC,CAAC;QACjB;AACF,IAAA,CAAC;AAED,IAAA,IAAI,CAAC,MAAM;AAAE,QAAA,OAAO,IAAI;AAExB,IAAA,MAAM,QAAQ,GAAG,CAAA,MAAM,KAAA,IAAA,IAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,QAAQ,KAAI,cAAc;AACnD,IAAA,MAAM,YAAY,GAAG,CAAA,MAAM,KAAA,IAAA,IAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,YAAY,KAAI,SAAS;AAEtD,IAAA,QACEE,eAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,CAAA,gBAAA,EAAmB,QAAQ,CAAA,CAAE,EACxC,KAAK,EAAE,EAAE,qBAAqB,EAAE,YAAY,EAAyB,EAAA,QAAA,EAAA,CAErEA,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,EAAC,KAAK,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE,EAAA,QAAA,EAAA,CACvEC,cAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAE,CAAA,MAAM,KAAA,IAAA,IAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,IAAI,KAAI,MAAM,EAAA,CAAM,EACnEA,cAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,uBAAuB,EACjC,OAAO,EAAE,OAAO,EAAA,YAAA,EACL,YAAY,EACvB,IAAI,EAAC,QAAQ,EAAA,QAAA,EAEbA,cAAA,CAAC,SAAS,EAAA,EAAA,CAAG,EAAA,CACN,IACL,EAEND,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAAA,CAC/B,QAAQ,CAAC,MAAM,KAAK,CAAC,KAAI,MAAM,KAAA,IAAA,IAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,QAAQ,CAAA,KACxCC,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAAE,MAAM,CAAC,QAAQ,EAAA,CAAO,CAC3D,EAEA,QAAQ,CAAC,GAAG,CAAC,OAAO,KACnBA,cAAA,CAAC,aAAa,EAAA,EAAkB,OAAO,EAAE,OAAO,EAAA,EAA5B,OAAO,CAAC,EAAE,CAAsB,CACrD,CAAC,EAED,SAAS,IAAIA,cAAA,CAAC,WAAW,EAAA,EAAA,CAAG,EAE7BA,cAAA,CAAA,KAAA,EAAA,EAAK,GAAG,EAAE,cAAc,EAAA,CAAI,CAAA,EAAA,CACxB,EAEND,eAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,0BAA0B,EAAC,QAAQ,EAAE,YAAY,EAAA,QAAA,EAAA,CAC/DC,cAAA,CAAA,UAAA,EAAA,EACE,GAAG,EAAE,QAAQ,EACb,SAAS,EAAC,gBAAgB,EAC1B,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC5C,SAAS,EAAE,aAAa,EACxB,WAAW,EAAE,CAAA,MAAM,KAAA,IAAA,IAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,WAAW,KAAI,mBAAmB,EACvD,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,CAAA,MAAM,aAAN,MAAM,KAAA,MAAA,GAAA,MAAA,GAAN,MAAM,CAAE,oBAAoB,KAAI,IAAI,EAC/C,QAAQ,EAAE,SAAS,EAAA,CACnB,EACFA,cAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,sBAAsB,EAChC,QAAQ,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,SAAS,EACzC,KAAK,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE,EAAA,YAAA,EAC7B,cAAc,EAAA,QAAA,EAEzBA,cAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,EAAA,CACL,CAAA,EAAA,CACJ,EAEN,CAAA,MAAM,KAAA,IAAA,IAAN,MAAM,uBAAN,MAAM,CAAE,aAAa,MACpBD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,EAAA,QAAA,EAAA,CAAA,aAAA,EACvBC,cAAA,CAAA,GAAA,EAAA,EAAG,IAAI,EAAC,wBAAwB,EAAC,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAe,CAAA,EAAA,CAChG,CACP,CAAA,EAAA,CACG;AAEV;;AChJO,MAAM,UAAU,GAA8B,CAAC,EACpD,MAAM,EACN,QAAQ,EACR,UAAU,GAAG,EAAE,EACf,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,aAAa,EACb,OAAO,EACP,aAAa,EACb,iBAAiB,EAClB,KAAI;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAGL,cAAQ,CAAC,KAAK,CAAC;;IAG3C,MAAM,OAAO,GAAG,UAAU,KAAK,OAAO,MAAM,KAAK,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;AAE3F,IAAA,MAAM,EACJ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,WAAW,EACX,KAAK,EACN,GAAG,aAAa,CAAC;QAChB,MAAM;QACN,QAAQ;AACR,QAAA,UAAU,EAAE,OAAO;QACnB,OAAO;QACP,aAAa;QACb;AACD,KAAA,CAAC;;AAGF,IAAA,MAAM,YAAY,GAAG,MAAM,GAAG;AAC5B,QAAA,GAAG,MAAM;AACT,QAAA,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ;AACrC,QAAA,YAAY,EAAE,YAAY,IAAI,MAAM,CAAC,YAAY;AACjD,QAAA,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ;AACrC,QAAA,WAAW,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW;AAC9C,QAAA,aAAa,EAAE,aAAa,KAAK,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;KACrE,GAAG,IAAI;IAER,MAAM,YAAY,GAAG,MAAK;QACxB,SAAS,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;AAC1B,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAK;QACvB,SAAS,CAAC,KAAK,CAAC;AAClB,IAAA,CAAC;;AAGD,IAAA,IAAI,KAAK,IAAI,MAAM,EAAE;AACnB,QAAA,QACEI,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,EAAA,QAAA,EAAA,CAC9BC,cAAA,CAAC,UAAU,EAAA,EACT,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,YAAY,IAAI,SAAS,EACvC,QAAQ,EAAE,QAAQ,IAAI,cAAc,GACpC,EACFD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,CAAA,gBAAA,EAAmB,QAAQ,IAAI,cAAc,CAAA,CAAE,EAAA,QAAA,EAAA,CAC7DA,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,EAAC,KAAK,EAAE,EAAE,eAAe,EAAE,YAAY,IAAI,SAAS,EAAE,EAAA,QAAA,EAAA,CACpFC,cAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAA,MAAA,EAAA,CAAU,EAC/CA,cAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,uBAAuB,EAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAC,QAAQ,EAAA,QAAA,EAC3EA,cAAA,CAAA,KAAA,EAAA,EAAK,OAAO,EAAC,WAAW,EAAC,KAAK,EAAC,4BAA4B,EAAA,QAAA,EACzDA,cAAA,CAAA,MAAA,EAAA,EACE,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,uGAAuG,EAAA,CACzG,EAAA,CACE,EAAA,CACC,CAAA,EAAA,CACL,EACND,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,gBAAgB,EAAA,QAAA,EAAA,CAC7BC,cAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAClC,KAAK,CAAC,OAAO,IAAI,sCAAsC,EAAA,CACtD,EACJA,cAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,sBAAsB,EAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAC,QAAQ,EAAA,QAAA,EAAA,OAAA,EAAA,CAE7D,CAAA,EAAA,CACL,CAAA,EAAA,CACF,CAAA,EAAA,CACF;IAEV;AAEA,IAAA,QACED,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,aAC9BC,cAAA,CAAC,UAAU,EAAA,EACT,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,CAAA,YAAY,aAAZ,YAAY,KAAA,MAAA,GAAA,MAAA,GAAZ,YAAY,CAAE,YAAY,KAAI,YAAY,IAAI,SAAS,EACrE,QAAQ,EAAE,CAAA,YAAY,KAAA,IAAA,IAAZ,YAAY,KAAA,MAAA,GAAA,MAAA,GAAZ,YAAY,CAAE,QAAQ,KAAI,QAAQ,IAAI,cAAc,EAAA,CAC9D,EACD,YAAY,KACXA,cAAA,CAAC,UAAU,EAAA,EACT,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,WAAW,GAC1B,CACH,CAAA,EAAA,CACG;AAEV;;ACpGA,MAAM,iBAAiB,GAAGE,mBAAa,CAAgC,IAAI,CAAC;MAM/D,kBAAkB,GAAsC,CAAC,EACpE,MAAM,EACN,QAAQ,EACR,UAAU,GAAG,EAAE,EACf,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACT,KAAI;IACH,MAAM,OAAO,GAAG,UAAU,KAAK,OAAO,MAAM,KAAK,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;IAE3F,MAAM,UAAU,GAAG,aAAa,CAAC;QAC/B,MAAM;QACN,QAAQ;AACR,QAAA,UAAU,EAAE,OAAO;QACnB,OAAO;QACP,aAAa;QACb;AACD,KAAA,CAAC;AAEF,IAAA,MAAM,KAAK,GAAGC,aAAO,CAAC,OAAO;QAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,aAAa,EAAE,UAAU,CAAC,aAAa;QACvC,KAAK,EAAE,UAAU,CAAC;AACnB,KAAA,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;AAEjB,IAAA,QACEH,cAAA,CAAC,iBAAiB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EACrC,QAAQ,EAAA,CACkB;AAEjC;AAEO,MAAM,oBAAoB,GAAG,MAA6B;AAC/D,IAAA,MAAM,OAAO,GAAGI,gBAAU,CAAC,iBAAiB,CAAC;IAC7C,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC;IAClF;AACA,IAAA,OAAO,OAAO;AAChB;;;;;;;;;;"}
@@ -0,0 +1,2 @@
1
+ !function(e,a){"object"==typeof exports&&"undefined"!=typeof module?a(exports,require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react"],a):a((e="undefined"!=typeof globalThis?globalThis:e||self).RAGChatWidget={},e.React,e.React)}(this,function(e,a,t){"use strict";function r(e){const{apiKey:a,widgetId:r,apiBaseUrl:o,onError:s,onMessageSent:n,onMessageReceived:i}=e,[c,l]=t.useState([]),[d,g]=t.useState(!1),[h,p]=t.useState(!1),[u,x]=t.useState(null),[f,m]=t.useState(null),[b,w]=t.useState(null),y=t.useRef(null);t.useEffect(()=>(v(),()=>{y.current&&y.current.abort()}),[a,r]);const v=t.useCallback(async()=>{try{const e=await fetch(`${o}/api/v1/widget/${r}/config`,{headers:{"X-API-Key":a}});if(!e.ok)throw new Error(`Failed to fetch config: ${e.status}`);const t=await e.json();if("success"!==t.status||!t.data)throw new Error(t.message||"Failed to load widget configuration");x(t.data),p(!0),m(null)}catch(e){const a=e instanceof Error?e:new Error("Unknown error");m(a),p(!1),null==s||s(a)}},[a,r,o,s]),j=t.useCallback(async()=>{const e=await fetch(`${o}/api/v1/widget/${r}/sessions`,{method:"POST",headers:{"X-API-Key":a,"Content-Type":"application/json"}});if(!e.ok)throw new Error(`Failed to create session: ${e.status}`);const t=await e.json();if("success"===t.status&&t.data)return t.data;throw new Error(t.message||"Failed to create session")},[a,r,o]),C=t.useCallback(async e=>{var t;if(!e.trim()||d)return;y.current&&y.current.abort(),y.current=new AbortController;const c={id:`msg-${Date.now()}`,role:"user",content:e.trim(),timestamp:new Date};l(e=>[...e,c]),g(!0),m(null),null==n||n(e);try{let s=b;(!s||new Date>new Date(s.expiresAt))&&(s=await j(),w(s));const n=`msg-${Date.now()}-assistant`,c={id:n,role:"assistant",content:"",timestamp:new Date,isStreaming:!0};l(e=>[...e,c]);const d=await fetch(`${o}/api/v1/widget/${r}/sessions/${s.sessionId}/messages`,{method:"POST",headers:{"X-API-Key":a,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify({message:e}),signal:y.current.signal});if(!d.ok)throw new Error(`Failed to send message: ${d.status}`);const g=null===(t=d.body)||void 0===t?void 0:t.getReader(),h=new TextDecoder;let p="";if(g)for(;;){const{done:e,value:a}=await g.read();if(e)break;const t=h.decode(a,{stream:!0}).split("\n");for(const e of t)if(e.startsWith("data: "))try{const a=JSON.parse(e.slice(6));if("chunk"===a.type)p+=a.content,l(e=>e.map(e=>e.id===n?{...e,content:p}:e));else if("done"===a.type){l(e=>e.map(e=>e.id===n?{...e,isStreaming:!1,sources:a.sources}:e));const e={id:n,role:"assistant",content:p,timestamp:new Date,sources:a.sources};null==i||i(e)}}catch(e){}}}catch(e){if("AbortError"===e.name)return;const a=e instanceof Error?e:new Error("Failed to send message");m(a),null==s||s(a),l(e=>e.filter(e=>!e.isStreaming))}finally{g(!1)}},[a,r,o,b,d,j,s,n,i]),k=t.useCallback(()=>{l([]),w(null)},[]),N=t.useCallback(()=>{m(null),v()},[v]);return{messages:c,isLoading:d,isConnected:h,config:u,error:f,sendMessage:C,clearMessages:k,retry:N}}const o=()=>a.jsxs("svg",{className:"rag-chat-bubble-icon",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[a.jsx("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"}),a.jsx("path",{d:"M7 9h10v2H7zm0-3h10v2H7z"})]}),s=()=>a.jsx("svg",{className:"rag-chat-bubble-icon",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:a.jsx("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"})}),n=({isOpen:e,onClick:t,primaryColor:r="#007bff",position:n="bottom-right",unreadCount:i=0})=>a.jsxs("button",{className:`rag-chat-bubble ${n}`,onClick:t,style:{backgroundColor:r},"aria-label":e?"Close chat":"Open chat",type:"button",children:[e?a.jsx(s,{}):a.jsx(o,{}),!e&&i>0&&a.jsx("span",{className:"rag-chat-bubble-badge",children:i>9?"9+":i})]}),i=()=>a.jsx("svg",{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:a.jsx("path",{fill:"currentColor",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"})}),c=()=>a.jsx("svg",{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:a.jsx("path",{d:"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"})}),l=()=>a.jsxs("div",{className:"rag-chat-loading",children:[a.jsx("div",{className:"rag-chat-loading-dot"}),a.jsx("div",{className:"rag-chat-loading-dot"}),a.jsx("div",{className:"rag-chat-loading-dot"})]}),d=({message:e})=>a.jsxs("div",{className:`rag-chat-message ${e.role}`,children:[a.jsx("p",{className:"rag-chat-message-content",children:e.content}),e.sources&&e.sources.length>0&&a.jsxs("div",{className:"rag-chat-message-sources",children:[a.jsx("div",{className:"rag-chat-message-sources-title",children:"Sources:"}),e.sources.map((e,t)=>a.jsx("div",{className:"rag-chat-message-source",children:e.title},t))]})]}),g=({isOpen:e,onClose:r,config:o,messages:s,isLoading:n,onSendMessage:g})=>{const[h,p]=t.useState(""),u=t.useRef(null),x=t.useRef(null);t.useEffect(()=>{var e;null===(e=u.current)||void 0===e||e.scrollIntoView({behavior:"smooth"})},[s]),t.useEffect(()=>{var a;e&&(null===(a=x.current)||void 0===a||a.focus())},[e]);const f=e=>{e.preventDefault(),h.trim()&&!n&&(g(h.trim()),p(""))};if(!e)return null;const m=(null==o?void 0:o.position)||"bottom-right",b=(null==o?void 0:o.primaryColor)||"#007bff";return a.jsxs("div",{className:`rag-chat-window ${m}`,style:{"--rag-primary-color":b},children:[a.jsxs("div",{className:"rag-chat-header",style:{backgroundColor:b},children:[a.jsx("h3",{className:"rag-chat-header-title",children:(null==o?void 0:o.name)||"Chat"}),a.jsx("button",{className:"rag-chat-header-close",onClick:r,"aria-label":"Close chat",type:"button",children:a.jsx(i,{})})]}),a.jsxs("div",{className:"rag-chat-messages",children:[0===s.length&&(null==o?void 0:o.greeting)&&a.jsx("div",{className:"rag-chat-greeting",children:o.greeting}),s.map(e=>a.jsx(d,{message:e},e.id)),n&&a.jsx(l,{}),a.jsx("div",{ref:u})]}),a.jsxs("form",{className:"rag-chat-input-container",onSubmit:f,children:[a.jsx("textarea",{ref:x,className:"rag-chat-input",value:h,onChange:e=>p(e.target.value),onKeyDown:e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),f(e))},placeholder:(null==o?void 0:o.placeholder)||"Type a message...",rows:1,maxLength:(null==o?void 0:o.allowedMessageLength)||2e3,disabled:n}),a.jsx("button",{type:"submit",className:"rag-chat-send-button",disabled:!h.trim()||n,style:{backgroundColor:b},"aria-label":"Send message",children:a.jsx(c,{})})]}),(null==o?void 0:o.showPoweredBy)&&a.jsxs("div",{className:"rag-chat-powered-by",children:["Powered by ",a.jsx("a",{href:"https://rag-widget.com",target:"_blank",rel:"noopener noreferrer",children:"RAG Widget"})]})]})};!function(e,a){void 0===a&&(a={});var t=a.insertAt;if("undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css","top"===t&&r.firstChild?r.insertBefore(o,r.firstChild):r.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}('.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}@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}}');const h=({apiKey:e,widgetId:o,apiBaseUrl:s="",position:i,primaryColor:c,greeting:l,placeholder:d,showPoweredBy:h,onError:p,onMessageSent:u,onMessageReceived:x})=>{const[f,m]=t.useState(!1),b=s||("undefined"!=typeof window?window.location.origin:""),{messages:w,isLoading:y,isConnected:v,config:j,error:C,sendMessage:k,retry:N}=r({apiKey:e,widgetId:o,apiBaseUrl:b,onError:p,onMessageSent:u,onMessageReceived:x}),M=j?{...j,position:i||j.position,primaryColor:c||j.primaryColor,greeting:l||j.greeting,placeholder:d||j.placeholder,showPoweredBy:void 0!==h?h:j.showPoweredBy}:null,S=()=>{m(e=>!e)},E=()=>{m(!1)};return C&&f?a.jsxs("div",{className:"rag-chat-widget",children:[a.jsx(n,{isOpen:f,onClick:S,primaryColor:c||"#007bff",position:i||"bottom-right"}),a.jsxs("div",{className:`rag-chat-window ${i||"bottom-right"}`,children:[a.jsxs("div",{className:"rag-chat-header",style:{backgroundColor:c||"#007bff"},children:[a.jsx("h3",{className:"rag-chat-header-title",children:"Chat"}),a.jsx("button",{className:"rag-chat-header-close",onClick:E,type:"button",children:a.jsx("svg",{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:a.jsx("path",{fill:"currentColor",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"})})})]}),a.jsxs("div",{className:"rag-chat-error",children:[a.jsx("p",{className:"rag-chat-error-message",children:C.message||"Unable to connect. Please try again."}),a.jsx("button",{className:"rag-chat-error-retry",onClick:N,type:"button",children:"Retry"})]})]})]}):a.jsxs("div",{className:"rag-chat-widget",children:[a.jsx(n,{isOpen:f,onClick:S,primaryColor:(null==M?void 0:M.primaryColor)||c||"#007bff",position:(null==M?void 0:M.position)||i||"bottom-right"}),M&&a.jsx(g,{isOpen:f,onClose:E,config:M,messages:w,isLoading:y,onSendMessage:k})]})},p=t.createContext(null);e.ChatBubble=n,e.ChatWidget=h,e.ChatWidgetProvider=({apiKey:e,widgetId:o,apiBaseUrl:s="",onError:n,onMessageSent:i,onMessageReceived:c,children:l})=>{const d=r({apiKey:e,widgetId:o,apiBaseUrl:s||("undefined"!=typeof window?window.location.origin:""),onError:n,onMessageSent:i,onMessageReceived:c}),g=t.useMemo(()=>({messages:d.messages,isLoading:d.isLoading,isConnected:d.isConnected,config:d.config,error:d.error,sendMessage:d.sendMessage,clearMessages:d.clearMessages,retry:d.retry}),[d]);return a.jsx(p.Provider,{value:g,children:l})},e.ChatWindow=g,e.default=h,e.useChatWidget=r,e.useChatWidgetContext=()=>{const e=t.useContext(p);if(!e)throw new Error("useChatWidgetContext must be used within a ChatWidgetProvider");return e},Object.defineProperty(e,"__esModule",{value:!0})});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +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 <p className=\"rag-chat-message-content\">{message.content}</p>\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?.greeting && (\r\n <div className=\"rag-chat-greeting\">{config.greeting}</div>\r\n )}\r\n\r\n {messages.map(message => (\r\n <MessageBubble key={message.id} message={message} />\r\n ))}\r\n\r\n {isLoading && <LoadingDots />}\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","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":"kVAuBM,SAAUA,EAAcC,GAC5B,MAAMC,OAAEA,EAAMC,SAAEA,EAAQC,WAAEA,EAAUC,QAAEA,EAAOC,cAAEA,EAAaC,kBAAEA,GAAsBN,GAE7EO,EAAUC,GAAeC,EAAAA,SAAoB,KAC7CC,EAAWC,GAAgBF,EAAAA,UAAS,IACpCG,EAAaC,GAAkBJ,EAAAA,UAAS,IACxCK,EAAQC,GAAaN,EAAAA,SAA8B,OACnDO,EAAOC,GAAYR,EAAAA,SAAuB,OAC1CS,EAASC,GAAcV,EAAAA,SAA6B,MAErDW,EAAqBC,EAAAA,OAA+B,MAG1DC,EAAAA,UAAU,KACRC,IACO,KACDH,EAAmBI,SACrBJ,EAAmBI,QAAQC,UAG9B,CAACxB,EAAQC,IAEZ,MAAMqB,EAAcG,EAAAA,YAAYC,UAC9B,IACE,MAAMC,QAAiBC,MAAM,GAAG1B,mBAA4BD,WAAmB,CAC7E4B,QAAS,CACP,YAAa7B,KAIjB,IAAK2B,EAASG,GACZ,MAAM,IAAIC,MAAM,2BAA2BJ,EAASK,UAGtD,MAAMC,QAA0CN,EAASO,OAEzD,GAAsB,YAAlBD,EAAOD,SAAwBC,EAAOE,KAKxC,MAAM,IAAIJ,MAAME,EAAOG,SAAW,uCAJlCtB,EAAUmB,EAAOE,MACjBvB,GAAe,GACfI,EAAS,KAIb,CAAE,MAAOqB,GACP,MAAMtB,EAAQsB,aAAeN,MAAQM,EAAM,IAAIN,MAAM,iBACrDf,EAASD,GACTH,GAAe,GACfT,SAAAA,EAAUY,EACZ,GACC,CAACf,EAAQC,EAAUC,EAAYC,IAE5BmC,EAAgBb,EAAAA,YAAYC,UAChC,MAAMC,QAAiBC,MAAM,GAAG1B,mBAA4BD,aAAqB,CAC/EsC,OAAQ,OACRV,QAAS,CACP,YAAa7B,EACb,eAAgB,sBAIpB,IAAK2B,EAASG,GACZ,MAAM,IAAIC,MAAM,6BAA6BJ,EAASK,UAGxD,MAAMC,QAAyCN,EAASO,OAExD,GAAsB,YAAlBD,EAAOD,QAAwBC,EAAOE,KACxC,OAAOF,EAAOE,KAGhB,MAAM,IAAIJ,MAAME,EAAOG,SAAW,6BACjC,CAACpC,EAAQC,EAAUC,IAEhBsC,EAAcf,cAAYC,MAAOe,UACrC,IAAKA,EAAQC,QAAUjC,EAAW,OAG9BU,EAAmBI,SACrBJ,EAAmBI,QAAQC,QAE7BL,EAAmBI,QAAU,IAAIoB,gBAEjC,MAAMC,EAAuB,CAC3BC,GAAI,OAAOC,KAAKC,QAChBC,KAAM,OACNP,QAASA,EAAQC,OACjBO,UAAW,IAAIH,MAGjBvC,EAAY2C,GAAQ,IAAIA,EAAMN,IAC9BlC,GAAa,GACbM,EAAS,MACTZ,SAAAA,EAAgBqC,GAEhB,IAEE,IAAIU,EAAiBlC,IAChBkC,GAAkB,IAAIL,KAAS,IAAIA,KAAKK,EAAeC,cAC1DD,QAAuBb,IACvBpB,EAAWiC,IAIb,MAAME,EAAqB,OAAOP,KAAKC,kBACjCO,EAA4B,CAChCT,GAAIQ,EACJL,KAAM,YACNP,QAAS,GACTQ,UAAW,IAAIH,KACfS,aAAa,GAEfhD,EAAY2C,GAAQ,IAAIA,EAAMI,IAG9B,MAAM3B,QAAiBC,MACrB,GAAG1B,mBAA4BD,cAAqBkD,EAAeK,qBACnE,CACEjB,OAAQ,OACRV,QAAS,CACP,YAAa7B,EACb,eAAgB,mBAChByD,OAAU,qBAEZC,KAAMC,KAAKC,UAAU,CAAExB,QAASK,IAChCoB,OAAQ1C,EAAmBI,QAAQsC,SAIvC,IAAKlC,EAASG,GACZ,MAAM,IAAIC,MAAM,2BAA2BJ,EAASK,UAGtD,MAAM8B,EAAsB,QAAbC,EAAApC,EAAS+B,YAAI,IAAAK,OAAA,EAAAA,EAAEC,YACxBC,EAAU,IAAIC,YACpB,IAAIC,EAAc,GAElB,GAAIL,EACF,OAAa,CACX,MAAMM,KAAEA,EAAIC,MAAEA,SAAgBP,EAAOQ,OACrC,GAAIF,EAAM,MAEV,MACMG,EADQN,EAAQO,OAAOH,EAAO,CAAEI,QAAQ,IAC1BC,MAAM,MAE1B,IAAK,MAAMC,KAAQJ,EACjB,GAAII,EAAKC,WAAW,UAClB,IACE,MAAMzC,EAAOwB,KAAKkB,MAAMF,EAAKG,MAAM,IAEnC,GAAkB,UAAd3C,EAAK4C,KACPZ,GAAehC,EAAKM,QACpBlC,EAAY2C,GACVA,EAAK8B,IAAIC,GACPA,EAAIpC,KAAOQ,EACP,IAAK4B,EAAKxC,QAAS0B,GACnBc,SAGH,GAAkB,SAAd9C,EAAK4C,KAAiB,CAC/BxE,EAAY2C,GACVA,EAAK8B,IAAIC,GACPA,EAAIpC,KAAOQ,EACP,IAAK4B,EAAK1B,aAAa,EAAO2B,QAAS/C,EAAK+C,SAC5CD,IAIR,MAAME,EAAwB,CAC5BtC,GAAIQ,EACJL,KAAM,YACNP,QAAS0B,EACTlB,UAAW,IAAIH,KACfoC,QAAS/C,EAAK+C,SAEhB7E,SAAAA,EAAoB8E,EACtB,CACF,CAAE,MAAAC,GAEF,CAGN,CAEJ,CAAE,MAAO/C,GACP,GAA4B,eAAvBA,EAAcgD,KAEjB,OAGF,MAAMtE,EAAQsB,aAAeN,MAAQM,EAAM,IAAIN,MAAM,0BACrDf,EAASD,GACTZ,SAAAA,EAAUY,GAGVR,EAAY2C,GAAQA,EAAKoC,OAAOL,IAAQA,EAAI1B,aAC9C,SACE7C,GAAa,EACf,GACC,CAACV,EAAQC,EAAUC,EAAYe,EAASR,EAAW6B,EAAenC,EAASC,EAAeC,IAEvFkF,EAAgB9D,EAAAA,YAAY,KAChClB,EAAY,IACZW,EAAW,OACV,IAEGsE,EAAQ/D,EAAAA,YAAY,KACxBT,EAAS,MACTM,KACC,CAACA,IAEJ,MAAO,CACLhB,WACAG,YACAE,cACAE,SACAE,QACAyB,cACA+C,gBACAC,QAEJ,CChPA,MAAMC,EAAqB,IACzBC,EAAAA,KAAA,MAAA,CACEC,UAAU,uBACVC,QAAQ,YACRC,MAAM,6BAA4BC,SAAA,CAElCC,MAAA,OAAA,CAAMC,EAAE,kGACRD,EAAAA,IAAA,OAAA,CAAMC,EAAE,gCAINC,EAAsB,IAC1BF,EAAAA,IAAA,MAAA,CACEJ,UAAU,uBACVC,QAAQ,YACRC,MAAM,6BAA4BC,SAElCC,EAAAA,IAAA,OAAA,CAAMC,EAAE,4GAICE,EAAwC,EACnDC,SACAC,UACAC,eAAe,UACfC,WAAW,eACXC,cAAc,KAGZb,EAAAA,KAAA,SAAA,CACEC,UAAW,mBAAmBW,IAC9BF,QAASA,EACTI,MAAO,CAAEC,gBAAiBJ,GAAc,aAC5BF,EAAS,aAAe,YACpCpB,KAAK,SAAQe,SAAA,CAEZK,EAASJ,EAAAA,IAACE,MAAeF,EAAAA,IAACN,EAAQ,KACjCU,GAAUI,EAAc,GACxBR,EAAAA,IAAA,OAAA,CAAMJ,UAAU,iCACbY,EAAc,EAAI,KAAOA,OCvC9BN,EAAsB,IAC1BF,EAAAA,IAAA,MAAA,CAAKH,QAAQ,YAAYC,MAAM,6BAA4BC,SACzDC,EAAAA,IAAA,OAAA,CACEW,KAAK,eACLV,EAAE,4GAKFW,EAAqB,IACzBZ,EAAAA,IAAA,MAAA,CAAKH,QAAQ,YAAYC,MAAM,sCAC7BE,EAAAA,IAAA,OAAA,CAAMC,EAAE,4CAINY,EAAwB,IAC5BlB,EAAAA,KAAA,MAAA,CAAKC,UAAU,mBAAkBG,SAAA,CAC/BC,EAAAA,IAAA,MAAA,CAAKJ,UAAU,yBACfI,EAAAA,IAAA,MAAA,CAAKJ,UAAU,yBACfI,EAAAA,IAAA,MAAA,CAAKJ,UAAU,4BAQbkB,EAA8C,EAAGzE,aACrDsD,EAAAA,KAAA,MAAA,CAAKC,UAAW,oBAAoBvD,EAAQY,OAAM8C,SAAA,CAChDC,EAAAA,IAAA,IAAA,CAAGJ,UAAU,2BAA0BG,SAAE1D,EAAQK,UAChDL,EAAQ8C,SAAW9C,EAAQ8C,QAAQ4B,OAAS,GAC3CpB,EAAAA,KAAA,MAAA,CAAKC,UAAU,2BAA0BG,SAAA,CACvCC,EAAAA,WAAKJ,UAAU,iCAAgCG,SAAA,aAC9C1D,EAAQ8C,QAAQF,IAAI,CAAC+B,EAAQC,IAC5BjB,EAAAA,IAAA,MAAA,CAAiBJ,UAAU,0BAAyBG,SACjDiB,EAAOE,OADAD,UASPE,EAAwC,EACnDf,SACAgB,UACAtG,SACAP,WACAG,YACA2G,oBAEA,MAAOC,EAAYC,GAAiB9G,EAAAA,SAAS,IACvC+G,EAAiBnG,EAAAA,OAAuB,MACxCoG,EAAWpG,EAAAA,OAA4B,MAG7CC,EAAAA,UAAU,WACc,QAAtB0C,EAAAwD,EAAehG,eAAO,IAAAwC,GAAAA,EAAE0D,eAAe,CAAEC,SAAU,YAClD,CAACpH,IAGJe,EAAAA,UAAU,WACJ8E,IACc,QAAhBpC,EAAAyD,EAASjG,eAAO,IAAAwC,GAAAA,EAAE4D,UAEnB,CAACxB,IAEJ,MAAMyB,EAAgBC,IACpBA,EAAEC,iBACET,EAAW3E,SAAWjC,IACxB2G,EAAcC,EAAW3E,QACzB4E,EAAc,MAWlB,IAAKnB,EAAQ,OAAO,KAEpB,MAAMG,GAAWzF,aAAM,EAANA,EAAQyF,WAAY,eAC/BD,GAAexF,aAAM,EAANA,EAAQwF,eAAgB,UAE7C,OACEX,OAAA,MAAA,CACEC,UAAW,mBAAmBW,IAC9BE,MAAO,CAAE,sBAAuBH,GAAqCP,SAAA,CAErEJ,EAAAA,KAAA,MAAA,CAAKC,UAAU,kBAAkBa,MAAO,CAAEC,gBAAiBJ,GAAcP,SAAA,CACvEC,EAAAA,IAAA,KAAA,CAAIJ,UAAU,wBAAuBG,UAAEjF,aAAM,EAANA,EAAQwE,OAAQ,SACvDU,MAAA,SAAA,CACEJ,UAAU,wBACVS,QAASe,EAAO,aACL,aACXpC,KAAK,SAAQe,SAEbC,EAAAA,IAACE,EAAS,CAAA,QAIdP,EAAAA,KAAA,MAAA,CAAKC,UAAU,oBAAmBG,SAAA,CACX,IAApBxF,EAASwG,SAAgBjG,aAAM,EAANA,EAAQkH,WAChChC,MAAA,MAAA,CAAKJ,UAAU,oBAAmBG,SAAEjF,EAAOkH,WAG5CzH,EAAS0E,IAAI5C,GACZ2D,EAAAA,IAACc,EAAa,CAAkBzE,QAASA,GAArBA,EAAQS,KAG7BpC,GAAasF,EAAAA,IAACa,EAAW,CAAA,GAE1Bb,EAAAA,IAAA,MAAA,CAAKiC,IAAKT,OAGZ7B,EAAAA,KAAA,OAAA,CAAMC,UAAU,2BAA2BsC,SAAUL,EAAY9B,SAAA,CAC/DC,EAAAA,IAAA,WAAA,CACEiC,IAAKR,EACL7B,UAAU,iBACVtB,MAAOgD,EACPa,SAAUL,GAAKP,EAAcO,EAAEM,OAAO9D,OACtC+D,UAjDeP,IACP,UAAVA,EAAEQ,KAAoBR,EAAES,WAC1BT,EAAEC,iBACFF,EAAaC,KA+CTU,aAAa1H,aAAM,EAANA,EAAQ0H,cAAe,oBACpCC,KAAM,EACNC,WAAW5H,aAAM,EAANA,EAAQ6H,uBAAwB,IAC3CC,SAAUlI,IAEZsF,EAAAA,IAAA,SAAA,CACEhB,KAAK,SACLY,UAAU,uBACVgD,UAAWtB,EAAW3E,QAAUjC,EAChC+F,MAAO,CAAEC,gBAAiBJ,GAAc,aAC7B,eAAcP,SAEzBC,EAAAA,IAACY,EAAQ,CAAA,SAIZ9F,eAAAA,EAAQ+H,gBACPlD,EAAAA,KAAA,MAAA,CAAKC,UAAU,sBAAqBG,SAAA,CAAA,cACvBC,EAAAA,IAAA,IAAA,CAAG8C,KAAK,yBAAyBV,OAAO,SAASW,IAAI,sBAAqBhD,SAAA,uBClJ/F,SAAqBiD,EAAKf,QACX,IAARA,IAAiBA,EAAM,CAAA,GAC5B,IAAIgB,EAAWhB,EAAIgB,SAEnB,GAAgC,oBAAbC,SAAnB,CAEA,IAAIC,EAAOD,SAASC,MAAQD,SAASE,qBAAqB,QAAQ,GAC9D3C,EAAQyC,SAASG,cAAc,SACnC5C,EAAMzB,KAAO,WAEI,QAAbiE,GACEE,EAAKG,WACPH,EAAKI,aAAa9C,EAAO0C,EAAKG,YAKhCH,EAAKK,YAAY/C,GAGfA,EAAMgD,WACRhD,EAAMgD,WAAWC,QAAUV,EAE3BvC,EAAM+C,YAAYN,SAASS,eAAeX,GAnBW,CAqBzD,kuKClBO,MAAMY,EAAwC,EACnD3J,SACAC,WACAC,aAAa,GACboG,WACAD,eACA0B,WACAQ,cACAK,gBACAzI,UACAC,gBACAC,wBAEA,MAAO8F,EAAQyD,GAAapJ,EAAAA,UAAS,GAG/BqJ,EAAU3J,IAAiC,oBAAX4J,OAAyBA,OAAOC,SAASC,OAAS,KAElF1J,SACJA,EAAQG,UACRA,EAASE,YACTA,EAAWE,OACXA,EAAME,MACNA,EAAKyB,YACLA,EAAWgD,MACXA,GACE1F,EAAc,CAChBE,SACAC,WACAC,WAAY2J,EACZ1J,UACAC,gBACAC,sBAII4J,EAAepJ,EAAS,IACzBA,EACHyF,SAAUA,GAAYzF,EAAOyF,SAC7BD,aAAcA,GAAgBxF,EAAOwF,aACrC0B,SAAUA,GAAYlH,EAAOkH,SAC7BQ,YAAaA,GAAe1H,EAAO0H,YACnCK,mBAAiCsB,IAAlBtB,EAA8BA,EAAgB/H,EAAO+H,eAClE,KAEEuB,EAAe,KACnBP,EAAU1G,IAASA,IAGfkH,EAAc,KAClBR,GAAU,IAIZ,OAAI7I,GAASoF,EAETT,OAAA,MAAA,CAAKC,UAAU,kBAAiBG,SAAA,CAC9BC,EAAAA,IAACG,EAAU,CACTC,OAAQA,EACRC,QAAS+D,EACT9D,aAAcA,GAAgB,UAC9BC,SAAUA,GAAY,iBAExBZ,EAAAA,KAAA,MAAA,CAAKC,UAAW,mBAAmBW,GAAY,iBAAgBR,SAAA,CAC7DJ,EAAAA,KAAA,MAAA,CAAKC,UAAU,kBAAkBa,MAAO,CAAEC,gBAAiBJ,GAAgB,WAAWP,SAAA,CACpFC,EAAAA,IAAA,KAAA,CAAIJ,UAAU,wBAAuBG,SAAA,SACrCC,EAAAA,IAAA,SAAA,CAAQJ,UAAU,wBAAwBS,QAASgE,EAAarF,KAAK,SAAQe,SAC3EC,EAAAA,IAAA,MAAA,CAAKH,QAAQ,YAAYC,MAAM,6BAA4BC,SACzDC,EAAAA,IAAA,OAAA,CACEW,KAAK,eACLV,EAAE,iHAKVN,EAAAA,KAAA,MAAA,CAAKC,UAAU,iBAAgBG,SAAA,CAC7BC,EAAAA,IAAA,IAAA,CAAGJ,UAAU,yBAAwBG,SAClC/E,EAAMqB,SAAW,yCAEpB2D,EAAAA,IAAA,SAAA,CAAQJ,UAAU,uBAAuBS,QAASZ,EAAOT,KAAK,SAAQe,SAAA,mBAU9EJ,OAAA,MAAA,CAAKC,UAAU,4BACbI,EAAAA,IAACG,EAAU,CACTC,OAAQA,EACRC,QAAS+D,EACT9D,cAAc4D,aAAY,EAAZA,EAAc5D,eAAgBA,GAAgB,UAC5DC,UAAU2D,aAAY,EAAZA,EAAc3D,WAAYA,GAAY,iBAEjD2D,GACClE,MAACmB,EAAU,CACTf,OAAQA,EACRgB,QAASiD,EACTvJ,OAAQoJ,EACR3J,SAAUA,EACVG,UAAWA,EACX2G,cAAe5E,QC/FnB6H,EAAoBC,EAAAA,cAA6C,yDAMF,EACnEtK,SACAC,WACAC,aAAa,GACbC,UACAC,gBACAC,oBACAyF,eAEA,MAEMyE,EAAazK,EAAc,CAC/BE,SACAC,WACAC,WALcA,IAAiC,oBAAX4J,OAAyBA,OAAOC,SAASC,OAAS,IAMtF7J,UACAC,gBACAC,sBAGIgE,EAAQmG,EAAAA,QAAQ,KAAA,CACpBlK,SAAUiK,EAAWjK,SACrBG,UAAW8J,EAAW9J,UACtBE,YAAa4J,EAAW5J,YACxBE,OAAQ0J,EAAW1J,OACnBE,MAAOwJ,EAAWxJ,MAClByB,YAAa+H,EAAW/H,YACxB+C,cAAegF,EAAWhF,cAC1BC,MAAO+E,EAAW/E,QAChB,CAAC+E,IAEL,OACExE,EAAAA,IAACsE,EAAkBI,SAAQ,CAACpG,MAAOA,EAAKyB,SACrCA,yEAK6B,KAClC,MAAM4E,EAAUC,EAAAA,WAAWN,GAC3B,IAAKK,EACH,MAAM,IAAI3I,MAAM,iEAElB,OAAO2I","x_google_ignoreList":[3]}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { ChatWidgetProps, WidgetConfig, Message } from '../types';
3
+ interface ChatWidgetContextValue {
4
+ messages: Message[];
5
+ isLoading: boolean;
6
+ isConnected: boolean;
7
+ config: WidgetConfig | null;
8
+ error: Error | null;
9
+ sendMessage: (content: string) => Promise<void>;
10
+ clearMessages: () => void;
11
+ retry: () => void;
12
+ }
13
+ export interface ChatWidgetProviderProps extends Omit<ChatWidgetProps, 'position' | 'primaryColor' | 'greeting' | 'placeholder' | 'showPoweredBy'> {
14
+ children: React.ReactNode;
15
+ }
16
+ export declare const ChatWidgetProvider: React.FC<ChatWidgetProviderProps>;
17
+ export declare const useChatWidgetContext: () => ChatWidgetContextValue;
18
+ export default ChatWidgetProvider;
@@ -0,0 +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}@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}}