fyrebot-widget 1.4.1 → 1.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ChatbotWidget.d.ts","sourceRoot":"","sources":["../src/ChatbotWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAE1D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA2+BjD,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ChatbotWidget.d.ts","sourceRoot":"","sources":["../src/ChatbotWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAG1D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmhDjD,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -1,12 +1,13 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /**
3
3
  * Chatbot Popup Widget
4
4
  * Production-ready, standalone chatbot component
5
5
  */
6
6
  import { useState, useRef, useEffect, useCallback } from 'react';
7
- import { MessageCircle, X, Send, Loader2, Bot, User, Sparkles, RefreshCw } from 'lucide-react';
7
+ import { MessageCircle, X, Send, Loader2, Bot, User, Sparkles, RefreshCw, Mail, ArrowLeft, CheckCircle } from 'lucide-react';
8
8
  import { ChatbotApiClient } from './api';
9
- export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle = 'Ask me anything', brandName, primaryColor = '#6366f1', welcomeMessage = 'Hello! How can I help you today?', placeholder = 'Type your message...', position = 'bottom-right', showTypingIndicator = true, showTimestamps = true, showSources = false, showSuggestedQuestions = true, suggestedQuestions: customSuggestions, maxSuggestions = 4, maxHeight = '600px', maxWidth = '400px', className = '', onOpen, onClose, onMessageSent, onMessageReceived, onError, }) => {
9
+ import { MessageRenderer } from './MessageRenderer';
10
+ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle = 'Ask me anything', brandName, primaryColor = '#6366f1', welcomeMessage = 'Hello! How can I help you today?', placeholder = 'Type your message...', position = 'bottom-right', showTypingIndicator = true, showTimestamps = true, showSources = false, showSuggestedQuestions = true, enableContactSupport = true, suggestedQuestions: customSuggestions, maxSuggestions = 4, maxHeight = '600px', maxWidth = '400px', fontSize = '13px', headerFontSize = '15px', smallFontSize = '11px', className = '', onOpen, onClose, onMessageSent, onMessageReceived, onError, }) => {
10
11
  const [isOpen, setIsOpen] = useState(false);
11
12
  const [messages, setMessages] = useState([]);
12
13
  const [input, setInput] = useState('');
@@ -14,6 +15,17 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
14
15
  const [error, setError] = useState(null);
15
16
  const [suggestions, setSuggestions] = useState([]);
16
17
  const [loadingSuggestions, setLoadingSuggestions] = useState(false);
18
+ const [showContactPrompt, setShowContactPrompt] = useState(false);
19
+ // Support form states
20
+ const [showSupportForm, setShowSupportForm] = useState(false);
21
+ const [supportFormData, setSupportFormData] = useState({
22
+ name: '',
23
+ email: '',
24
+ message: '',
25
+ });
26
+ const [isSubmittingTicket, setIsSubmittingTicket] = useState(false);
27
+ const [ticketSubmitted, setTicketSubmitted] = useState(false);
28
+ const [ticketNumber, setTicketNumber] = useState(null);
17
29
  const scrollRef = useRef(null);
18
30
  const apiClient = useRef(null);
19
31
  // Initialize API client
@@ -25,7 +37,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
25
37
  if (scrollRef.current) {
26
38
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
27
39
  }
28
- }, [messages, isLoading]);
40
+ }, [messages, isLoading, showContactPrompt]);
29
41
  // Fetch suggestions when chat opens and no messages exist
30
42
  useEffect(() => {
31
43
  const fetchSuggestions = async () => {
@@ -53,6 +65,62 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
53
65
  };
54
66
  fetchSuggestions();
55
67
  }, [isOpen, messages.length, showSuggestedQuestions, customSuggestions, maxSuggestions]);
68
+ // Detect if user wants to contact support
69
+ const detectContactIntent = useCallback((message) => {
70
+ if (!enableContactSupport)
71
+ return false;
72
+ const lowerMessage = message.toLowerCase().trim();
73
+ // Direct support keywords
74
+ const contactKeywords = [
75
+ 'contact support',
76
+ 'talk to support',
77
+ 'speak to someone',
78
+ 'human support',
79
+ 'real person',
80
+ 'customer service',
81
+ 'help desk',
82
+ 'create ticket',
83
+ 'open ticket',
84
+ 'submit ticket',
85
+ 'generate ticket',
86
+ 'make ticket',
87
+ 'new ticket',
88
+ 'email support',
89
+ 'need help',
90
+ 'talk to team',
91
+ 'speak to team',
92
+ 'contact team',
93
+ 'reach out',
94
+ 'get in touch',
95
+ 'escalate',
96
+ 'not satisfied',
97
+ 'doesn\'t work',
98
+ 'still having issues',
99
+ 'not working',
100
+ 'urgent',
101
+ 'contact you',
102
+ 'contact aasim',
103
+ 'talk to aasim',
104
+ 'reach aasim',
105
+ 'speak with',
106
+ 'get support',
107
+ ];
108
+ // Question-based patterns (user asking how to contact)
109
+ const questionPatterns = [
110
+ /can i (contact|reach|talk to|speak to|speak with|get in touch)/i,
111
+ /how (do i|can i|to) (contact|reach|talk to|speak to|get support)/i,
112
+ /i (want|need|would like) to (contact|reach|talk to|speak to|create|generate|open|submit|make).*(support|ticket|team|you|aasim|someone)/i,
113
+ /where (can|do) i (contact|reach|get support)/i,
114
+ /is there (a way|someone) (to|i can) (contact|talk to|reach)/i,
115
+ /(contact|support|help).*(email|phone|number)/i,
116
+ /can.*(help|support|assist).*(me|us)/i,
117
+ ];
118
+ // Check direct keywords
119
+ const hasKeyword = contactKeywords.some(keyword => lowerMessage.includes(keyword));
120
+ // Check question patterns
121
+ const hasPattern = questionPatterns.some(pattern => pattern.test(message));
122
+ return hasKeyword || hasPattern;
123
+ }, [enableContactSupport]);
56
124
  // Handle open/close
57
125
  const handleToggle = useCallback(() => {
58
126
  const newState = !isOpen;
@@ -60,6 +128,8 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
60
128
  if (newState) {
61
129
  onOpen?.();
62
130
  setError(null);
131
+ setShowSupportForm(false);
132
+ setTicketSubmitted(false);
63
133
  }
64
134
  else {
65
135
  onClose?.();
@@ -90,7 +160,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
90
160
  setInput('');
91
161
  setIsLoading(true);
92
162
  setError(null);
163
+ setShowContactPrompt(false); // Reset prompt
93
164
  onMessageSent?.(userMessage.content);
165
+ // Check if user wants to contact support
166
+ const wantsContact = detectContactIntent(textToSend);
94
167
  try {
95
168
  const response = await apiClient.current.sendMessage(userMessage.content);
96
169
  const assistantMessage = {
@@ -102,6 +175,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
102
175
  };
103
176
  setMessages((prev) => [...prev, assistantMessage]);
104
177
  onMessageReceived?.(assistantMessage);
178
+ // Show contact prompt if detected and enabled
179
+ if (wantsContact && enableContactSupport) {
180
+ setShowContactPrompt(true);
181
+ }
105
182
  }
106
183
  catch (err) {
107
184
  const error = err;
@@ -111,7 +188,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
111
188
  finally {
112
189
  setIsLoading(false);
113
190
  }
114
- }, [input, isLoading, onMessageSent, onMessageReceived, onError]);
191
+ }, [input, isLoading, detectContactIntent, enableContactSupport, onMessageSent, onMessageReceived, onError]);
115
192
  // Handle Enter key
116
193
  const handleKeyPress = useCallback((e) => {
117
194
  if (e.key === 'Enter' && !e.shiftKey) {
@@ -123,8 +200,55 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
123
200
  const handleReset = useCallback(() => {
124
201
  setMessages([]);
125
202
  setError(null);
203
+ setShowSupportForm(false);
204
+ setTicketSubmitted(false);
205
+ setShowContactPrompt(false);
126
206
  apiClient.current?.resetSession();
127
207
  }, []);
208
+ // Handle support form submission
209
+ const handleSupportFormSubmit = useCallback(async (e) => {
210
+ e.preventDefault();
211
+ if (!supportFormData.email || !supportFormData.message || !apiClient.current) {
212
+ return;
213
+ }
214
+ setIsSubmittingTicket(true);
215
+ setError(null);
216
+ try {
217
+ const result = await apiClient.current.createTicket({
218
+ name: supportFormData.name || undefined,
219
+ email: supportFormData.email,
220
+ message: supportFormData.message,
221
+ priority: 'medium',
222
+ });
223
+ setTicketNumber(result.ticketNumber);
224
+ setTicketSubmitted(true);
225
+ // Reset form
226
+ setSupportFormData({ name: '', email: '', message: '' });
227
+ }
228
+ catch (err) {
229
+ const error = err;
230
+ setError(error.message);
231
+ onError?.(error);
232
+ }
233
+ finally {
234
+ setIsSubmittingTicket(false);
235
+ }
236
+ }, [supportFormData, onError]);
237
+ // Toggle support form
238
+ const handleShowSupportForm = useCallback(() => {
239
+ setShowSupportForm(true);
240
+ setShowContactPrompt(false);
241
+ setError(null);
242
+ }, []);
243
+ const handleBackToChat = useCallback(() => {
244
+ setShowSupportForm(false);
245
+ setTicketSubmitted(false);
246
+ setShowContactPrompt(false);
247
+ setError(null);
248
+ }, []);
249
+ const handleDismissContactPrompt = useCallback(() => {
250
+ setShowContactPrompt(false);
251
+ }, []);
128
252
  // Position styles
129
253
  const positionStyles = {
130
254
  'bottom-right': { bottom: '40px', right: '40px' },
@@ -226,8 +350,8 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
226
350
 
227
351
  .chatbot-title h3 {
228
352
  margin: 0;
229
- font-size: 16px;
230
- font-weight: 600;
353
+ font-size: ${headerFontSize};
354
+ font-weight: 500;
231
355
  white-space: nowrap;
232
356
  overflow: hidden;
233
357
  text-overflow: ellipsis;
@@ -235,7 +359,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
235
359
 
236
360
  .chatbot-title p {
237
361
  margin: 0;
238
- font-size: 12px;
362
+ font-size: ${smallFontSize};
239
363
  opacity: 0.9;
240
364
  white-space: nowrap;
241
365
  overflow: hidden;
@@ -306,6 +430,244 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
306
430
  color: ${primaryColor};
307
431
  }
308
432
 
433
+ .chatbot-support-link {
434
+ margin-top: 20px;
435
+ padding-top: 20px;
436
+ border-top: 1px solid #333;
437
+ }
438
+
439
+ .chatbot-support-button {
440
+ background: #2a2a2a;
441
+ border: 1px solid #333;
442
+ color: ${primaryColor};
443
+ padding: 12px 20px;
444
+ border-radius: 8px;
445
+ font-size: ${fontSize};
446
+ cursor: pointer;
447
+ transition: all 0.2s;
448
+ display: inline-flex;
449
+ align-items: center;
450
+ gap: 8px;
451
+ font-weight: 500;
452
+ }
453
+
454
+ .chatbot-support-button:hover {
455
+ background: #333;
456
+ border-color: ${primaryColor};
457
+ transform: translateY(-2px);
458
+ }
459
+
460
+ .chatbot-contact-prompt {
461
+ background: linear-gradient(135deg, ${primaryColor}15, ${primaryColor}08);
462
+ border: 1px solid ${primaryColor}40;
463
+ border-radius: 12px;
464
+ padding: 16px;
465
+ margin: 16px 0;
466
+ animation: slideIn 0.3s ease;
467
+ }
468
+
469
+ @keyframes slideIn {
470
+ from {
471
+ opacity: 0;
472
+ transform: translateY(-10px);
473
+ }
474
+ to {
475
+ opacity: 1;
476
+ transform: translateY(0);
477
+ }
478
+ }
479
+
480
+ .chatbot-contact-prompt-header {
481
+ display: flex;
482
+ align-items: center;
483
+ gap: 12px;
484
+ margin-bottom: 12px;
485
+ }
486
+
487
+ .chatbot-contact-prompt-icon {
488
+ width: 40px;
489
+ height: 40px;
490
+ border-radius: 50%;
491
+ background: ${primaryColor};
492
+ display: flex;
493
+ align-items: center;
494
+ justify-content: center;
495
+ color: white;
496
+ flex-shrink: 0;
497
+ }
498
+
499
+ .chatbot-contact-prompt-title {
500
+ font-size: ${headerFontSize};
501
+ font-weight: 600;
502
+ color: #e0e0e0;
503
+ margin: 0;
504
+ }
505
+
506
+ .chatbot-contact-prompt-description {
507
+ font-size: ${fontSize};
508
+ color: #aaa;
509
+ margin: 0 0 16px 0;
510
+ line-height: 1.5;
511
+ }
512
+
513
+ .chatbot-contact-prompt-actions {
514
+ display: flex;
515
+ gap: 8px;
516
+ }
517
+
518
+ .chatbot-contact-prompt-button {
519
+ flex: 1;
520
+ padding: 12px 16px;
521
+ border-radius: 8px;
522
+ font-size: ${fontSize};
523
+ font-weight: 600;
524
+ cursor: pointer;
525
+ transition: all 0.2s;
526
+ display: flex;
527
+ align-items: center;
528
+ justify-content: center;
529
+ gap: 8px;
530
+ border: none;
531
+ }
532
+
533
+ .chatbot-contact-prompt-button.primary {
534
+ background: ${primaryColor};
535
+ color: white;
536
+ }
537
+
538
+ .chatbot-contact-prompt-button.primary:hover {
539
+ opacity: 0.9;
540
+ transform: translateY(-2px);
541
+ }
542
+
543
+ .chatbot-contact-prompt-button.secondary {
544
+ background: #2a2a2a;
545
+ color: #ccc;
546
+ border: 1px solid #333;
547
+ }
548
+
549
+ .chatbot-contact-prompt-button.secondary:hover {
550
+ background: #333;
551
+ color: #fff;
552
+ }
553
+
554
+ .chatbot-support-form {
555
+ flex: 1;
556
+ overflow-y: auto;
557
+ padding: 20px;
558
+ background: #1a1a1a;
559
+ }
560
+
561
+ .chatbot-form-group {
562
+ margin-bottom: 16px;
563
+ }
564
+
565
+ .chatbot-form-label {
566
+ display: block;
567
+ color: #ccc;
568
+ font-size: ${fontSize};
569
+ font-weight: 500;
570
+ margin-bottom: 8px;
571
+ }
572
+
573
+ .chatbot-form-input {
574
+ width: 100%;
575
+ padding: 12px;
576
+ background: #2a2a2a;
577
+ border: 1px solid #333;
578
+ border-radius: 8px;
579
+ color: #e0e0e0;
580
+ font-size: ${fontSize};
581
+ font-family: inherit;
582
+ transition: border-color 0.2s;
583
+ }
584
+
585
+ .chatbot-form-input:focus {
586
+ outline: none;
587
+ border-color: ${primaryColor};
588
+ }
589
+
590
+ .chatbot-form-textarea {
591
+ min-height: 120px;
592
+ resize: vertical;
593
+ }
594
+
595
+ .chatbot-form-submit {
596
+ width: 100%;
597
+ padding: 14px;
598
+ background: ${primaryColor};
599
+ border: none;
600
+ border-radius: 8px;
601
+ color: white;
602
+ font-size: ${fontSize};
603
+ font-weight: 600;
604
+ cursor: pointer;
605
+ transition: all 0.2s;
606
+ display: flex;
607
+ align-items: center;
608
+ justify-content: center;
609
+ gap: 8px;
610
+ }
611
+
612
+ .chatbot-form-submit:hover:not(:disabled) {
613
+ opacity: 0.9;
614
+ transform: translateY(-2px);
615
+ }
616
+
617
+ .chatbot-form-submit:disabled {
618
+ opacity: 0.5;
619
+ cursor: not-allowed;
620
+ }
621
+
622
+ .chatbot-success-message {
623
+ text-align: center;
624
+ padding: 40px 20px;
625
+ }
626
+
627
+ .chatbot-success-icon {
628
+ width: 64px;
629
+ height: 64px;
630
+ margin: 0 auto 16px;
631
+ border-radius: 50%;
632
+ background: rgba(16, 185, 129, 0.1);
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: center;
636
+ color: #10b981;
637
+ }
638
+
639
+ .chatbot-ticket-number {
640
+ display: inline-block;
641
+ padding: 8px 16px;
642
+ background: #2a2a2a;
643
+ border: 1px solid #333;
644
+ border-radius: 8px;
645
+ color: ${primaryColor};
646
+ font-family: monospace;
647
+ font-size: ${fontSize};
648
+ margin: 16px 0;
649
+ }
650
+
651
+ .chatbot-back-button {
652
+ margin-top: 20px;
653
+ background: #2a2a2a;
654
+ border: 1px solid #333;
655
+ color: #ccc;
656
+ padding: 12px 20px;
657
+ border-radius: 8px;
658
+ font-size: ${fontSize};
659
+ cursor: pointer;
660
+ transition: all 0.2s;
661
+ display: inline-flex;
662
+ align-items: center;
663
+ gap: 8px;
664
+ }
665
+
666
+ .chatbot-back-button:hover {
667
+ background: #333;
668
+ color: #fff;
669
+ }
670
+
309
671
  .chatbot-message {
310
672
  display: flex;
311
673
  gap: 12px;
@@ -376,7 +738,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
376
738
  }
377
739
 
378
740
  .chatbot-timestamp {
379
- font-size: 11px;
741
+ font-size: ${smallFontSize};
380
742
  color: #666;
381
743
  margin-top: 4px;
382
744
  }
@@ -389,7 +751,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
389
751
  }
390
752
 
391
753
  .chatbot-source {
392
- font-size: 11px;
754
+ font-size: ${smallFontSize};
393
755
  padding: 4px 8px;
394
756
  background: rgba(99, 102, 241, 0.1);
395
757
  color: ${primaryColor};
@@ -446,7 +808,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
446
808
  padding: 12px;
447
809
  border-radius: 8px;
448
810
  margin: 0 16px 16px;
449
- font-size: 13px;
811
+ font-size: ${fontSize};
450
812
  display: flex;
451
813
  align-items: center;
452
814
  gap: 8px;
@@ -484,7 +846,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
484
846
  outline: none;
485
847
  padding: 12px 0;
486
848
  color: #e0e0e0;
487
- font-size: 14px;
849
+ font-size: ${fontSize};
488
850
  min-width: 0;
489
851
  }
490
852
 
@@ -539,7 +901,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
539
901
  }
540
902
 
541
903
  .chatbot-suggestions-title {
542
- font-size: 12px;
904
+ font-size: ${smallFontSize};
543
905
  color: #888;
544
906
  font-weight: 500;
545
907
  margin-bottom: 4px;
@@ -553,7 +915,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
553
915
  color: #ccc;
554
916
  padding: 10px 14px;
555
917
  border-radius: 20px;
556
- font-size: 13px;
918
+ font-size: ${fontSize};
557
919
  cursor: pointer;
558
920
  transition: all 0.2s ease;
559
921
  text-align: left;
@@ -595,7 +957,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
595
957
  .chatbot-suggestion-icon {
596
958
  color: ${primaryColor};
597
959
  opacity: 0.7;
598
- font-size: 16px;
960
+ font-size: ${headerFontSize};
599
961
  flex-shrink: 0;
600
962
  }
601
963
 
@@ -636,19 +998,16 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
636
998
 
637
999
  /* Mobile responsiveness */
638
1000
  @media (max-width: 480px) {
639
- /* Don't modify the container positioning - let it stay fixed at bottom-right for the button */
640
1001
  .chatbot-widget-container {
641
1002
  /* Keep default positioning from parent styles */
642
1003
  }
643
1004
 
644
1005
  .chatbot-button {
645
- /* Button stays in corner */
646
1006
  width: 56px;
647
1007
  height: 56px;
648
1008
  }
649
1009
 
650
1010
  .chatbot-window {
651
- /* Only the chat window covers full screen when open */
652
1011
  position: fixed;
653
1012
  bottom: 0 !important;
654
1013
  right: 0 !important;
@@ -684,17 +1043,21 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
684
1043
  }
685
1044
 
686
1045
  .chatbot-title h3 {
687
- font-size: 15px;
1046
+ font-size: ${fontSize};
688
1047
  }
689
1048
 
690
1049
  .chatbot-title p {
691
- font-size: 11px;
1050
+ font-size: ${smallFontSize};
692
1051
  }
693
1052
 
694
1053
  .chatbot-messages {
695
1054
  padding: 12px;
696
1055
  }
697
1056
 
1057
+ .chatbot-support-form {
1058
+ padding: 16px;
1059
+ }
1060
+
698
1061
  .chatbot-welcome {
699
1062
  padding: 30px 16px;
700
1063
  }
@@ -715,7 +1078,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
715
1078
 
716
1079
  .chatbot-bubble {
717
1080
  padding: 10px 14px;
718
- font-size: 14px;
1081
+ font-size: ${fontSize};
719
1082
  }
720
1083
 
721
1084
  .chatbot-input-area {
@@ -740,7 +1103,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
740
1103
 
741
1104
  .chatbot-suggestion-chip {
742
1105
  padding: 12px 16px;
743
- font-size: 14px;
1106
+ font-size: ${fontSize};
744
1107
  min-height: 48px;
745
1108
  }
746
1109
 
@@ -761,16 +1124,20 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
761
1124
  }
762
1125
 
763
1126
  .chatbot-title h3 {
764
- font-size: 14px;
1127
+ font-size: ${fontSize};
765
1128
  }
766
1129
 
767
1130
  .chatbot-messages {
768
1131
  padding: 10px;
769
1132
  }
770
1133
 
1134
+ .chatbot-support-form {
1135
+ padding: 12px;
1136
+ }
1137
+
771
1138
  .chatbot-bubble {
772
1139
  padding: 8px 12px;
773
- font-size: 13px;
1140
+ font-size: ${fontSize};
774
1141
  }
775
1142
 
776
1143
  .chatbot-input-area {
@@ -794,10 +1161,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
794
1161
  padding: 10px 16px;
795
1162
  }
796
1163
  }
797
- ` }), !isOpen && (_jsx("button", { className: "chatbot-button", onClick: handleToggle, "aria-label": "Open chat", children: _jsx(MessageCircle, { size: 28 }) })), isOpen && (_jsxs("div", { className: "chatbot-window", children: [_jsxs("div", { className: "chatbot-header", children: [_jsxs("div", { className: "chatbot-header-content", children: [_jsx("div", { className: "chatbot-icon", children: _jsx(Sparkles, { size: 20 }) }), _jsxs("div", { className: "chatbot-title", children: [_jsx("h3", { children: title }), subtitle && _jsx("p", { children: subtitle })] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [messages.length > 0 && (_jsx("button", { className: "chatbot-close", onClick: handleReset, "aria-label": "Reset conversation", title: "Start new conversation", children: _jsx(RefreshCw, { size: 18 }) })), _jsx("button", { className: "chatbot-close", onClick: handleToggle, "aria-label": "Close chat", children: _jsx(X, { size: 20 }) })] })] }), _jsxs("div", { className: "chatbot-messages", ref: scrollRef, children: [messages.length === 0 ? (_jsxs("div", { className: "chatbot-welcome", children: [_jsx("div", { className: "chatbot-welcome-icon", children: _jsx(Bot, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#ccc' }, children: brandName ? `Welcome to ${brandName}!` : 'Welcome!' }), _jsx("p", { style: { margin: 0, fontSize: '14px' }, children: welcomeMessage })] })) : (messages.map((message) => (_jsxs("div", { className: `chatbot-message ${message.role}`, children: [_jsx("div", { className: `chatbot-avatar ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? _jsx(User, { size: 18 }) : _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-message-content", children: [_jsx("div", { className: `chatbot-bubble ${message.role === 'user' ? 'user' : 'bot'}`, children: message.content }), showSources && message.sources && message.sources.length > 0 && (_jsx("div", { className: "chatbot-sources", children: message.sources.map((source, idx) => (_jsxs("span", { className: "chatbot-source", children: [source.title, " (", Math.round(source.score * 100), "%)"] }, idx))) })), showTimestamps && (_jsx("div", { className: "chatbot-timestamp", children: new Date(message.timestamp).toLocaleTimeString([], {
798
- hour: '2-digit',
799
- minute: '2-digit',
800
- }) }))] })] }, message.id)))), isLoading && showTypingIndicator && (_jsxs("div", { className: "chatbot-typing", children: [_jsx("div", { className: "chatbot-avatar bot", children: _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-typing-dots", children: [_jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" })] })] }))] }), showSuggestedQuestions && messages.length === 0 && !isLoading && (loadingSuggestions || suggestions.length > 0) && (_jsxs("div", { className: "chatbot-suggestions", children: [(loadingSuggestions || suggestions.length > 0) && (_jsx("div", { className: "chatbot-suggestions-title", children: "Suggested Questions" })), loadingSuggestions ? (_jsxs("div", { className: "chatbot-suggestions-skeleton", children: [_jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" })] })) : (suggestions.map((suggestion, idx) => (_jsxs("button", { className: "chatbot-suggestion-chip", onClick: () => handleSuggestionClick(suggestion), disabled: isLoading, children: [_jsx("span", { className: "chatbot-suggestion-icon", children: "\uD83D\uDCAC" }), suggestion] }, idx))))] })), error && (_jsxs("div", { className: "chatbot-error", children: [_jsx("span", { children: "\u26A0\uFE0F" }), error] })), _jsxs("div", { className: "chatbot-input-area", children: [_jsx("div", { className: "chatbot-input-wrapper", children: _jsx("input", { type: "text", className: "chatbot-input", value: input, onChange: (e) => setInput(e.target.value), onKeyPress: handleKeyPress, placeholder: placeholder, disabled: isLoading }) }), _jsx("button", { className: "chatbot-button-icon", onClick: () => handleSendMessage(), disabled: !input.trim() || isLoading, "aria-label": "Send message", children: isLoading ? _jsx(Loader2, { size: 20, className: "spin" }) : _jsx(Send, { size: 20 }) })] })] })), _jsx("style", { children: `
1164
+ ` }), !isOpen && (_jsx("button", { className: "chatbot-button", onClick: handleToggle, "aria-label": "Open chat", children: _jsx(MessageCircle, { size: 28 }) })), isOpen && (_jsxs("div", { className: "chatbot-window", children: [_jsxs("div", { className: "chatbot-header", children: [_jsxs("div", { className: "chatbot-header-content", children: [showSupportForm && (_jsx("button", { className: "chatbot-close", onClick: handleBackToChat, "aria-label": "Back to chat", title: "Back to chat", style: { marginRight: '8px' }, children: _jsx(ArrowLeft, { size: 18 }) })), _jsx("div", { className: "chatbot-icon", children: showSupportForm ? _jsx(Mail, { size: 20 }) : _jsx(Sparkles, { size: 20 }) }), _jsxs("div", { className: "chatbot-title", children: [_jsx("h3", { children: showSupportForm ? 'Contact Support' : title }), subtitle && !showSupportForm && _jsx("p", { children: subtitle }), showSupportForm && _jsx("p", { children: "We'll get back to you soon" })] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [messages.length > 0 && !showSupportForm && (_jsx("button", { className: "chatbot-close", onClick: handleReset, "aria-label": "Reset conversation", title: "Start new conversation", children: _jsx(RefreshCw, { size: 18 }) })), _jsx("button", { className: "chatbot-close", onClick: handleToggle, "aria-label": "Close chat", children: _jsx(X, { size: 20 }) })] })] }), showSupportForm && !ticketSubmitted && (_jsxs("form", { className: "chatbot-support-form", onSubmit: handleSupportFormSubmit, children: [_jsxs("div", { className: "chatbot-form-group", children: [_jsx("label", { className: "chatbot-form-label", children: "Name (Optional)" }), _jsx("input", { type: "text", className: "chatbot-form-input", value: supportFormData.name, onChange: (e) => setSupportFormData({ ...supportFormData, name: e.target.value }), placeholder: "Your name", disabled: isSubmittingTicket })] }), _jsxs("div", { className: "chatbot-form-group", children: [_jsxs("label", { className: "chatbot-form-label", children: ["Email Address ", _jsx("span", { style: { color: '#ef4444' }, children: "*" })] }), _jsx("input", { type: "email", className: "chatbot-form-input", value: supportFormData.email, onChange: (e) => setSupportFormData({ ...supportFormData, email: e.target.value }), placeholder: "your@email.com", required: true, disabled: isSubmittingTicket })] }), _jsxs("div", { className: "chatbot-form-group", children: [_jsxs("label", { className: "chatbot-form-label", children: ["Message ", _jsx("span", { style: { color: '#ef4444' }, children: "*" })] }), _jsx("textarea", { className: "chatbot-form-input chatbot-form-textarea", value: supportFormData.message, onChange: (e) => setSupportFormData({ ...supportFormData, message: e.target.value }), placeholder: "Please describe your issue or question...", required: true, minLength: 10, disabled: isSubmittingTicket })] }), _jsx("button", { type: "submit", className: "chatbot-form-submit", disabled: isSubmittingTicket || !supportFormData.email || !supportFormData.message, children: isSubmittingTicket ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 18, className: "spin" }), "Submitting..."] })) : (_jsxs(_Fragment, { children: [_jsx(Send, { size: 18 }), "Submit Ticket"] })) }), error && (_jsxs("div", { className: "chatbot-error", style: { marginTop: '16px' }, children: [_jsx("span", { children: "\u26A0\uFE0F" }), error] }))] })), ticketSubmitted && (_jsx("div", { className: "chatbot-support-form", children: _jsxs("div", { className: "chatbot-success-message", children: [_jsx("div", { className: "chatbot-success-icon", children: _jsx(CheckCircle, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#10b981', fontSize: '18px' }, children: "Ticket Submitted!" }), _jsx("p", { style: { margin: '0 0 16px 0', color: '#888', fontSize: '14px' }, children: "Thank you for contacting us. We've received your message and will get back to you soon." }), ticketNumber && (_jsxs("div", { children: [_jsx("p", { style: { margin: '0 0 8px 0', color: '#ccc', fontSize: '13px' }, children: "Your ticket number:" }), _jsx("div", { className: "chatbot-ticket-number", children: ticketNumber })] })), _jsx("p", { style: { margin: '20px 0 0 0', color: '#666', fontSize: '12px' }, children: "Please check your email for confirmation and updates." }), _jsxs("button", { className: "chatbot-back-button", onClick: handleBackToChat, children: [_jsx(ArrowLeft, { size: 16 }), "Back to Chat"] })] }) })), !showSupportForm && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "chatbot-messages", ref: scrollRef, children: [messages.length === 0 ? (_jsxs("div", { className: "chatbot-welcome", children: [_jsx("div", { className: "chatbot-welcome-icon", children: _jsx(Bot, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#ccc' }, children: brandName ? `Welcome to ${brandName}!` : 'Welcome!' }), _jsx("p", { style: { margin: 0, fontSize: '14px' }, children: welcomeMessage })] })) : (messages.map((message) => (_jsxs("div", { className: `chatbot-message ${message.role}`, children: [_jsx("div", { className: `chatbot-avatar ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? _jsx(User, { size: 18 }) : _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-message-content", children: [_jsx("div", { className: `chatbot-bubble ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? (message.content) : (_jsx(MessageRenderer, { content: message.content, primaryColor: primaryColor, fontSize: fontSize, headerFontSize: headerFontSize, smallFontSize: smallFontSize })) }), showSources && message.sources && message.sources.length > 0 && (_jsx("div", { className: "chatbot-sources", children: message.sources.map((source, idx) => (_jsxs("span", { className: "chatbot-source", children: [source.title, " (", Math.round(source.score * 100), "%)"] }, idx))) })), showTimestamps && (_jsx("div", { className: "chatbot-timestamp", children: new Date(message.timestamp).toLocaleTimeString([], {
1165
+ hour: '2-digit',
1166
+ minute: '2-digit',
1167
+ }) }))] })] }, message.id)))), isLoading && showTypingIndicator && (_jsxs("div", { className: "chatbot-typing", children: [_jsx("div", { className: "chatbot-avatar bot", children: _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-typing-dots", children: [_jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" })] })] })), showContactPrompt && enableContactSupport && (_jsxs("div", { className: "chatbot-contact-prompt", children: [_jsxs("div", { className: "chatbot-contact-prompt-header", children: [_jsx("div", { className: "chatbot-contact-prompt-icon", children: _jsx(Mail, { size: 20 }) }), _jsx("h4", { className: "chatbot-contact-prompt-title", children: "Need to Contact Support?" })] }), _jsx("p", { className: "chatbot-contact-prompt-description", children: "It looks like you may need additional help. Would you like to create a support ticket? Our team will get back to you as soon as possible." }), _jsxs("div", { className: "chatbot-contact-prompt-actions", children: [_jsxs("button", { className: "chatbot-contact-prompt-button primary", onClick: handleShowSupportForm, children: [_jsx(Mail, { size: 16 }), "Create Ticket"] }), _jsx("button", { className: "chatbot-contact-prompt-button secondary", onClick: handleDismissContactPrompt, children: "Continue Chat" })] })] }))] }), showSuggestedQuestions && messages.length === 0 && !isLoading && (loadingSuggestions || suggestions.length > 0) && (_jsxs("div", { className: "chatbot-suggestions", children: [(loadingSuggestions || suggestions.length > 0) && (_jsx("div", { className: "chatbot-suggestions-title", children: "Suggested Questions" })), loadingSuggestions ? (_jsxs("div", { className: "chatbot-suggestions-skeleton", children: [_jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" })] })) : (suggestions.map((suggestion, idx) => (_jsxs("button", { className: "chatbot-suggestion-chip", onClick: () => handleSuggestionClick(suggestion), disabled: isLoading, children: [_jsx("span", { className: "chatbot-suggestion-icon", children: "\uD83D\uDCAC" }), suggestion] }, idx))))] })), error && (_jsxs("div", { className: "chatbot-error", children: [_jsx("span", { children: "\u26A0\uFE0F" }), error] })), _jsxs("div", { className: "chatbot-input-area", children: [_jsx("div", { className: "chatbot-input-wrapper", children: _jsx("input", { type: "text", className: "chatbot-input", value: input, onChange: (e) => setInput(e.target.value), onKeyPress: handleKeyPress, placeholder: placeholder, disabled: isLoading }) }), _jsx("button", { className: "chatbot-button-icon", onClick: () => handleSendMessage(), disabled: !input.trim() || isLoading, "aria-label": "Send message", children: isLoading ? _jsx(Loader2, { size: 20, className: "spin" }) : _jsx(Send, { size: 20 }) })] })] }))] })), _jsx("style", { children: `
801
1168
  .spin {
802
1169
  animation: spin 1s linear infinite;
803
1170
  }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ interface MessageRendererProps {
3
+ content: string;
4
+ primaryColor?: string;
5
+ fontSize?: string;
6
+ headerFontSize?: string;
7
+ smallFontSize?: string;
8
+ }
9
+ /**
10
+ * Production-ready message renderer
11
+ * Handles: Lists, Tables, Code, Links, JSON, Markdown
12
+ */
13
+ export declare const MessageRenderer: React.FC<MessageRendererProps>;
14
+ export {};
15
+ //# sourceMappingURL=MessageRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageRenderer.d.ts","sourceRoot":"","sources":["../src/MessageRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA4vB1D,CAAC"}