@blumessage/react-chat 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/BlumessageChat.js +153 -70
- package/dist/types/BlumessageChat.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ function App() {
|
|
|
83
83
|
| `initialMessages` | `Message[]` | `[]` | Pre-populate with messages |
|
|
84
84
|
| `conversationId` | `string` | - | Continue specific conversation |
|
|
85
85
|
| `persistent` | `boolean` | `false` | Use localStorage vs sessionStorage |
|
|
86
|
+
| `showTimestamps` | `boolean` | `false` | Display timestamps: today="14:00", older="17 July, 13:00" |
|
|
86
87
|
| **Event Callbacks** |
|
|
87
88
|
| `onUserMessage` | `(message: Message) => void` | - | Called when user sends message |
|
|
88
89
|
| `onAssistantMessage` | `(message: Message) => void` | - | Called when assistant responds |
|
|
@@ -155,6 +156,30 @@ const initialMessages = [
|
|
|
155
156
|
/>
|
|
156
157
|
```
|
|
157
158
|
|
|
159
|
+
### Chat with Timestamps
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
<BlumessageChat
|
|
163
|
+
apiKey="your-api-key"
|
|
164
|
+
showTimestamps={true} // Shows "14:00" or "17 July, 13:00"
|
|
165
|
+
floating={false}
|
|
166
|
+
initialMessages={[
|
|
167
|
+
{
|
|
168
|
+
id: '1',
|
|
169
|
+
role: 'assistant' as const,
|
|
170
|
+
content: 'Message from today',
|
|
171
|
+
timestamp: Date.now() - (60 * 60 * 1000) // Shows: "14:00" (or "2:00 PM")
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: '2',
|
|
175
|
+
role: 'user' as const,
|
|
176
|
+
content: 'Message from yesterday',
|
|
177
|
+
timestamp: Date.now() - (24 * 60 * 60 * 1000) // Shows: "17 July, 13:00"
|
|
178
|
+
}
|
|
179
|
+
]}
|
|
180
|
+
/>
|
|
181
|
+
```
|
|
182
|
+
|
|
158
183
|
## Icon Options
|
|
159
184
|
|
|
160
185
|
The `icon` prop accepts **any lucide-react icon name** with flexible naming patterns. The component intelligently matches your input to the appropriate lucide-react icon:
|
package/dist/BlumessageChat.js
CHANGED
|
@@ -57,6 +57,15 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
57
57
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
58
58
|
import React, { useState, useEffect, useRef } from "react";
|
|
59
59
|
import { MessageCircle, AlertTriangle, Loader2, Send, X, Maximize, Minimize2, Bot, MessageSquare, Phone, Mail, Headphones, Users, User, Heart, Star, Zap } from "lucide-react";
|
|
60
|
+
// Custom CSS animations that don't depend on Tailwind
|
|
61
|
+
var customStyles = "\n @keyframes bounce {\n 0%, 100% {\n transform: translateY(0);\n }\n 50% {\n transform: translateY(-25%);\n }\n }\n \n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n \n .blumessage-animate-bounce {\n animation: bounce 1s infinite;\n }\n \n .blumessage-animate-spin {\n animation: spin 1s linear infinite;\n }\n";
|
|
62
|
+
// Inject custom styles
|
|
63
|
+
if (typeof document !== 'undefined' && !document.getElementById('blumessage-styles')) {
|
|
64
|
+
var style = document.createElement('style');
|
|
65
|
+
style.id = 'blumessage-styles';
|
|
66
|
+
style.textContent = customStyles;
|
|
67
|
+
document.head.appendChild(style);
|
|
68
|
+
}
|
|
60
69
|
// Session storage key for conversation ID
|
|
61
70
|
var CONVERSATION_ID_KEY = 'blumessage_conversation_id';
|
|
62
71
|
// Utility functions for storage
|
|
@@ -92,25 +101,54 @@ var clearStoredConversationId = function (persistent) {
|
|
|
92
101
|
}
|
|
93
102
|
};
|
|
94
103
|
export var BlumessageChat = function (_a) {
|
|
95
|
-
var apiKey = _a.apiKey, _b = _a.placeholder, placeholder = _b === void 0 ? "Type your message..." : _b, _c = _a.theme, theme = _c === void 0 ? 'light' : _c, width = _a.width, height = _a.height, _d = _a.size, size = _d === void 0 ? 'medium' : _d, _e = _a.name, name = _e === void 0 ? "Blumessage AI" : _e, _f = _a.subtitle, subtitle = _f === void 0 ? "Online • Instant responses" : _f, _g = _a.initialMessages, initialMessages = _g === void 0 ? [] : _g, onUserMessage = _a.onUserMessage, onAssistantMessage = _a.onAssistantMessage, initialConversationId = _a.conversationId, onConversationIdChange = _a.onConversationIdChange, onChatWidgetOpen = _a.onChatWidgetOpen, onChatWidgetClosed = _a.onChatWidgetClosed, onError = _a.onError, _h = _a.persistent, persistent = _h === void 0 ? false : _h,
|
|
104
|
+
var apiKey = _a.apiKey, _b = _a.placeholder, placeholder = _b === void 0 ? "Type your message..." : _b, _c = _a.theme, theme = _c === void 0 ? 'light' : _c, width = _a.width, height = _a.height, _d = _a.size, size = _d === void 0 ? 'medium' : _d, _e = _a.name, name = _e === void 0 ? "Blumessage AI" : _e, _f = _a.subtitle, subtitle = _f === void 0 ? "Online • Instant responses" : _f, _g = _a.initialMessages, initialMessages = _g === void 0 ? [] : _g, onUserMessage = _a.onUserMessage, onAssistantMessage = _a.onAssistantMessage, initialConversationId = _a.conversationId, onConversationIdChange = _a.onConversationIdChange, onChatWidgetOpen = _a.onChatWidgetOpen, onChatWidgetClosed = _a.onChatWidgetClosed, onError = _a.onError, _h = _a.persistent, persistent = _h === void 0 ? false : _h, _j = _a.showTimestamps, showTimestamps = _j === void 0 ? false : _j,
|
|
96
105
|
// Floating button props
|
|
97
|
-
|
|
106
|
+
_k = _a.floating,
|
|
98
107
|
// Floating button props
|
|
99
|
-
floating =
|
|
108
|
+
floating = _k === void 0 ? true : _k, _l = _a.buttonText, buttonText = _l === void 0 ? "Chat with us" : _l, _m = _a.buttonPosition, buttonPosition = _m === void 0 ? 'bottom-right' : _m, buttonStyle = _a.buttonStyle, _o = _a.defaultOpen, defaultOpen = _o === void 0 ? false : _o, _p = _a.maximizeToggleButton, maximizeToggleButton = _p === void 0 ? true : _p, _q = _a.fullScreen, fullScreen = _q === void 0 ? false : _q, _r = _a.icon, icon = _r === void 0 ? 'message-circle' : _r,
|
|
100
109
|
// Styling props
|
|
101
|
-
|
|
110
|
+
_s = _a.primaryColor,
|
|
102
111
|
// Styling props
|
|
103
|
-
primaryColor =
|
|
104
|
-
var
|
|
105
|
-
var
|
|
106
|
-
var
|
|
107
|
-
var
|
|
108
|
-
var
|
|
109
|
-
var
|
|
110
|
-
var
|
|
111
|
-
var
|
|
112
|
-
var
|
|
112
|
+
primaryColor = _s === void 0 ? "linear-gradient(to right, #3b82f6,rgb(8, 98, 242))" : _s;
|
|
113
|
+
var _t = useState(false), isInitialized = _t[0], setIsInitialized = _t[1];
|
|
114
|
+
var _u = useState(null), error = _u[0], setError = _u[1];
|
|
115
|
+
var _v = useState(initialMessages), messages = _v[0], setMessages = _v[1];
|
|
116
|
+
var _w = useState(''), inputValue = _w[0], setInputValue = _w[1];
|
|
117
|
+
var _x = useState(initialConversationId || getStoredConversationId(persistent)), conversationId = _x[0], setConversationId = _x[1];
|
|
118
|
+
var _y = useState(defaultOpen), isOpen = _y[0], setIsOpen = _y[1];
|
|
119
|
+
var _z = useState(false), isAnimating = _z[0], setIsAnimating = _z[1];
|
|
120
|
+
var _0 = useState(false), isLoading = _0[0], setIsLoading = _0[1];
|
|
121
|
+
var _1 = useState(false), isMaximized = _1[0], setIsMaximized = _1[1];
|
|
113
122
|
var messagesEndRef = useRef(null);
|
|
123
|
+
var isInitialLoad = useRef(true);
|
|
124
|
+
// Helper function to format timestamp
|
|
125
|
+
var formatTimestamp = function (timestamp) {
|
|
126
|
+
var date = new Date(timestamp);
|
|
127
|
+
var now = new Date();
|
|
128
|
+
// Check if the message is from today
|
|
129
|
+
var isToday = date.toDateString() === now.toDateString();
|
|
130
|
+
if (isToday) {
|
|
131
|
+
// If today: show time only in user's locale format (14:00 or 2:00 PM)
|
|
132
|
+
return date.toLocaleTimeString(undefined, {
|
|
133
|
+
hour: '2-digit',
|
|
134
|
+
minute: '2-digit',
|
|
135
|
+
hour12: undefined // Let browser decide based on user's locale
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// If more than a day: show "17 July, 13:00" format in user's locale
|
|
140
|
+
var dateStr = date.toLocaleDateString(undefined, {
|
|
141
|
+
day: 'numeric',
|
|
142
|
+
month: 'long'
|
|
143
|
+
});
|
|
144
|
+
var timeStr = date.toLocaleTimeString(undefined, {
|
|
145
|
+
hour: '2-digit',
|
|
146
|
+
minute: '2-digit',
|
|
147
|
+
hour12: undefined // Let browser decide based on user's locale
|
|
148
|
+
});
|
|
149
|
+
return "".concat(dateStr, ", ").concat(timeStr);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
114
152
|
// Helper function to get dimensions based on size
|
|
115
153
|
var getDimensions = function () {
|
|
116
154
|
// If custom width/height are provided, use them
|
|
@@ -118,17 +156,21 @@ export var BlumessageChat = function (_a) {
|
|
|
118
156
|
return { width: width, height: height };
|
|
119
157
|
}
|
|
120
158
|
// Otherwise, use size-based dimensions
|
|
159
|
+
var dimensions;
|
|
121
160
|
switch (size) {
|
|
122
161
|
case 'small':
|
|
123
|
-
|
|
162
|
+
dimensions = { width: '320px', height: '400px' };
|
|
163
|
+
break;
|
|
124
164
|
case 'large':
|
|
125
|
-
|
|
165
|
+
dimensions = { width: '680px', height: '800px' };
|
|
166
|
+
break;
|
|
126
167
|
case 'medium':
|
|
127
168
|
default:
|
|
128
|
-
|
|
169
|
+
dimensions = { width: '480px', height: '600px' };
|
|
129
170
|
}
|
|
171
|
+
return dimensions;
|
|
130
172
|
};
|
|
131
|
-
var
|
|
173
|
+
var _2 = getDimensions(), actualWidth = _2.width, actualHeight = _2.height;
|
|
132
174
|
// Function to update conversation ID and notify parent
|
|
133
175
|
var updateConversationId = function (newConversationId) {
|
|
134
176
|
setConversationId(newConversationId);
|
|
@@ -198,11 +240,11 @@ export var BlumessageChat = function (_a) {
|
|
|
198
240
|
}
|
|
199
241
|
// Validate API key with Blumessage API
|
|
200
242
|
var validateApiKey = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
201
|
-
var response,
|
|
243
|
+
var response, errorMessage, err_1, errorMessage;
|
|
202
244
|
return __generator(this, function (_a) {
|
|
203
245
|
switch (_a.label) {
|
|
204
246
|
case 0:
|
|
205
|
-
_a.trys.push([0,
|
|
247
|
+
_a.trys.push([0, 2, , 3]);
|
|
206
248
|
setIsInitialized(false);
|
|
207
249
|
setError(null);
|
|
208
250
|
console.log("Initializing Blumessage chat...");
|
|
@@ -215,43 +257,22 @@ export var BlumessageChat = function (_a) {
|
|
|
215
257
|
})];
|
|
216
258
|
case 1:
|
|
217
259
|
response = _a.sent();
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
return [3 /*break*/, 6];
|
|
232
|
-
case 3:
|
|
233
|
-
if (!conversationId) return [3 /*break*/, 5];
|
|
234
|
-
return [4 /*yield*/, fetchConversationHistory(conversationId)];
|
|
235
|
-
case 4:
|
|
236
|
-
historyMessages = _a.sent();
|
|
237
|
-
setMessages(historyMessages); // Will be empty array if fetch failed
|
|
238
|
-
return [3 /*break*/, 6];
|
|
239
|
-
case 5:
|
|
240
|
-
// No conversation ID and no initial messages - start with empty array
|
|
241
|
-
setMessages([]);
|
|
242
|
-
_a.label = 6;
|
|
243
|
-
case 6: return [3 /*break*/, 8];
|
|
244
|
-
case 7:
|
|
245
|
-
console.error("Blumessage chat initialization failed:", response.status, response.statusText);
|
|
246
|
-
errorMessage = "Unable to connect - invalid API key";
|
|
247
|
-
setError(errorMessage);
|
|
248
|
-
setIsInitialized(false);
|
|
249
|
-
if (onError) {
|
|
250
|
-
onError(errorMessage, "api_key_validation");
|
|
260
|
+
if (response.ok) {
|
|
261
|
+
console.log("Blumessage chat initialized successfully");
|
|
262
|
+
setIsInitialized(true);
|
|
263
|
+
setError(null);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
console.error("Blumessage chat initialization failed:", response.status, response.statusText);
|
|
267
|
+
errorMessage = "Unable to connect - invalid API key";
|
|
268
|
+
setError(errorMessage);
|
|
269
|
+
setIsInitialized(false);
|
|
270
|
+
if (onError) {
|
|
271
|
+
onError(errorMessage, "api_key_validation");
|
|
272
|
+
}
|
|
251
273
|
}
|
|
252
|
-
|
|
253
|
-
case
|
|
254
|
-
case 9:
|
|
274
|
+
return [3 /*break*/, 3];
|
|
275
|
+
case 2:
|
|
255
276
|
err_1 = _a.sent();
|
|
256
277
|
console.error("Blumessage chat initialization error:", err_1);
|
|
257
278
|
errorMessage = "Unable to connect - network error";
|
|
@@ -260,13 +281,52 @@ export var BlumessageChat = function (_a) {
|
|
|
260
281
|
if (onError) {
|
|
261
282
|
onError(errorMessage, "network_error");
|
|
262
283
|
}
|
|
263
|
-
return [3 /*break*/,
|
|
264
|
-
case
|
|
284
|
+
return [3 /*break*/, 3];
|
|
285
|
+
case 3: return [2 /*return*/];
|
|
265
286
|
}
|
|
266
287
|
});
|
|
267
288
|
}); };
|
|
268
289
|
validateApiKey();
|
|
269
|
-
}, [apiKey
|
|
290
|
+
}, [apiKey]);
|
|
291
|
+
// Handle initial message loading (only runs once on mount)
|
|
292
|
+
useEffect(function () {
|
|
293
|
+
var loadInitialMessages = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
294
|
+
var historyMessages;
|
|
295
|
+
return __generator(this, function (_a) {
|
|
296
|
+
switch (_a.label) {
|
|
297
|
+
case 0:
|
|
298
|
+
if (!isInitialLoad.current) return [3 /*break*/, 5];
|
|
299
|
+
isInitialLoad.current = false;
|
|
300
|
+
if (!(initialMessages.length > 0 && conversationId)) return [3 /*break*/, 1];
|
|
301
|
+
// Warn if both are provided - initialMessages takes precedence
|
|
302
|
+
console.warn('Both initialMessages and conversationId provided. Using initialMessages and ignoring stored conversation.');
|
|
303
|
+
setMessages(initialMessages);
|
|
304
|
+
return [3 /*break*/, 5];
|
|
305
|
+
case 1:
|
|
306
|
+
if (!(initialMessages.length > 0)) return [3 /*break*/, 2];
|
|
307
|
+
// Use provided initial messages
|
|
308
|
+
setMessages(initialMessages);
|
|
309
|
+
return [3 /*break*/, 5];
|
|
310
|
+
case 2:
|
|
311
|
+
if (!conversationId) return [3 /*break*/, 4];
|
|
312
|
+
return [4 /*yield*/, fetchConversationHistory(conversationId)];
|
|
313
|
+
case 3:
|
|
314
|
+
historyMessages = _a.sent();
|
|
315
|
+
setMessages(historyMessages); // Will be empty array if fetch failed
|
|
316
|
+
return [3 /*break*/, 5];
|
|
317
|
+
case 4:
|
|
318
|
+
// No conversation ID and no initial messages - start with empty array
|
|
319
|
+
setMessages([]);
|
|
320
|
+
_a.label = 5;
|
|
321
|
+
case 5: return [2 /*return*/];
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}); };
|
|
325
|
+
// Only load initial messages after API key is validated
|
|
326
|
+
if (isInitialized) {
|
|
327
|
+
loadInitialMessages();
|
|
328
|
+
}
|
|
329
|
+
}, [isInitialized]);
|
|
270
330
|
var handleSendMessage = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
271
331
|
var userMessage, currentInput, requestBody, response, apiResponse, assistantMessages, latestAssistantMessage, assistantResponse_1, errorMessage_1, error_2, errorMessage_2;
|
|
272
332
|
return __generator(this, function (_a) {
|
|
@@ -548,23 +608,36 @@ export var BlumessageChat = function (_a) {
|
|
|
548
608
|
height: (fullScreen || isMaximized) ? '100%' : actualHeight,
|
|
549
609
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
550
610
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
551
|
-
}, children: [_jsxs("div", { className: "
|
|
611
|
+
}, children: [_jsxs("div", { className: "border-b ".concat(theme === 'dark'
|
|
552
612
|
? 'bg-gray-900 border-gray-700'
|
|
553
|
-
: 'bg-white border-gray-100'),
|
|
613
|
+
: 'bg-white border-gray-100'), style: {
|
|
614
|
+
display: 'flex',
|
|
615
|
+
alignItems: 'center',
|
|
616
|
+
padding: '16px 24px'
|
|
617
|
+
}, children: [_jsx("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
618
|
+
backgroundImage: primaryColor,
|
|
619
|
+
width: '48px',
|
|
620
|
+
height: '48px',
|
|
621
|
+
marginRight: '24px'
|
|
622
|
+
}, children: React.createElement(getIconComponent(), { className: "w-6 h-6 text-white" }) }), _jsxs("div", { style: { flex: 1 }, children: [_jsx("div", { className: "text-lg font-semibold m-0 leading-6 ".concat(theme === 'dark' ? 'text-gray-100' : 'text-gray-900'), children: name }), _jsx("div", { className: "text-sm m-0 leading-5 ".concat(theme === 'dark' ? 'text-gray-400' : 'text-gray-500'), children: subtitle })] }), floating && (_jsxs("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && (_jsx("button", { onClick: handleToggleMaximize, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
554
623
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
555
624
|
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'), children: isMaximized ? _jsx(Minimize2, { className: "w-4 h-4" }) : _jsx(Maximize, { className: "w-4 h-4" }) })), _jsx("button", { onClick: handleCloseChat, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
556
625
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
557
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'), children: _jsx(X, { className: "w-4 h-4" }) })] }))] }), _jsxs("div", { className: "flex-1 px-6 py-4 flex flex-col gap-4 overflow-y-auto ".concat(theme === 'dark' ? 'bg-gray-800' : 'bg-gray-50'), children: [messages.map(function (message) { return (_jsx("div", { className: "flex ".concat(message.role === 'user' ? 'justify-end' : 'justify-start'), children: _jsx("div", { className: "px-4 py-3 rounded-2xl
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
626
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'), children: _jsx(X, { className: "w-4 h-4" }) })] }))] }), _jsxs("div", { className: "flex-1 px-6 py-4 flex flex-col gap-4 overflow-y-auto ".concat(theme === 'dark' ? 'bg-gray-800' : 'bg-gray-50'), children: [messages.map(function (message) { return (_jsx("div", { className: "flex ".concat(message.role === 'user' ? 'justify-end' : 'justify-start'), children: _jsxs("div", { className: "max-w-[80%] ".concat(message.role === 'user' ? 'text-right' : 'text-left'), children: [_jsx("div", { className: "px-4 py-3 rounded-2xl text-sm leading-6 ".concat(message.role === 'user'
|
|
627
|
+
? 'text-white'
|
|
628
|
+
: theme === 'dark'
|
|
629
|
+
? 'bg-gray-700 text-gray-100 border border-gray-600 shadow-sm'
|
|
630
|
+
: 'bg-white text-gray-800 border border-gray-200 shadow-sm'), style: message.role === 'user' ? { backgroundImage: primaryColor } : {}, children: message.content }), showTimestamps && (_jsx("div", { className: "text-xs mt-1 ".concat(theme === 'dark' ? 'text-gray-500' : 'text-gray-400'), style: {
|
|
631
|
+
textAlign: message.role === 'user' ? 'right' : 'left',
|
|
632
|
+
paddingLeft: message.role === 'assistant' ? '16px' : '0',
|
|
633
|
+
paddingRight: message.role === 'user' ? '16px' : '0'
|
|
634
|
+
}, children: formatTimestamp(message.timestamp) }))] }) }, message.id)); }), isLoading && (_jsx("div", { className: "flex justify-start", children: _jsx("div", { className: "px-4 py-3 rounded-2xl max-w-[80%] text-sm leading-6 shadow-sm ".concat(theme === 'dark'
|
|
562
635
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
563
|
-
: 'bg-white text-gray-800 border border-gray-200'), children: _jsxs("div", { className: "flex space-x-1", children: [_jsx("div", { className: "w-2 h-2 rounded-full animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '0ms' } }), _jsx("div", { className: "w-2 h-2 rounded-full animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '150ms' } }), _jsx("div", { className: "w-2 h-2 rounded-full animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '300ms' } })] }) }) })), messages.length === 0 && !isLoading && (_jsx("div", { className: "text-center text-sm py-8 ".concat(theme === 'dark' ? 'text-gray-400' : 'text-gray-500'), children: "No messages yet. Start a conversation!" })), _jsx("div", { ref: messagesEndRef })] }), _jsx("div", { className: "px-6 py-4 border-t ".concat(theme === 'dark'
|
|
636
|
+
: 'bg-white text-gray-800 border border-gray-200'), children: _jsxs("div", { className: "flex space-x-1", children: [_jsx("div", { className: "w-2 h-2 rounded-full blumessage-animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '0ms' } }), _jsx("div", { className: "w-2 h-2 rounded-full blumessage-animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '150ms' } }), _jsx("div", { className: "w-2 h-2 rounded-full blumessage-animate-bounce ".concat(theme === 'dark' ? 'bg-gray-400' : 'bg-gray-400'), style: { animationDelay: '300ms' } })] }) }) })), messages.length === 0 && !isLoading && (_jsx("div", { className: "text-center text-sm py-8 ".concat(theme === 'dark' ? 'text-gray-400' : 'text-gray-500'), children: "No messages yet. Start a conversation!" })), _jsx("div", { ref: messagesEndRef })] }), _jsx("div", { className: "px-6 py-4 border-t ".concat(theme === 'dark'
|
|
564
637
|
? 'bg-gray-900 border-gray-700'
|
|
565
638
|
: 'bg-white border-gray-100'), children: _jsxs("div", { className: "flex items-center rounded-full px-4 py-3 border ".concat(theme === 'dark'
|
|
566
639
|
? 'bg-gray-800 border-gray-600'
|
|
567
|
-
: 'bg-gray-50 border-gray-200'), children: [_jsx("input", { className: "flex-1 border-none bg-transparent outline-none text-sm font-inherit ".concat(theme === 'dark' ? 'text-gray-100' : 'text-gray-700'), type: "text", placeholder: placeholder, value: inputValue, onChange: function (e) { return setInputValue(e.target.value); }, onKeyPress: handleKeyPress }), _jsx("button", { className: "w-8 h-8 rounded-full border-none flex items-center justify-center cursor-pointer ml-2 text-white transition-all disabled:opacity-50 disabled:cursor-not-allowed", style: { backgroundImage: primaryColor }, onClick: handleSendMessage, disabled: !inputValue.trim() || isLoading, children: isLoading ? (_jsx(Loader2, { className: "w-4 h-4 animate-spin" })) : (_jsx(Send, { className: "w-4 h-4" })) })] }) })] }));
|
|
640
|
+
: 'bg-gray-50 border-gray-200'), children: [_jsx("input", { className: "flex-1 border-none bg-transparent outline-none text-sm font-inherit ".concat(theme === 'dark' ? 'text-gray-100' : 'text-gray-700'), type: "text", placeholder: placeholder, value: inputValue, onChange: function (e) { return setInputValue(e.target.value); }, onKeyPress: handleKeyPress }), _jsx("button", { className: "w-8 h-8 rounded-full border-none flex items-center justify-center cursor-pointer ml-2 text-white transition-all disabled:opacity-50 disabled:cursor-not-allowed", style: { backgroundImage: primaryColor }, onClick: handleSendMessage, disabled: !inputValue.trim() || isLoading, children: isLoading ? (_jsx(Loader2, { className: "w-4 h-4 blumessage-animate-spin" })) : (_jsx(Send, { className: "w-4 h-4" })) })] }) })] }));
|
|
568
641
|
if (floating) {
|
|
569
642
|
return (_jsx("div", { style: getChatPositionStyles(), children: chatContent }));
|
|
570
643
|
}
|
|
@@ -584,7 +657,12 @@ export var BlumessageChat = function (_a) {
|
|
|
584
657
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
585
658
|
}, children: [_jsxs("div", { className: "flex items-center px-6 py-4 border-b ".concat(theme === 'dark'
|
|
586
659
|
? 'bg-gray-900 border-gray-700'
|
|
587
|
-
: 'bg-white border-gray-100'), children: [_jsx("div", { className: "
|
|
660
|
+
: 'bg-white border-gray-100'), children: [_jsx("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
661
|
+
backgroundColor: '#ef4444',
|
|
662
|
+
width: '48px',
|
|
663
|
+
height: '48px',
|
|
664
|
+
marginRight: '24px'
|
|
665
|
+
}, children: _jsx(AlertTriangle, { className: "w-6 h-6 text-white" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-lg font-semibold m-0 leading-6 ".concat(theme === 'dark' ? 'text-gray-100' : 'text-gray-900'), children: "Connection Error" }), _jsx("div", { className: "text-sm m-0 leading-5 ".concat(theme === 'dark' ? 'text-gray-400' : 'text-gray-500'), children: "Unable to connect" })] }), floating && (_jsxs("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && (_jsx("button", { onClick: handleToggleMaximize, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
588
666
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
589
667
|
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'), children: isMaximized ? _jsx(Minimize2, { className: "w-4 h-4" }) : _jsx(Maximize, { className: "w-4 h-4" }) })), _jsx("button", { onClick: handleCloseChat, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
590
668
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
@@ -606,7 +684,12 @@ export var BlumessageChat = function (_a) {
|
|
|
606
684
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
607
685
|
}, children: [_jsxs("div", { className: "flex items-center px-6 py-4 border-b ".concat(theme === 'dark'
|
|
608
686
|
? 'bg-gray-900 border-gray-700'
|
|
609
|
-
: 'bg-white border-gray-100'), children: [_jsx("div", { className: "
|
|
687
|
+
: 'bg-white border-gray-100'), children: [_jsx("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
688
|
+
backgroundImage: primaryColor,
|
|
689
|
+
width: '48px',
|
|
690
|
+
height: '48px',
|
|
691
|
+
marginRight: '24px'
|
|
692
|
+
}, children: _jsx(Loader2, { className: "w-6 h-6 text-white animate-spin" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-lg font-semibold m-0 leading-6 ".concat(theme === 'dark' ? 'text-gray-100' : 'text-gray-900'), children: name }), _jsx("div", { className: "text-sm m-0 leading-5 ".concat(theme === 'dark' ? 'text-gray-400' : 'text-gray-500'), children: subtitle })] }), floating && (_jsxs("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && (_jsx("button", { onClick: handleToggleMaximize, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
610
693
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
611
694
|
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'), children: isMaximized ? _jsx(Minimize2, { className: "w-4 h-4" }) : _jsx(Maximize, { className: "w-4 h-4" }) })), _jsx("button", { onClick: handleCloseChat, className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ".concat(theme === 'dark'
|
|
612
695
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
@@ -35,6 +35,7 @@ export interface BlumessageChatProps {
|
|
|
35
35
|
onChatWidgetClosed?: () => void;
|
|
36
36
|
onError?: (error: string, context?: string) => void;
|
|
37
37
|
persistent?: boolean;
|
|
38
|
+
showTimestamps?: boolean;
|
|
38
39
|
floating?: boolean;
|
|
39
40
|
buttonText?: string;
|
|
40
41
|
buttonPosition?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blumessage/react-chat",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "A React TypeScript chat widget component with floating button, theming, and Blumessage API integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blumessage <contact@blumessage.com>",
|