fyrebot-widget 1.3.3 → 1.5.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,CAy+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,CAw/BjD,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -6,7 +6,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  import { useState, useRef, useEffect, useCallback } from 'react';
7
7
  import { MessageCircle, X, Send, Loader2, Bot, User, Sparkles, RefreshCw } 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, 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('');
@@ -226,8 +227,8 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
226
227
 
227
228
  .chatbot-title h3 {
228
229
  margin: 0;
229
- font-size: 16px;
230
- font-weight: 600;
230
+ font-size: ${headerFontSize};
231
+ font-weight: 500;
231
232
  white-space: nowrap;
232
233
  overflow: hidden;
233
234
  text-overflow: ellipsis;
@@ -235,7 +236,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
235
236
 
236
237
  .chatbot-title p {
237
238
  margin: 0;
238
- font-size: 12px;
239
+ font-size: ${smallFontSize};
239
240
  opacity: 0.9;
240
241
  white-space: nowrap;
241
242
  overflow: hidden;
@@ -376,7 +377,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
376
377
  }
377
378
 
378
379
  .chatbot-timestamp {
379
- font-size: 11px;
380
+ font-size: ${smallFontSize};
380
381
  color: #666;
381
382
  margin-top: 4px;
382
383
  }
@@ -389,7 +390,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
389
390
  }
390
391
 
391
392
  .chatbot-source {
392
- font-size: 11px;
393
+ font-size: ${smallFontSize};
393
394
  padding: 4px 8px;
394
395
  background: rgba(99, 102, 241, 0.1);
395
396
  color: ${primaryColor};
@@ -446,7 +447,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
446
447
  padding: 12px;
447
448
  border-radius: 8px;
448
449
  margin: 0 16px 16px;
449
- font-size: 13px;
450
+ font-size: ${fontSize};
450
451
  display: flex;
451
452
  align-items: center;
452
453
  gap: 8px;
@@ -484,7 +485,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
484
485
  outline: none;
485
486
  padding: 12px 0;
486
487
  color: #e0e0e0;
487
- font-size: 14px;
488
+ font-size: ${fontSize};
488
489
  min-width: 0;
489
490
  }
490
491
 
@@ -539,7 +540,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
539
540
  }
540
541
 
541
542
  .chatbot-suggestions-title {
542
- font-size: 12px;
543
+ font-size: ${smallFontSize};
543
544
  color: #888;
544
545
  font-weight: 500;
545
546
  margin-bottom: 4px;
@@ -553,7 +554,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
553
554
  color: #ccc;
554
555
  padding: 10px 14px;
555
556
  border-radius: 20px;
556
- font-size: 13px;
557
+ font-size: ${fontSize};
557
558
  cursor: pointer;
558
559
  transition: all 0.2s ease;
559
560
  text-align: left;
@@ -595,7 +596,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
595
596
  .chatbot-suggestion-icon {
596
597
  color: ${primaryColor};
597
598
  opacity: 0.7;
598
- font-size: 16px;
599
+ font-size: ${headerFontSize};
599
600
  flex-shrink: 0;
600
601
  }
601
602
 
@@ -684,11 +685,11 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
684
685
  }
685
686
 
686
687
  .chatbot-title h3 {
687
- font-size: 15px;
688
+ font-size: ${fontSize};
688
689
  }
689
690
 
690
691
  .chatbot-title p {
691
- font-size: 11px;
692
+ font-size: ${smallFontSize};
692
693
  }
693
694
 
694
695
  .chatbot-messages {
@@ -715,7 +716,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
715
716
 
716
717
  .chatbot-bubble {
717
718
  padding: 10px 14px;
718
- font-size: 14px;
719
+ font-size: ${fontSize};
719
720
  }
720
721
 
721
722
  .chatbot-input-area {
@@ -740,7 +741,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
740
741
 
741
742
  .chatbot-suggestion-chip {
742
743
  padding: 12px 16px;
743
- font-size: 14px;
744
+ font-size: ${fontSize};
744
745
  min-height: 48px;
745
746
  }
746
747
 
@@ -761,7 +762,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
761
762
  }
762
763
 
763
764
  .chatbot-title h3 {
764
- font-size: 14px;
765
+ font-size: ${fontSize};
765
766
  }
766
767
 
767
768
  .chatbot-messages {
@@ -770,7 +771,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
770
771
 
771
772
  .chatbot-bubble {
772
773
  padding: 8px 12px;
773
- font-size: 13px;
774
+ font-size: ${fontSize};
774
775
  }
775
776
 
776
777
  .chatbot-input-area {
@@ -794,10 +795,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
794
795
  padding: 10px 16px;
795
796
  }
796
797
  }
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
+ ` }), !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.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([], {
798
799
  hour: '2-digit',
799
800
  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 && (_jsxs("div", { className: "chatbot-suggestions", children: [_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.length > 0 ? (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)))) : null] })), 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
+ }) }))] })] }, 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: `
801
802
  .spin {
802
803
  animation: spin 1s linear infinite;
803
804
  }
@@ -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"}
@@ -0,0 +1,619 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Production-ready message renderer
4
+ * Handles: Lists, Tables, Code, Links, JSON, Markdown
5
+ */
6
+ export const MessageRenderer = ({ content, primaryColor = '#6366f1', fontSize = '13px', headerFontSize = '15px', smallFontSize = '11px' }) => {
7
+ /**
8
+ * Parse and render different content types
9
+ */
10
+ const renderContent = () => {
11
+ // Try to detect structured data
12
+ const trimmedContent = content.trim();
13
+ // 1. Try to parse as JSON
14
+ if (trimmedContent.startsWith('{') || trimmedContent.startsWith('[')) {
15
+ try {
16
+ const parsed = JSON.parse(trimmedContent);
17
+ return renderJSON(parsed);
18
+ }
19
+ catch (e) {
20
+ // Not JSON, continue
21
+ }
22
+ }
23
+ // 2. Check for markdown tables
24
+ if (trimmedContent.includes('|') && trimmedContent.includes('---')) {
25
+ return renderMarkdownTable(trimmedContent);
26
+ }
27
+ // 3. Check for lists (numbered or bulleted)
28
+ if (hasListPattern(trimmedContent)) {
29
+ return renderList(trimmedContent);
30
+ }
31
+ // 4. Check for steps/instructions
32
+ if (hasStepsPattern(trimmedContent)) {
33
+ return renderSteps(trimmedContent);
34
+ }
35
+ // 5. Default: render as formatted text with markdown-like features
36
+ return renderFormattedText(trimmedContent);
37
+ };
38
+ /**
39
+ * Render JSON objects beautifully
40
+ */
41
+ const renderJSON = (data) => {
42
+ if (Array.isArray(data)) {
43
+ return (_jsxs("div", { className: "json-array", children: [_jsxs("div", { className: "json-label", children: ["Array (", data.length, " items):"] }), data.map((item, index) => (_jsx("div", { className: "json-item", children: typeof item === 'object' ? renderJSONObject(item, index) : (_jsx("div", { className: "json-primitive", children: String(item) })) }, index)))] }));
44
+ }
45
+ else if (typeof data === 'object' && data !== null) {
46
+ return renderJSONObject(data);
47
+ }
48
+ return _jsx("div", { children: String(data) });
49
+ };
50
+ const renderJSONObject = (obj, index) => {
51
+ return (_jsxs("div", { className: "json-object", children: [index !== undefined && _jsxs("div", { className: "json-index", children: ["#", index + 1] }), Object.entries(obj).map(([key, value]) => (_jsxs("div", { className: "json-row", children: [_jsxs("span", { className: "json-key", children: [key, ":"] }), _jsx("span", { className: "json-value", children: typeof value === 'object' && value !== null
52
+ ? JSON.stringify(value, null, 2)
53
+ : String(value) })] }, key)))] }));
54
+ };
55
+ /**
56
+ * Render markdown tables
57
+ */
58
+ const renderMarkdownTable = (text) => {
59
+ const lines = text.split('\n').filter(line => line.trim());
60
+ const headerLine = lines.find(line => line.startsWith('|'));
61
+ const separatorIndex = lines.findIndex(line => line.includes('---'));
62
+ if (!headerLine || separatorIndex === -1) {
63
+ return renderFormattedText(text);
64
+ }
65
+ const headers = headerLine.split('|').map(h => h.trim()).filter(h => h);
66
+ const dataLines = lines.slice(separatorIndex + 1).filter(line => line.startsWith('|'));
67
+ return (_jsx("div", { className: "table-container", children: _jsxs("table", { className: "response-table", children: [_jsx("thead", { children: _jsx("tr", { children: headers.map((header, i) => (_jsx("th", { children: header }, i))) }) }), _jsx("tbody", { children: dataLines.map((line, rowIndex) => {
68
+ const cells = line.split('|').map(c => c.trim()).filter(c => c);
69
+ return (_jsx("tr", { children: cells.map((cell, cellIndex) => (_jsx("td", { children: cell }, cellIndex))) }, rowIndex));
70
+ }) })] }) }));
71
+ };
72
+ /**
73
+ * Check if content has list pattern
74
+ */
75
+ const hasListPattern = (text) => {
76
+ const lines = text.split('\n').map(l => l.trim()).filter(l => l);
77
+ // Check for explicit list markers
78
+ const listPatterns = [
79
+ /^[\-\*\+]\s+/, // Bullet points: -, *, +
80
+ /^\d+\.\s+/, // Numbered: 1., 2., etc
81
+ /^•\s+/, // Bullet: •
82
+ ];
83
+ let listItemCount = 0;
84
+ let colonHeaderCount = 0;
85
+ lines.forEach(line => {
86
+ if (listPatterns.some(pattern => pattern.test(line))) {
87
+ listItemCount++;
88
+ }
89
+ // Detect colon headers (e.g., "Streaming Enthusiasts:")
90
+ if (/^[A-Z][\w\s\-]+:$/i.test(line)) {
91
+ colonHeaderCount++;
92
+ }
93
+ });
94
+ // Consider it a list if we have list items OR multiple colon headers with content
95
+ return listItemCount >= 2 || (colonHeaderCount >= 2 && lines.length > colonHeaderCount);
96
+ };
97
+ /**
98
+ * Render lists (bulleted or numbered) with smart heading detection
99
+ */
100
+ const renderList = (text) => {
101
+ const lines = text.split('\n');
102
+ const elements = [];
103
+ let currentList = null;
104
+ let key = 0;
105
+ let i = 0;
106
+ const flushList = () => {
107
+ if (currentList && currentList.items.length > 0) {
108
+ const ListTag = currentList.isNumbered ? 'ol' : 'ul';
109
+ elements.push(_jsx(ListTag, { className: "response-list", children: currentList.items.map((item, index) => (_jsx("li", { children: renderInlineFormatting(item) }, index))) }, key++));
110
+ currentList = null;
111
+ }
112
+ };
113
+ while (i < lines.length) {
114
+ const trimmed = lines[i].trim();
115
+ // Skip empty lines
116
+ if (!trimmed) {
117
+ i++;
118
+ continue;
119
+ }
120
+ // Check if it's a markdown heading (###, ##, #)
121
+ if (/^#{1,3}\s+/.test(trimmed)) {
122
+ flushList();
123
+ const level = trimmed.match(/^(#{1,3})/)?.[0].length || 3;
124
+ const headingText = trimmed.replace(/^#{1,3}\s+/, '');
125
+ if (level === 1) {
126
+ elements.push(_jsx("h3", { className: "section-heading", children: headingText }, key++));
127
+ }
128
+ else if (level === 2) {
129
+ elements.push(_jsx("h4", { className: "section-subheading", children: headingText }, key++));
130
+ }
131
+ else {
132
+ elements.push(_jsx("h5", { className: "section-subheading", children: headingText }, key++));
133
+ }
134
+ i++;
135
+ }
136
+ // Check if it's a colon-terminated header (e.g., "Streaming Enthusiasts:")
137
+ // Look ahead to see if the next line is descriptive text (not a list item or another header)
138
+ else if (/^[A-Z][\w\s\-]+:$/i.test(trimmed)) {
139
+ flushList();
140
+ // Check if next line exists and is descriptive content (not a list marker)
141
+ const nextLine = i + 1 < lines.length ? lines[i + 1].trim() : '';
142
+ const isFollowedByContent = nextLine &&
143
+ !(/^#{1,3}\s+/.test(nextLine)) &&
144
+ !(/^[A-Z][\w\s\-]+:$/i.test(nextLine)) &&
145
+ !(/^[\-\*\+•]\s+/.test(nextLine)) &&
146
+ !(/^\d+\.\s+/.test(nextLine));
147
+ if (isFollowedByContent) {
148
+ // Render as header with description
149
+ const headerText = trimmed.replace(/:$/, '');
150
+ elements.push(_jsxs("div", { className: "definition-item", children: [_jsx("div", { className: "definition-term", children: headerText }), _jsx("div", { className: "definition-description", children: renderInlineFormatting(nextLine) })] }, key++));
151
+ i += 2; // Skip both header and description line
152
+ }
153
+ else {
154
+ // Just a header without immediate description
155
+ elements.push(_jsx("h5", { className: "colon-heading", children: renderInlineFormatting(trimmed.replace(/:$/, '')) }, key++));
156
+ i++;
157
+ }
158
+ }
159
+ // Check if it's a list item (bullet or numbered)
160
+ else if (/^[\-\*\+•]\s+/.test(trimmed) || /^\d+\.\s+/.test(trimmed)) {
161
+ const isNumbered = /^\d+\.\s+/.test(trimmed);
162
+ const itemText = trimmed.replace(/^[\-\*\+•]\s+/, '').replace(/^\d+\.\s+/, '');
163
+ // Start a new list or continue existing one
164
+ if (!currentList) {
165
+ currentList = { items: [itemText], isNumbered };
166
+ }
167
+ else if (currentList.isNumbered === isNumbered) {
168
+ currentList.items.push(itemText);
169
+ }
170
+ else {
171
+ // List type changed, flush and start new
172
+ flushList();
173
+ currentList = { items: [itemText], isNumbered };
174
+ }
175
+ i++;
176
+ }
177
+ // Regular text (not a heading or list item)
178
+ else {
179
+ flushList();
180
+ elements.push(_jsx("p", { className: "section-text", children: renderInlineFormatting(trimmed) }, key++));
181
+ i++;
182
+ }
183
+ }
184
+ // Flush any remaining list
185
+ flushList();
186
+ return (_jsx("div", { className: "smart-content", children: elements }));
187
+ };
188
+ /**
189
+ * Check if content has step-by-step pattern
190
+ */
191
+ const hasStepsPattern = (text) => {
192
+ const stepPatterns = [
193
+ /step\s+\d+/i,
194
+ /^\d+\.\s+\*\*/i,
195
+ /###\s+\d+\./,
196
+ ];
197
+ return stepPatterns.some(pattern => pattern.test(text));
198
+ };
199
+ /**
200
+ * Render step-by-step instructions
201
+ */
202
+ const renderSteps = (text) => {
203
+ const lines = text.split('\n');
204
+ const steps = [];
205
+ let currentStep = null;
206
+ lines.forEach(line => {
207
+ const trimmed = line.trim();
208
+ // Check if it's a step header
209
+ if (/^(step\s+\d+|###\s+\d+\.|\d+\.\s+\*\*)/i.test(trimmed)) {
210
+ if (currentStep)
211
+ steps.push(currentStep);
212
+ currentStep = {
213
+ title: trimmed.replace(/^###\s+/, '').replace(/\*\*/g, ''),
214
+ content: []
215
+ };
216
+ }
217
+ else if (currentStep && trimmed) {
218
+ currentStep.content.push(trimmed);
219
+ }
220
+ });
221
+ if (currentStep)
222
+ steps.push(currentStep);
223
+ return (_jsx("div", { className: "steps-container", children: steps.map((step, index) => (_jsxs("div", { className: "step-item", children: [_jsx("div", { className: "step-number", children: index + 1 }), _jsxs("div", { className: "step-content", children: [_jsx("div", { className: "step-title", children: step.title }), step.content.map((line, i) => (_jsx("div", { className: "step-description", children: renderInlineFormatting(line) }, i)))] })] }, index))) }));
224
+ };
225
+ /**
226
+ * Render formatted text with inline markdown
227
+ */
228
+ const renderFormattedText = (text) => {
229
+ const paragraphs = text.split('\n\n').filter(p => p.trim());
230
+ return (_jsx("div", { className: "formatted-text", children: paragraphs.map((paragraph, index) => {
231
+ const trimmed = paragraph.trim();
232
+ // Headers
233
+ if (trimmed.startsWith('###')) {
234
+ return _jsx("h3", { children: trimmed.replace(/^###\s+/, '') }, index);
235
+ }
236
+ if (trimmed.startsWith('##')) {
237
+ return _jsx("h2", { children: trimmed.replace(/^##\s+/, '') }, index);
238
+ }
239
+ if (trimmed.startsWith('#')) {
240
+ return _jsx("h1", { children: trimmed.replace(/^#\s+/, '') }, index);
241
+ }
242
+ // Code blocks
243
+ if (trimmed.startsWith('```')) {
244
+ const code = trimmed.replace(/```\w*\n?/, '').replace(/```$/, '');
245
+ return (_jsx("pre", { className: "code-block", children: _jsx("code", { children: code }) }, index));
246
+ }
247
+ // Regular paragraph
248
+ return (_jsx("p", { children: renderInlineFormatting(trimmed) }, index));
249
+ }) }));
250
+ };
251
+ /**
252
+ * Handle inline formatting (bold, italic, links, code)
253
+ */
254
+ const renderInlineFormatting = (text) => {
255
+ const parts = [];
256
+ let remaining = text;
257
+ let key = 0;
258
+ // Match patterns: **bold**, *italic*, `code`, [link](url)
259
+ const pattern = /(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`|\[([^\]]+)\]\(([^)]+)\))/g;
260
+ let match;
261
+ let lastIndex = 0;
262
+ while ((match = pattern.exec(text)) !== null) {
263
+ // Add text before match
264
+ if (match.index > lastIndex) {
265
+ parts.push(text.substring(lastIndex, match.index));
266
+ }
267
+ const matched = match[0];
268
+ if (matched.startsWith('**')) {
269
+ // Bold
270
+ parts.push(_jsx("strong", { children: matched.slice(2, -2) }, key++));
271
+ }
272
+ else if (matched.startsWith('*')) {
273
+ // Italic
274
+ parts.push(_jsx("em", { children: matched.slice(1, -1) }, key++));
275
+ }
276
+ else if (matched.startsWith('`')) {
277
+ // Inline code
278
+ parts.push(_jsx("code", { className: "inline-code", children: matched.slice(1, -1) }, key++));
279
+ }
280
+ else if (matched.startsWith('[')) {
281
+ // Link
282
+ const linkText = match[2];
283
+ const linkUrl = match[3];
284
+ parts.push(_jsx("a", { href: linkUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-link", children: linkText }, key++));
285
+ }
286
+ lastIndex = match.index + matched.length;
287
+ }
288
+ // Add remaining text
289
+ if (lastIndex < text.length) {
290
+ parts.push(text.substring(lastIndex));
291
+ }
292
+ return parts.length > 0 ? _jsx(_Fragment, { children: parts }) : text;
293
+ };
294
+ return (_jsxs("div", { className: "message-renderer", children: [renderContent(), _jsx("style", { children: `
295
+ .message-renderer {
296
+ line-height: 1.6;
297
+ }
298
+
299
+ /* JSON Rendering */
300
+ .json-array, .json-object {
301
+ background: rgba(99, 102, 241, 0.05);
302
+ border-left: 3px solid ${primaryColor};
303
+ padding: 12px;
304
+ border-radius: 6px;
305
+ margin: 8px 0;
306
+ }
307
+
308
+ .json-label {
309
+ font-weight: 500;
310
+ color: ${primaryColor};
311
+ margin-bottom: 8px;
312
+ font-size: ${smallFontSize};
313
+ }
314
+
315
+ .json-item {
316
+ margin: 8px 0;
317
+ }
318
+
319
+ .json-index {
320
+ display: inline-block;
321
+ background: ${primaryColor};
322
+ color: white;
323
+ padding: 2px 8px;
324
+ border-radius: 4px;
325
+ font-size: ${smallFontSize};
326
+ margin-bottom: 6px;
327
+ }
328
+
329
+ .json-row {
330
+ padding: 6px 0;
331
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
332
+ }
333
+
334
+ .json-row:last-child {
335
+ border-bottom: none;
336
+ }
337
+
338
+ .json-key {
339
+ font-weight: 500;
340
+ color: ${primaryColor};
341
+ margin-right: 8px;
342
+ }
343
+
344
+ .json-value {
345
+ color: #e0e0e0;
346
+ }
347
+
348
+ /* Table Rendering */
349
+ .table-container {
350
+ overflow-x: auto;
351
+ margin: 12px 0;
352
+ }
353
+
354
+ .response-table {
355
+ width: 100%;
356
+ border-collapse: collapse;
357
+ font-size: ${fontSize};
358
+ }
359
+
360
+ .response-table th {
361
+ background: ${primaryColor};
362
+ color: white;
363
+ padding: 10px;
364
+ text-align: left;
365
+ font-weight: 500;
366
+ }
367
+
368
+ .response-table td {
369
+ padding: 10px;
370
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
371
+ }
372
+
373
+ .response-table tr:hover {
374
+ background: rgba(99, 102, 241, 0.05);
375
+ }
376
+
377
+ /* List Rendering */
378
+ .list-container {
379
+ margin: 12px 0;
380
+ }
381
+
382
+ .list-header {
383
+ font-weight: 600;
384
+ margin-bottom: 10px;
385
+ color: #e0e0e0;
386
+ font-size: ${fontSize};
387
+ }
388
+
389
+ .response-list {
390
+ margin: 10px 0;
391
+ padding-left: 24px;
392
+ list-style-position: outside;
393
+ }
394
+
395
+ .response-list li {
396
+ margin: 8px 0;
397
+ color: #d0d0d0;
398
+ font-size: ${fontSize};
399
+ display: list-item;
400
+ }
401
+
402
+ .response-list ul {
403
+ list-style-type: disc;
404
+ }
405
+
406
+ .response-list ol {
407
+ list-style-type: decimal;
408
+ }
409
+
410
+ .response-list li::marker {
411
+ color: ${primaryColor};
412
+ font-weight: bold;
413
+ }
414
+
415
+ ul.response-list {
416
+ list-style-type: disc;
417
+ }
418
+
419
+ ol.response-list {
420
+ list-style-type: decimal;
421
+ }
422
+
423
+ .list-footer {
424
+ margin-top: 10px;
425
+ color: #b0b0b0;
426
+ display: none;
427
+ font-size: ${smallFontSize};
428
+ }
429
+
430
+ /* Steps Rendering */
431
+ .steps-container {
432
+ margin: 12px 0;
433
+ }
434
+
435
+ .step-item {
436
+ display: flex;
437
+ gap: 12px;
438
+ margin: 16px 0;
439
+ padding: 12px;
440
+ background: rgba(99, 102, 241, 0.05);
441
+ border-radius: 8px;
442
+ }
443
+
444
+ .step-number {
445
+ flex-shrink: 0;
446
+ width: 32px;
447
+ height: 32px;
448
+ background: ${primaryColor};
449
+ color: white;
450
+ border-radius: 50%;
451
+ display: flex;
452
+ align-items: center;
453
+ justify-content: center;
454
+ font-weight: 500;
455
+ font-size: ${fontSize};
456
+ }
457
+
458
+ .step-content {
459
+ flex: 1;
460
+ }
461
+
462
+ .step-title {
463
+ font-weight: 500;
464
+ color: #e0e0e0;
465
+ margin-bottom: 6px;
466
+ }
467
+
468
+ .step-description {
469
+ color: #c0c0c0;
470
+ font-size: ${fontSize};
471
+ margin: 4px 0;
472
+ }
473
+
474
+ /* Formatted Text */
475
+ .formatted-text h1 {
476
+ font-size: ${headerFontSize};
477
+ font-weight: 500;
478
+ margin: 16px 0 10px 0;
479
+ color: #f0f0f0;
480
+ }
481
+
482
+ .formatted-text h2 {
483
+ font-size: ${headerFontSize}
484
+ font-weight: 500;
485
+ margin: 14px 0 8px 0;
486
+ color: #e0e0e0;
487
+ }
488
+
489
+ .formatted-text h3 {
490
+ font-size: ${headerFontSize};
491
+ font-weight: 500;
492
+ margin: 12px 0 6px 0;
493
+ color: #d0d0d0;
494
+ }
495
+
496
+ .formatted-text p {
497
+ margin: 10px 0;
498
+ color: #d0d0d0;
499
+ }
500
+
501
+ .code-block {
502
+ background: #1e1e1e;
503
+ border: 1px solid #333;
504
+ border-radius: 6px;
505
+ padding: 12px;
506
+ overflow-x: auto;
507
+ margin: 12px 0;
508
+ }
509
+
510
+ .code-block code {
511
+ color: #e0e0e0;
512
+ font-family: 'Courier New', monospace;
513
+ font-size: ${fontSize};
514
+ }
515
+
516
+ /* Inline Formatting */
517
+ .inline-code {
518
+ background: rgba(255, 255, 255, 0.1);
519
+ padding: 2px 6px;
520
+ border-radius: 3px;
521
+ font-family: 'Courier New', monospace;
522
+ font-size: ${fontSize};
523
+ color: ${primaryColor};
524
+ }
525
+
526
+ .inline-link {
527
+ color: ${primaryColor};
528
+ text-decoration: underline;
529
+ cursor: pointer;
530
+ }
531
+
532
+ .inline-link:hover {
533
+ text-decoration: none;
534
+ opacity: 0.8;
535
+ }
536
+
537
+ strong {
538
+ font-weight: 600;
539
+ color: #f0f0f0;
540
+ }
541
+
542
+ em {
543
+ font-style: italic;
544
+ color: #e0e0e0;
545
+ }
546
+
547
+ /* Smart Content Rendering */
548
+ .smart-content {
549
+ margin: 0;
550
+ }
551
+
552
+ .section-heading {
553
+ font-size: calc(${headerFontSize} + 2px);
554
+ font-weight: 600;
555
+ margin: 16px 0 12px 0;
556
+ color: #f0f0f0;
557
+ border-bottom: 2px solid ${primaryColor};
558
+ padding-bottom: 6px;
559
+ }
560
+
561
+ .section-subheading {
562
+ font-size: ${headerFontSize};
563
+ font-weight: 500;
564
+ margin: 14px 0 10px 0;
565
+ color: #e0e0e0;
566
+ }
567
+
568
+ .section-text {
569
+ margin: 8px 0;
570
+ color: #d0d0d0;
571
+ font-size: ${fontSize};
572
+ line-height: 1.6;
573
+ }
574
+
575
+ .colon-heading {
576
+ font-size: ${headerFontSize};
577
+ font-weight: 600;
578
+ margin: 12px 0 6px 0;
579
+ color: ${primaryColor};
580
+ position: relative;
581
+ padding-left: 12px;
582
+ }
583
+
584
+ .colon-heading::before {
585
+ content: '';
586
+ position: absolute;
587
+ left: 0;
588
+ top: 50%;
589
+ transform: translateY(-50%);
590
+ width: 4px;
591
+ height: 60%;
592
+ background: ${primaryColor};
593
+ border-radius: 2px;
594
+ }
595
+
596
+ /* Definition List Style (Header + Description) */
597
+ .definition-item {
598
+ margin: 12px 0;
599
+ padding: 10px 12px;
600
+ background: rgba(99, 102, 241, 0.03);
601
+ border-left: 3px solid ${primaryColor};
602
+ border-radius: 4px;
603
+ }
604
+
605
+ .definition-term {
606
+ font-size: ${headerFontSize};
607
+ font-weight: 600;
608
+ color: ${primaryColor};
609
+ margin-bottom: 6px;
610
+ }
611
+
612
+ .definition-description {
613
+ font-size: ${fontSize};
614
+ color: #d0d0d0;
615
+ line-height: 1.6;
616
+ padding-left: 8px;
617
+ }
618
+ ` })] }));
619
+ };
package/dist/types.d.ts CHANGED
@@ -53,6 +53,12 @@ export interface ChatbotConfig {
53
53
  maxHeight?: string;
54
54
  /** Maximum width of the chat window */
55
55
  maxWidth?: string;
56
+ /** Font size for message text (default: '13px') */
57
+ fontSize?: string;
58
+ /** Font size for headers (default: '15px') */
59
+ headerFontSize?: string;
60
+ /** Font size for small text like timestamps (default: '11px') */
61
+ smallFontSize?: string;
56
62
  /** Custom CSS class for styling */
57
63
  className?: string;
58
64
  /** Callback when chat is opened */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fyrebot-widget",
3
- "version": "1.3.3",
3
+ "version": "1.5.0",
4
4
  "description": "Production-ready AI chatbot popup widget by Fyrebot - Multi-tenant support with seamless React integration",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -49,7 +49,12 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "axios": "^1.7.0",
52
- "lucide-react": "^0.460.0"
52
+ "lucide-react": "^0.460.0",
53
+ "marked": "^17.0.1",
54
+ "prismjs": "^1.30.0",
55
+ "react-markdown": "^10.1.0",
56
+ "rehype-raw": "^7.0.0",
57
+ "remark-gfm": "^4.0.1"
53
58
  },
54
59
  "devDependencies": {
55
60
  "@types/react": "^18.3.0",