@rag-widget/chat-widget 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/accessibility.test.d.ts +1 -0
- package/dist/components/ChatWidget.test.d.ts +1 -0
- package/dist/components/home/BookmarksRow.d.ts +6 -0
- package/dist/components/home/BookmarksRow.test.d.ts +1 -0
- package/dist/components/home/HeaderSection.d.ts +6 -0
- package/dist/components/home/HeaderSection.test.d.ts +1 -0
- package/dist/components/home/StartChatCard.d.ts +6 -0
- package/dist/components/home/StartChatCard.test.d.ts +1 -0
- package/dist/components/home/TicketCategoryList.d.ts +7 -0
- package/dist/components/home/TicketCategoryList.test.d.ts +1 -0
- package/dist/components/home/index.d.ts +8 -0
- package/dist/components/views/HomeView.d.ts +9 -0
- package/dist/components/views/HomeView.test.d.ts +1 -0
- package/dist/components/views/index.d.ts +2 -0
- package/dist/hooks/useViewNavigation.d.ts +10 -0
- package/dist/hooks/useViewNavigation.test.d.ts +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.esm.js +206 -41
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +229 -58
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/providers/ChatWidgetProvider.d.ts +7 -1
- package/dist/providers/ChatWidgetProvider.test.d.ts +1 -0
- package/dist/styles.css +1 -1
- package/dist/test/setup.d.ts +1 -0
- package/dist/types/homeView.test.d.ts +1 -0
- package/dist/types/index.d.ts +22 -0
- package/package.json +13 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TicketCategory } from '../../types';
|
|
3
|
+
export interface TicketCategoryListProps {
|
|
4
|
+
categories: TicketCategory[];
|
|
5
|
+
onCategoryClick: (categoryId: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const TicketCategoryList: React.FC<TicketCategoryListProps>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { HeaderSection } from './HeaderSection';
|
|
2
|
+
export type { HeaderSectionProps } from './HeaderSection';
|
|
3
|
+
export { StartChatCard } from './StartChatCard';
|
|
4
|
+
export type { StartChatCardProps } from './StartChatCard';
|
|
5
|
+
export { TicketCategoryList } from './TicketCategoryList';
|
|
6
|
+
export type { TicketCategoryListProps } from './TicketCategoryList';
|
|
7
|
+
export { BookmarksRow } from './BookmarksRow';
|
|
8
|
+
export type { BookmarksRowProps } from './BookmarksRow';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { WidgetConfig } from '../../types';
|
|
3
|
+
export interface HomeViewProps {
|
|
4
|
+
config: WidgetConfig;
|
|
5
|
+
onStartChat: () => void;
|
|
6
|
+
onTicketCategoryClick?: (categoryId: string) => void;
|
|
7
|
+
autoFocus?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const HomeView: React.FC<HomeViewProps>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WidgetView } from '../types';
|
|
2
|
+
export interface UseViewNavigationReturn {
|
|
3
|
+
currentView: WidgetView;
|
|
4
|
+
previousView: WidgetView | null;
|
|
5
|
+
canGoBack: boolean;
|
|
6
|
+
navigateToChat: () => void;
|
|
7
|
+
navigateToHome: () => void;
|
|
8
|
+
goBack: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const useViewNavigation: (initialView?: WidgetView) => UseViewNavigationReturn;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export { ChatWidget, default as default } from './components/ChatWidget';
|
|
2
2
|
export { ChatBubble } from './components/ChatBubble';
|
|
3
3
|
export { ChatWindow } from './components/ChatWindow';
|
|
4
|
+
export { HomeView } from './components/views/HomeView';
|
|
5
|
+
export { HeaderSection } from './components/home/HeaderSection';
|
|
6
|
+
export { StartChatCard } from './components/home/StartChatCard';
|
|
7
|
+
export { TicketCategoryList } from './components/home/TicketCategoryList';
|
|
8
|
+
export { BookmarksRow } from './components/home/BookmarksRow';
|
|
4
9
|
export { useChatWidget } from './hooks/useChatWidget';
|
|
10
|
+
export { useViewNavigation } from './hooks/useViewNavigation';
|
|
5
11
|
export { ChatWidgetProvider, useChatWidgetContext } from './providers/ChatWidgetProvider';
|
|
6
|
-
export type { ChatWidgetProps, ChatBubbleProps, ChatWindowProps, WidgetConfig, Message, Source, ChatSession, UsageInfo, ApiResponse } from './types';
|
|
12
|
+
export type { ChatWidgetProps, ChatBubbleProps, ChatWindowProps, WidgetConfig, Message, Source, ChatSession, UsageInfo, ApiResponse, WidgetView, HomeViewConfig, TicketCategory, Bookmark, } from './types';
|
|
7
13
|
import './styles/widget.css';
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef, useEffect, useCallback, createContext, useMemo, useContext } from 'react';
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import React, { useState, useRef, useEffect, useCallback, createContext, useMemo, useContext } from 'react';
|
|
3
3
|
|
|
4
4
|
function useChatWidget(options) {
|
|
5
5
|
const { apiKey, widgetId, apiBaseUrl, onError, onMessageSent, onMessageReceived } = options;
|
|
@@ -190,10 +190,195 @@ function useChatWidget(options) {
|
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
const
|
|
193
|
+
const useViewNavigation = (initialView = 'home') => {
|
|
194
|
+
const [state, setState] = useState({
|
|
195
|
+
currentView: initialView,
|
|
196
|
+
previousView: null,
|
|
197
|
+
});
|
|
198
|
+
const navigateToChat = useCallback(() => {
|
|
199
|
+
setState((prev) => ({
|
|
200
|
+
currentView: 'chat',
|
|
201
|
+
previousView: prev.currentView,
|
|
202
|
+
}));
|
|
203
|
+
}, []);
|
|
204
|
+
const navigateToHome = useCallback(() => {
|
|
205
|
+
setState((prev) => ({
|
|
206
|
+
currentView: 'home',
|
|
207
|
+
previousView: prev.currentView,
|
|
208
|
+
}));
|
|
209
|
+
}, []);
|
|
210
|
+
const goBack = useCallback(() => {
|
|
211
|
+
if (state.currentView !== 'home') {
|
|
212
|
+
setState((prev) => ({
|
|
213
|
+
currentView: 'home',
|
|
214
|
+
previousView: prev.currentView,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
}, [state.currentView]);
|
|
218
|
+
const canGoBack = state.currentView !== 'home';
|
|
219
|
+
return {
|
|
220
|
+
currentView: state.currentView,
|
|
221
|
+
previousView: state.previousView,
|
|
222
|
+
canGoBack,
|
|
223
|
+
navigateToChat,
|
|
224
|
+
navigateToHome,
|
|
225
|
+
goBack,
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const ChatIcon$1 = () => (jsxs("svg", { className: "rag-chat-bubble-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: [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" }), jsx("path", { d: "M7 9h10v2H7zm0-3h10v2H7z" })] }));
|
|
194
230
|
const CloseIcon$1 = () => (jsx("svg", { className: "rag-chat-bubble-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: 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" }) }));
|
|
195
231
|
const ChatBubble = ({ isOpen, onClick, primaryColor = '#007bff', position = 'bottom-right', unreadCount = 0 }) => {
|
|
196
|
-
return (jsxs("button", { className: `rag-chat-bubble ${position}`, onClick: onClick, style: { backgroundColor: primaryColor }, "aria-label": isOpen ? 'Close chat' : 'Open chat', type: "button", children: [isOpen ? jsx(CloseIcon$1, {}) : jsx(ChatIcon, {}), !isOpen && unreadCount > 0 && (jsx("span", { className: "rag-chat-bubble-badge", children: unreadCount > 9 ? '9+' : unreadCount }))] }));
|
|
232
|
+
return (jsxs("button", { className: `rag-chat-bubble ${position}`, onClick: onClick, style: { backgroundColor: primaryColor }, "aria-label": isOpen ? 'Close chat' : 'Open chat', type: "button", children: [isOpen ? jsx(CloseIcon$1, {}) : jsx(ChatIcon$1, {}), !isOpen && unreadCount > 0 && (jsx("span", { className: "rag-chat-bubble-badge", children: unreadCount > 9 ? '9+' : unreadCount }))] }));
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const HeaderSection = ({ greeting, logoUrl, }) => {
|
|
236
|
+
return (jsxs("div", { className: "rag-home-header", children: [logoUrl && (jsx("img", { src: logoUrl, alt: "Logo", className: "rag-home-logo" })), jsx("h2", { className: "rag-home-greeting", children: greeting })] }));
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const ChatIcon = () => (jsx("svg", { "data-testid": "chat-icon", className: "rag-start-chat-card__icon", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
240
|
+
const ArrowIcon = () => (jsx("svg", { "data-testid": "arrow-icon", className: "rag-start-chat-card__arrow", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M9 18l6-6-6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
241
|
+
const StartChatCard = React.forwardRef(({ onStartChat, subtitle, }, ref) => {
|
|
242
|
+
const handleKeyDown = (e) => {
|
|
243
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
onStartChat();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
return (jsxs("button", { ref: ref, type: "button", className: "rag-start-chat-card", onClick: onStartChat, onKeyDown: handleKeyDown, "aria-label": "Start new chat conversation", children: [jsx(ChatIcon, {}), jsxs("div", { className: "rag-start-chat-card__content", children: [jsx("div", { className: "rag-start-chat-card__title", children: "Start new chat" }), subtitle && (jsx("div", { className: "rag-start-chat-card__subtitle", children: subtitle }))] }), jsx(ArrowIcon, {})] }));
|
|
249
|
+
});
|
|
250
|
+
// Display name for debugging
|
|
251
|
+
StartChatCard.displayName = 'StartChatCard';
|
|
252
|
+
|
|
253
|
+
const ChevronIcon = () => (jsx("svg", { className: "rag-ticket-category__chevron", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M9 18l6-6-6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
254
|
+
const TicketCategoryList = ({ categories, onCategoryClick, }) => {
|
|
255
|
+
const enabledCategories = categories.filter((cat) => cat.enabled);
|
|
256
|
+
if (enabledCategories.length === 0) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
return (jsxs("div", { className: "rag-ticket-section", children: [jsx("div", { className: "rag-ticket-section__title", children: "Submit a ticket" }), jsx("div", { className: "rag-ticket-list", children: enabledCategories.map((category) => (jsxs("button", { type: "button", className: "rag-ticket-category", onClick: () => onCategoryClick(category.id), "aria-label": `Submit ${category.label} ticket`, children: [jsx("span", { className: "rag-ticket-category__icon", children: category.icon }), jsx("span", { className: "rag-ticket-category__label", children: category.label }), jsx(ChevronIcon, {})] }, category.id))) })] }));
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const BookmarksRow = ({ bookmarks }) => {
|
|
263
|
+
if (bookmarks.length === 0) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
return (jsxs("nav", { className: "rag-bookmarks-section", role: "navigation", "aria-label": "Quick links", children: [jsx("div", { className: "rag-bookmarks-section__title", id: "bookmarks-title", children: "Bookmarks" }), jsx("div", { className: "rag-bookmarks-row", "aria-labelledby": "bookmarks-title", children: bookmarks.map((bookmark) => (jsxs("a", { href: bookmark.url, target: "_blank", rel: "noopener noreferrer", className: "rag-bookmark", "aria-label": `${bookmark.label} - opens in new tab`, children: [jsx("span", { className: "rag-bookmark__icon", "aria-hidden": "true", children: bookmark.icon }), jsx("span", { className: "rag-bookmark__label", children: bookmark.label })] }, bookmark.id))) })] }));
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const HomeView = ({ config, onStartChat, onTicketCategoryClick, autoFocus = false, }) => {
|
|
270
|
+
const homeConfig = config.homeView;
|
|
271
|
+
const startChatRef = useRef(null);
|
|
272
|
+
// Auto-focus first interactive element when autoFocus is enabled
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (autoFocus && startChatRef.current) {
|
|
275
|
+
startChatRef.current.focus();
|
|
276
|
+
}
|
|
277
|
+
}, [autoFocus]);
|
|
278
|
+
// Don't render if home view is not enabled or missing
|
|
279
|
+
if (!(homeConfig === null || homeConfig === void 0 ? void 0 : homeConfig.enabled)) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
// Use homeView greeting, fallback to widget greeting
|
|
283
|
+
const greeting = homeConfig.greeting || config.greeting;
|
|
284
|
+
const handleTicketCategoryClick = (categoryId) => {
|
|
285
|
+
if (onTicketCategoryClick) {
|
|
286
|
+
onTicketCategoryClick(categoryId);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
// Default behavior: log "Coming soon" message
|
|
290
|
+
console.log('Ticket category clicked (Coming soon):', categoryId);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
return (jsxs("div", { className: "rag-home-view", role: "region", "aria-label": "Help Center Home", children: [jsx(HeaderSection, { greeting: greeting, logoUrl: homeConfig.logoUrl }), homeConfig.showStartChat && (jsx(StartChatCard, { ref: startChatRef, onStartChat: onStartChat, subtitle: "How can we help you?" })), homeConfig.ticketCategories && homeConfig.ticketCategories.length > 0 && (jsx(TicketCategoryList, { categories: homeConfig.ticketCategories, onCategoryClick: handleTicketCategoryClick })), homeConfig.bookmarks && homeConfig.bookmarks.length > 0 && (jsx(BookmarksRow, { bookmarks: homeConfig.bookmarks })), config.showPoweredBy && (jsxs("div", { className: "rag-home-footer", children: ["Powered by ", jsx("a", { href: "https://rag-widget.com", target: "_blank", rel: "noopener noreferrer", children: "RAG Widget" })] }))] }));
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const ChatWidget = ({ apiKey, widgetId, apiBaseUrl = '', position, primaryColor, greeting, placeholder, showPoweredBy, onError, onMessageSent, onMessageReceived }) => {
|
|
297
|
+
var _a, _b, _c;
|
|
298
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
299
|
+
// Determine the API base URL
|
|
300
|
+
const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
|
|
301
|
+
const { messages, isLoading, config, error, sendMessage, retry } = useChatWidget({
|
|
302
|
+
apiKey,
|
|
303
|
+
widgetId,
|
|
304
|
+
apiBaseUrl: baseUrl,
|
|
305
|
+
onError,
|
|
306
|
+
onMessageSent,
|
|
307
|
+
onMessageReceived
|
|
308
|
+
});
|
|
309
|
+
// Merge props with fetched config (props take precedence)
|
|
310
|
+
const mergedConfig = config ? {
|
|
311
|
+
...config,
|
|
312
|
+
position: position || config.position,
|
|
313
|
+
primaryColor: primaryColor || config.primaryColor,
|
|
314
|
+
greeting: greeting || config.greeting,
|
|
315
|
+
placeholder: placeholder || config.placeholder,
|
|
316
|
+
showPoweredBy: showPoweredBy !== undefined ? showPoweredBy : config.showPoweredBy
|
|
317
|
+
} : null;
|
|
318
|
+
// Determine initial view based on home view configuration
|
|
319
|
+
const homeViewEnabled = (_b = (_a = mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.homeView) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : false;
|
|
320
|
+
const initialView = homeViewEnabled ? 'home' : 'chat';
|
|
321
|
+
const { currentView, canGoBack, navigateToChat, navigateToHome, } = useViewNavigation(initialView);
|
|
322
|
+
// Update view when config loads - fixes race condition where config isn't
|
|
323
|
+
// available on first render but homeView.enabled is true
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
var _a;
|
|
326
|
+
if (((_a = mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.homeView) === null || _a === void 0 ? void 0 : _a.enabled) && currentView === 'chat') {
|
|
327
|
+
navigateToHome();
|
|
328
|
+
}
|
|
329
|
+
}, [(_c = mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.homeView) === null || _c === void 0 ? void 0 : _c.enabled]);
|
|
330
|
+
const handleToggle = () => {
|
|
331
|
+
setIsOpen(prev => !prev);
|
|
332
|
+
};
|
|
333
|
+
const handleClose = () => {
|
|
334
|
+
setIsOpen(false);
|
|
335
|
+
};
|
|
336
|
+
const handleStartChat = () => {
|
|
337
|
+
navigateToChat();
|
|
338
|
+
};
|
|
339
|
+
const handleBack = () => {
|
|
340
|
+
navigateToHome();
|
|
341
|
+
};
|
|
342
|
+
const effectivePrimaryColor = (mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.primaryColor) || primaryColor || '#007bff';
|
|
343
|
+
const effectivePosition = (mergedConfig === null || mergedConfig === void 0 ? void 0 : mergedConfig.position) || position || 'bottom-right';
|
|
344
|
+
// Show error state in the window if there's an error
|
|
345
|
+
if (error && isOpen) {
|
|
346
|
+
return (jsxs("div", { className: "rag-chat-widget", children: [jsx(ChatBubble, { isOpen: isOpen, onClick: handleToggle, primaryColor: effectivePrimaryColor, position: effectivePosition }), jsxs("div", { className: `rag-chat-window ${effectivePosition}`, children: [jsxs("div", { className: "rag-chat-header", style: { backgroundColor: effectivePrimaryColor }, children: [jsx("h3", { className: "rag-chat-header-title", children: "Chat" }), jsx("button", { className: "rag-chat-header-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: 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" }) }) })] }), jsxs("div", { className: "rag-chat-error", children: [jsx("p", { className: "rag-chat-error-message", children: error.message || 'Unable to connect. Please try again.' }), jsx("button", { className: "rag-chat-error-retry", onClick: retry, type: "button", children: "Retry" })] })] })] }));
|
|
347
|
+
}
|
|
348
|
+
// Determine which view to render
|
|
349
|
+
const shouldShowHomeView = currentView === 'home' && homeViewEnabled && mergedConfig;
|
|
350
|
+
const shouldShowChatView = currentView === 'chat' || !homeViewEnabled;
|
|
351
|
+
return (jsxs("div", { className: "rag-chat-widget", children: [jsx(ChatBubble, { isOpen: isOpen, onClick: handleToggle, primaryColor: effectivePrimaryColor, position: effectivePosition }), isOpen && mergedConfig && (jsxs("div", { className: `rag-chat-window ${effectivePosition}`, style: { '--rag-primary-color': effectivePrimaryColor }, children: [jsxs("div", { className: "rag-chat-header", style: { backgroundColor: effectivePrimaryColor }, children: [jsxs("div", { className: "rag-chat-header-left", children: [canGoBack && (jsx("button", { className: "rag-chat-header-back", onClick: handleBack, type: "button", "aria-label": "Back to home", children: jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { fill: "currentColor", d: "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" }) }) })), jsx("h3", { className: "rag-chat-header-title", children: mergedConfig.name || 'Chat' })] }), jsx("button", { className: "rag-chat-header-close", onClick: handleClose, "aria-label": "Close chat", type: "button", children: jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: 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" }) }) })] }), jsxs("div", { className: "rag-view-container", children: [shouldShowHomeView && (jsx(HomeView, { config: mergedConfig, onStartChat: handleStartChat })), shouldShowChatView && (jsx(ChatWindowContent, { config: mergedConfig, messages: messages, isLoading: isLoading, onSendMessage: sendMessage }))] })] }))] }));
|
|
352
|
+
};
|
|
353
|
+
const ChatWindowContent = ({ config, messages, isLoading, onSendMessage, }) => {
|
|
354
|
+
const [inputValue, setInputValue] = React.useState('');
|
|
355
|
+
const messagesEndRef = React.useRef(null);
|
|
356
|
+
const inputRef = React.useRef(null);
|
|
357
|
+
// Scroll to bottom when new messages arrive
|
|
358
|
+
React.useEffect(() => {
|
|
359
|
+
if (messagesEndRef.current && typeof messagesEndRef.current.scrollIntoView === 'function') {
|
|
360
|
+
messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
|
|
361
|
+
}
|
|
362
|
+
}, [messages]);
|
|
363
|
+
// Focus input when content mounts
|
|
364
|
+
React.useEffect(() => {
|
|
365
|
+
var _a;
|
|
366
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
367
|
+
}, []);
|
|
368
|
+
const handleSubmit = (e) => {
|
|
369
|
+
e.preventDefault();
|
|
370
|
+
if (inputValue.trim() && !isLoading) {
|
|
371
|
+
onSendMessage(inputValue.trim());
|
|
372
|
+
setInputValue('');
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
const handleKeyDown = (e) => {
|
|
376
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
377
|
+
e.preventDefault();
|
|
378
|
+
handleSubmit(e);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: "rag-chat-messages", children: [messages.length === 0 && (config.uspText || config.greeting) && (jsxs("div", { className: "rag-chat-greeting", children: [config.uspText && (jsx("p", { className: "rag-chat-usp-text", children: config.uspText })), config.greeting && (jsx("p", { className: "rag-chat-greeting-text", children: config.greeting }))] })), messages.map(message => (jsxs("div", { className: `rag-chat-message ${message.role}`, children: [message.isStreaming && !message.content ? (jsxs("div", { className: "rag-chat-loading", children: [jsx("div", { className: "rag-chat-loading-dot" }), jsx("div", { className: "rag-chat-loading-dot" }), jsx("div", { className: "rag-chat-loading-dot" })] })) : (jsx("p", { className: "rag-chat-message-content", children: message.content })), message.sources && message.sources.length > 0 && (jsxs("div", { className: "rag-chat-message-sources", children: [jsx("div", { className: "rag-chat-message-sources-title", children: "Sources:" }), message.sources.map((source, index) => (jsx("div", { className: "rag-chat-message-source", children: source.title }, index)))] }))] }, message.id))), jsx("div", { ref: messagesEndRef })] }), jsxs("form", { className: "rag-chat-input-container", onSubmit: handleSubmit, children: [jsx("textarea", { ref: inputRef, className: "rag-chat-input", value: inputValue, onChange: e => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder: config.placeholder || 'Type a message...', rows: 1, maxLength: config.allowedMessageLength || 2000, disabled: isLoading }), jsx("button", { type: "submit", className: "rag-chat-send-button", disabled: !inputValue.trim() || isLoading, style: { backgroundColor: config.primaryColor }, "aria-label": "Send message", children: jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) }) })] }), config.showPoweredBy && (jsxs("div", { className: "rag-chat-powered-by", children: ["Powered by ", jsx("a", { href: "https://rag-widget.com", target: "_blank", rel: "noopener noreferrer", children: "RAG Widget" })] }))] }));
|
|
197
382
|
};
|
|
198
383
|
|
|
199
384
|
const CloseIcon = () => (jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: 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" }) }));
|
|
@@ -236,42 +421,9 @@ const ChatWindow = ({ isOpen, onClose, config, messages, isLoading, onSendMessag
|
|
|
236
421
|
return (jsxs("div", { className: `rag-chat-window ${position}`, style: { '--rag-primary-color': primaryColor }, children: [jsxs("div", { className: "rag-chat-header", style: { backgroundColor: primaryColor }, children: [jsx("h3", { className: "rag-chat-header-title", children: (config === null || config === void 0 ? void 0 : config.name) || 'Chat' }), jsx("button", { className: "rag-chat-header-close", onClick: onClose, "aria-label": "Close chat", type: "button", children: jsx(CloseIcon, {}) })] }), jsxs("div", { className: "rag-chat-messages", children: [messages.length === 0 && ((config === null || config === void 0 ? void 0 : config.uspText) || (config === null || config === void 0 ? void 0 : config.greeting)) && (jsxs("div", { className: "rag-chat-greeting", children: [(config === null || config === void 0 ? void 0 : config.uspText) && (jsx("p", { className: "rag-chat-usp-text", children: config.uspText })), (config === null || config === void 0 ? void 0 : config.greeting) && (jsx("p", { className: "rag-chat-greeting-text", children: config.greeting }))] })), messages.map(message => (jsx(MessageBubble, { message: message }, message.id))), jsx("div", { ref: messagesEndRef })] }), jsxs("form", { className: "rag-chat-input-container", onSubmit: handleSubmit, children: [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 }), jsx("button", { type: "submit", className: "rag-chat-send-button", disabled: !inputValue.trim() || isLoading, style: { backgroundColor: primaryColor }, "aria-label": "Send message", children: jsx(SendIcon, {}) })] }), (config === null || config === void 0 ? void 0 : config.showPoweredBy) && (jsxs("div", { className: "rag-chat-powered-by", children: ["Powered by ", jsx("a", { href: "https://rag-widget.com", target: "_blank", rel: "noopener noreferrer", children: "RAG Widget" })] }))] }));
|
|
237
422
|
};
|
|
238
423
|
|
|
239
|
-
const ChatWidget = ({ apiKey, widgetId, apiBaseUrl = '', position, primaryColor, greeting, placeholder, showPoweredBy, onError, onMessageSent, onMessageReceived }) => {
|
|
240
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
241
|
-
// Determine the API base URL
|
|
242
|
-
const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
|
|
243
|
-
const { messages, isLoading, isConnected, config, error, sendMessage, retry } = useChatWidget({
|
|
244
|
-
apiKey,
|
|
245
|
-
widgetId,
|
|
246
|
-
apiBaseUrl: baseUrl,
|
|
247
|
-
onError,
|
|
248
|
-
onMessageSent,
|
|
249
|
-
onMessageReceived
|
|
250
|
-
});
|
|
251
|
-
// Merge props with fetched config (props take precedence)
|
|
252
|
-
const mergedConfig = config ? {
|
|
253
|
-
...config,
|
|
254
|
-
position: position || config.position,
|
|
255
|
-
primaryColor: primaryColor || config.primaryColor,
|
|
256
|
-
greeting: greeting || config.greeting,
|
|
257
|
-
placeholder: placeholder || config.placeholder,
|
|
258
|
-
showPoweredBy: showPoweredBy !== undefined ? showPoweredBy : config.showPoweredBy
|
|
259
|
-
} : null;
|
|
260
|
-
const handleToggle = () => {
|
|
261
|
-
setIsOpen(prev => !prev);
|
|
262
|
-
};
|
|
263
|
-
const handleClose = () => {
|
|
264
|
-
setIsOpen(false);
|
|
265
|
-
};
|
|
266
|
-
// Show error state in the window if there's an error
|
|
267
|
-
if (error && isOpen) {
|
|
268
|
-
return (jsxs("div", { className: "rag-chat-widget", children: [jsx(ChatBubble, { isOpen: isOpen, onClick: handleToggle, primaryColor: primaryColor || '#007bff', position: position || 'bottom-right' }), jsxs("div", { className: `rag-chat-window ${position || 'bottom-right'}`, children: [jsxs("div", { className: "rag-chat-header", style: { backgroundColor: primaryColor || '#007bff' }, children: [jsx("h3", { className: "rag-chat-header-title", children: "Chat" }), jsx("button", { className: "rag-chat-header-close", onClick: handleClose, type: "button", children: jsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: 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" }) }) })] }), jsxs("div", { className: "rag-chat-error", children: [jsx("p", { className: "rag-chat-error-message", children: error.message || 'Unable to connect. Please try again.' }), jsx("button", { className: "rag-chat-error-retry", onClick: retry, type: "button", children: "Retry" })] })] })] }));
|
|
269
|
-
}
|
|
270
|
-
return (jsxs("div", { className: "rag-chat-widget", children: [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 && (jsx(ChatWindow, { isOpen: isOpen, onClose: handleClose, config: mergedConfig, messages: messages, isLoading: isLoading, onSendMessage: sendMessage }))] }));
|
|
271
|
-
};
|
|
272
|
-
|
|
273
424
|
const ChatWidgetContext = createContext(null);
|
|
274
425
|
const ChatWidgetProvider = ({ apiKey, widgetId, apiBaseUrl = '', onError, onMessageSent, onMessageReceived, children }) => {
|
|
426
|
+
var _a, _b, _c;
|
|
275
427
|
const baseUrl = apiBaseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
|
|
276
428
|
const chatWidget = useChatWidget({
|
|
277
429
|
apiKey,
|
|
@@ -281,7 +433,13 @@ const ChatWidgetProvider = ({ apiKey, widgetId, apiBaseUrl = '', onError, onMess
|
|
|
281
433
|
onMessageSent,
|
|
282
434
|
onMessageReceived
|
|
283
435
|
});
|
|
436
|
+
// Determine initial view based on config
|
|
437
|
+
// If homeView is enabled, start with home; otherwise start with chat
|
|
438
|
+
const homeViewEnabled = (_c = (_b = (_a = chatWidget.config) === null || _a === void 0 ? void 0 : _a.homeView) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : false;
|
|
439
|
+
const initialView = homeViewEnabled ? 'home' : 'chat';
|
|
440
|
+
const viewNavigation = useViewNavigation(initialView);
|
|
284
441
|
const value = useMemo(() => ({
|
|
442
|
+
// Chat state
|
|
285
443
|
messages: chatWidget.messages,
|
|
286
444
|
isLoading: chatWidget.isLoading,
|
|
287
445
|
isConnected: chatWidget.isConnected,
|
|
@@ -289,8 +447,15 @@ const ChatWidgetProvider = ({ apiKey, widgetId, apiBaseUrl = '', onError, onMess
|
|
|
289
447
|
error: chatWidget.error,
|
|
290
448
|
sendMessage: chatWidget.sendMessage,
|
|
291
449
|
clearMessages: chatWidget.clearMessages,
|
|
292
|
-
retry: chatWidget.retry
|
|
293
|
-
|
|
450
|
+
retry: chatWidget.retry,
|
|
451
|
+
// View navigation
|
|
452
|
+
currentView: viewNavigation.currentView,
|
|
453
|
+
previousView: viewNavigation.previousView,
|
|
454
|
+
canGoBack: viewNavigation.canGoBack,
|
|
455
|
+
navigateToChat: viewNavigation.navigateToChat,
|
|
456
|
+
navigateToHome: viewNavigation.navigateToHome,
|
|
457
|
+
goBack: viewNavigation.goBack,
|
|
458
|
+
}), [chatWidget, viewNavigation]);
|
|
294
459
|
return (jsx(ChatWidgetContext.Provider, { value: value, children: children }));
|
|
295
460
|
};
|
|
296
461
|
const useChatWidgetContext = () => {
|
|
@@ -301,5 +466,5 @@ const useChatWidgetContext = () => {
|
|
|
301
466
|
return context;
|
|
302
467
|
};
|
|
303
468
|
|
|
304
|
-
export { ChatBubble, ChatWidget, ChatWidgetProvider, ChatWindow, ChatWidget as default, useChatWidget, useChatWidgetContext };
|
|
469
|
+
export { BookmarksRow, ChatBubble, ChatWidget, ChatWidgetProvider, ChatWindow, HeaderSection, HomeView, StartChatCard, TicketCategoryList, ChatWidget as default, useChatWidget, useChatWidgetContext, useViewNavigation };
|
|
305
470
|
//# sourceMappingURL=index.esm.js.map
|