@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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import type { Bookmark } from '../../types';
3
+ export interface BookmarksRowProps {
4
+ bookmarks: Bookmark[];
5
+ }
6
+ export declare const BookmarksRow: React.FC<BookmarksRowProps>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export interface HeaderSectionProps {
3
+ greeting: string;
4
+ logoUrl?: string;
5
+ }
6
+ export declare const HeaderSection: React.FC<HeaderSectionProps>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export interface StartChatCardProps {
3
+ onStartChat: () => void;
4
+ subtitle?: string;
5
+ }
6
+ export declare const StartChatCard: React.ForwardRefExoticComponent<StartChatCardProps & React.RefAttributes<HTMLButtonElement>>;
@@ -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,2 @@
1
+ export { HomeView } from './HomeView';
2
+ export type { HomeViewProps } from './HomeView';
@@ -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 ChatIcon = () => (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" })] }));
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
- }), [chatWidget]);
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