@blumessage/react-chat 1.0.6 → 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 +75 -24
- 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
|
@@ -101,26 +101,54 @@ var clearStoredConversationId = function (persistent) {
|
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
export var BlumessageChat = function (_a) {
|
|
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,
|
|
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,
|
|
105
105
|
// Floating button props
|
|
106
|
-
|
|
106
|
+
_k = _a.floating,
|
|
107
107
|
// Floating button props
|
|
108
|
-
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,
|
|
109
109
|
// Styling props
|
|
110
|
-
|
|
110
|
+
_s = _a.primaryColor,
|
|
111
111
|
// Styling props
|
|
112
|
-
primaryColor =
|
|
113
|
-
var
|
|
114
|
-
var
|
|
115
|
-
var
|
|
116
|
-
var
|
|
117
|
-
var
|
|
118
|
-
var
|
|
119
|
-
var
|
|
120
|
-
var
|
|
121
|
-
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];
|
|
122
122
|
var messagesEndRef = useRef(null);
|
|
123
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
|
+
};
|
|
124
152
|
// Helper function to get dimensions based on size
|
|
125
153
|
var getDimensions = function () {
|
|
126
154
|
// If custom width/height are provided, use them
|
|
@@ -142,7 +170,7 @@ export var BlumessageChat = function (_a) {
|
|
|
142
170
|
}
|
|
143
171
|
return dimensions;
|
|
144
172
|
};
|
|
145
|
-
var
|
|
173
|
+
var _2 = getDimensions(), actualWidth = _2.width, actualHeight = _2.height;
|
|
146
174
|
// Function to update conversation ID and notify parent
|
|
147
175
|
var updateConversationId = function (newConversationId) {
|
|
148
176
|
setConversationId(newConversationId);
|
|
@@ -580,17 +608,30 @@ export var BlumessageChat = function (_a) {
|
|
|
580
608
|
height: (fullScreen || isMaximized) ? '100%' : actualHeight,
|
|
581
609
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
582
610
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
583
|
-
}, children: [_jsxs("div", { className: "
|
|
611
|
+
}, children: [_jsxs("div", { className: "border-b ".concat(theme === 'dark'
|
|
584
612
|
? 'bg-gray-900 border-gray-700'
|
|
585
|
-
: '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'
|
|
586
623
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
587
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'
|
|
588
625
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
589
|
-
: '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
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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'
|
|
594
635
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
595
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'
|
|
596
637
|
? 'bg-gray-900 border-gray-700'
|
|
@@ -616,7 +657,12 @@ export var BlumessageChat = function (_a) {
|
|
|
616
657
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
617
658
|
}, children: [_jsxs("div", { className: "flex items-center px-6 py-4 border-b ".concat(theme === 'dark'
|
|
618
659
|
? 'bg-gray-900 border-gray-700'
|
|
619
|
-
: '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'
|
|
620
666
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
621
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'
|
|
622
668
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
@@ -638,7 +684,12 @@ export var BlumessageChat = function (_a) {
|
|
|
638
684
|
borderRadius: (fullScreen || isMaximized) ? '12px' : '24px'
|
|
639
685
|
}, children: [_jsxs("div", { className: "flex items-center px-6 py-4 border-b ".concat(theme === 'dark'
|
|
640
686
|
? 'bg-gray-900 border-gray-700'
|
|
641
|
-
: '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'
|
|
642
693
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
643
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'
|
|
644
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>",
|