@blumessage/react-chat 1.0.6 → 1.0.8
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 +38 -0
- package/dist/BlumessageChat.js +76 -25
- package/dist/types/BlumessageChat.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,8 @@ 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" |
|
|
87
|
+
| `typingText` | `string` | `"Agent is typing..."` | Custom text shown while waiting for assistant response |
|
|
86
88
|
| **Event Callbacks** |
|
|
87
89
|
| `onUserMessage` | `(message: Message) => void` | - | Called when user sends message |
|
|
88
90
|
| `onAssistantMessage` | `(message: Message) => void` | - | Called when assistant responds |
|
|
@@ -155,6 +157,42 @@ const initialMessages = [
|
|
|
155
157
|
/>
|
|
156
158
|
```
|
|
157
159
|
|
|
160
|
+
### Chat with Timestamps
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<BlumessageChat
|
|
164
|
+
apiKey="your-api-key"
|
|
165
|
+
showTimestamps={true} // Shows "14:00" or "17 July, 13:00"
|
|
166
|
+
floating={false}
|
|
167
|
+
initialMessages={[
|
|
168
|
+
{
|
|
169
|
+
id: '1',
|
|
170
|
+
role: 'assistant' as const,
|
|
171
|
+
content: 'Message from today',
|
|
172
|
+
timestamp: Date.now() - (60 * 60 * 1000) // Shows: "14:00" (or "2:00 PM")
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: '2',
|
|
176
|
+
role: 'user' as const,
|
|
177
|
+
content: 'Message from yesterday',
|
|
178
|
+
timestamp: Date.now() - (24 * 60 * 60 * 1000) // Shows: "17 July, 13:00"
|
|
179
|
+
}
|
|
180
|
+
]}
|
|
181
|
+
/>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Custom Typing Indicator
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
<BlumessageChat
|
|
188
|
+
apiKey="your-api-key"
|
|
189
|
+
typingText="Support agent is typing..." // Custom loading message
|
|
190
|
+
// Or use different text for different languages:
|
|
191
|
+
// typingText="L'agent écrit..." // French
|
|
192
|
+
// typingText="El agente está escribiendo..." // Spanish
|
|
193
|
+
/>
|
|
194
|
+
```
|
|
195
|
+
|
|
158
196
|
## Icon Options
|
|
159
197
|
|
|
160
198
|
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, _k = _a.typingText, typingText = _k === void 0 ? "Agent is typing..." : _k,
|
|
105
105
|
// Floating button props
|
|
106
|
-
|
|
106
|
+
_l = _a.floating,
|
|
107
107
|
// Floating button props
|
|
108
|
-
floating =
|
|
108
|
+
floating = _l === void 0 ? true : _l, _m = _a.buttonText, buttonText = _m === void 0 ? "Chat with us" : _m, _o = _a.buttonPosition, buttonPosition = _o === void 0 ? 'bottom-right' : _o, buttonStyle = _a.buttonStyle, _p = _a.defaultOpen, defaultOpen = _p === void 0 ? false : _p, _q = _a.maximizeToggleButton, maximizeToggleButton = _q === void 0 ? true : _q, _r = _a.fullScreen, fullScreen = _r === void 0 ? false : _r, _s = _a.icon, icon = _s === void 0 ? 'message-circle' : _s,
|
|
109
109
|
// Styling props
|
|
110
|
-
|
|
110
|
+
_t = _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 = _t === void 0 ? "linear-gradient(to right, #3b82f6,rgb(8, 98, 242))" : _t;
|
|
113
|
+
var _u = useState(false), isInitialized = _u[0], setIsInitialized = _u[1];
|
|
114
|
+
var _v = useState(null), error = _v[0], setError = _v[1];
|
|
115
|
+
var _w = useState(initialMessages), messages = _w[0], setMessages = _w[1];
|
|
116
|
+
var _x = useState(''), inputValue = _x[0], setInputValue = _x[1];
|
|
117
|
+
var _y = useState(initialConversationId || getStoredConversationId(persistent)), conversationId = _y[0], setConversationId = _y[1];
|
|
118
|
+
var _z = useState(defaultOpen), isOpen = _z[0], setIsOpen = _z[1];
|
|
119
|
+
var _0 = useState(false), isAnimating = _0[0], setIsAnimating = _0[1];
|
|
120
|
+
var _1 = useState(false), isLoading = _1[0], setIsLoading = _1[1];
|
|
121
|
+
var _2 = useState(false), isMaximized = _2[0], setIsMaximized = _2[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 _3 = getDimensions(), actualWidth = _3.width, actualHeight = _3.height;
|
|
146
174
|
// Function to update conversation ID and notify parent
|
|
147
175
|
var updateConversationId = function (newConversationId) {
|
|
148
176
|
setConversationId(newConversationId);
|
|
@@ -580,19 +608,32 @@ 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
|
-
: 'bg-white text-gray-800 border border-gray-200'), children:
|
|
636
|
+
: 'bg-white text-gray-800 border border-gray-200'), children: _jsx("div", { className: "".concat(theme === 'dark' ? 'text-gray-300' : 'text-gray-600'), style: { fontStyle: 'italic' }, children: typingText }) }) })), 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'
|
|
597
638
|
: 'bg-white border-gray-100'), children: _jsxs("div", { className: "flex items-center rounded-full px-4 py-3 border ".concat(theme === 'dark'
|
|
598
639
|
? 'bg-gray-800 border-gray-600'
|
|
@@ -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,8 @@ export interface BlumessageChatProps {
|
|
|
35
35
|
onChatWidgetClosed?: () => void;
|
|
36
36
|
onError?: (error: string, context?: string) => void;
|
|
37
37
|
persistent?: boolean;
|
|
38
|
+
showTimestamps?: boolean;
|
|
39
|
+
typingText?: string;
|
|
38
40
|
floating?: boolean;
|
|
39
41
|
buttonText?: string;
|
|
40
42
|
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.8",
|
|
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>",
|