floating-copilot-widget 1.1.0 → 1.2.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.
@@ -8,6 +8,415 @@
8
8
  --shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.18);
9
9
  }
10
10
 
11
+ /* Wrapper for positioning */
12
+ .copilot-wrapper {
13
+ position: fixed;
14
+ z-index: var(--z-index, 9999);
15
+ }
16
+
17
+ /* Floating Chat Icon */
18
+ .copilot-chat-icon {
19
+ width: 60px;
20
+ height: 60px;
21
+ border-radius: 50%;
22
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
23
+ rgba(var(--primary-color, 99, 102, 241), 0.8) 100%);
24
+ border: none;
25
+ cursor: pointer;
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ font-size: 28px;
30
+ box-shadow: var(--shadow-lg);
31
+ transition: var(--transition-smooth);
32
+ backdrop-filter: blur(10px);
33
+ color: white;
34
+ font-weight: bold;
35
+ }
36
+
37
+ .copilot-chat-icon:hover {
38
+ transform: scale(1.1);
39
+ box-shadow: var(--shadow-xl);
40
+ }
41
+
42
+ .copilot-chat-icon:active {
43
+ transform: scale(0.95);
44
+ }
45
+
46
+ .floating-copilot {
47
+ display: flex;
48
+ flex-direction: column;
49
+ border-radius: 16px;
50
+ box-shadow: var(--shadow-xl);
51
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
52
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
53
+ sans-serif;
54
+ background-color: var(--bg-color, #ffffff);
55
+ color: var(--text-color, #1f2937);
56
+ border: 1px solid var(--border-color, #e5e7eb);
57
+ overflow: hidden;
58
+ transition: var(--transition-smooth);
59
+ backdrop-filter: blur(10px);
60
+ }
61
+
62
+ .floating-copilot:hover {
63
+ box-shadow: var(--shadow-xl);
64
+ }
65
+
66
+ .floating-copilot.maximized {
67
+ border-radius: 0;
68
+ box-shadow: none;
69
+ }
70
+
71
+ /* Header */
72
+ .copilot-header {
73
+ display: flex;
74
+ justify-content: space-between;
75
+ align-items: center;
76
+ padding: 16px 20px;
77
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
78
+ rgba(var(--primary-color, 99, 102, 241), 0.8) 100%);
79
+ color: white;
80
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
81
+ user-select: none;
82
+ cursor: grab;
83
+ transition: var(--transition-smooth);
84
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
85
+ }
86
+
87
+ .copilot-header:hover {
88
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
89
+ rgba(var(--primary-color, 99, 102, 241), 0.9) 100%);
90
+ }
91
+
92
+ .copilot-header:active {
93
+ cursor: grabbing;
94
+ }
95
+
96
+ .copilot-title {
97
+ margin: 0;
98
+ font-size: 16px;
99
+ font-weight: 600;
100
+ flex: 1;
101
+ letter-spacing: 0.3px;
102
+ }
103
+
104
+ .copilot-buttons {
105
+ display: flex;
106
+ gap: 8px;
107
+ align-items: center;
108
+ }
109
+
110
+ .copilot-btn {
111
+ background: rgba(255, 255, 255, 0.2);
112
+ border: 1px solid rgba(255, 255, 255, 0.3);
113
+ color: white;
114
+ width: 32px;
115
+ height: 32px;
116
+ border-radius: 8px;
117
+ cursor: pointer;
118
+ font-size: 16px;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ transition: var(--transition-smooth);
123
+ backdrop-filter: blur(10px);
124
+ padding: 0;
125
+ flex-shrink: 0;
126
+ }
127
+
128
+ .copilot-btn:hover {
129
+ background: rgba(255, 255, 255, 0.3);
130
+ border-color: rgba(255, 255, 255, 0.4);
131
+ transform: translateY(-2px);
132
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
133
+ }
134
+
135
+ .copilot-btn:active {
136
+ transform: translateY(0);
137
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
138
+ }
139
+
140
+ /* Messages Container */
141
+ .copilot-messages {
142
+ flex: 1;
143
+ overflow-y: auto;
144
+ padding: 16px;
145
+ display: flex;
146
+ flex-direction: column;
147
+ gap: 12px;
148
+ background: linear-gradient(to bottom, var(--bg-color, #ffffff) 0%,
149
+ rgba(var(--primary-color, 99, 102, 241), 0.02) 100%);
150
+ }
151
+
152
+ .copilot-empty-state {
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ height: 100%;
157
+ color: #9ca3af;
158
+ text-align: center;
159
+ font-size: 14px;
160
+ flex-direction: column;
161
+ gap: 12px;
162
+ }
163
+
164
+ .copilot-empty-icon {
165
+ font-size: 48px;
166
+ opacity: 0.5;
167
+ }
168
+
169
+ /* Message Styles */
170
+ .copilot-message {
171
+ display: flex;
172
+ flex-direction: column;
173
+ gap: 4px;
174
+ animation: slideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
175
+ }
176
+
177
+ @keyframes slideIn {
178
+ from {
179
+ opacity: 0;
180
+ transform: translateY(12px) scale(0.95);
181
+ }
182
+ to {
183
+ opacity: 1;
184
+ transform: translateY(0) scale(1);
185
+ }
186
+ }
187
+
188
+ .copilot-message-user {
189
+ align-items: flex-end;
190
+ }
191
+
192
+ .copilot-message-bot {
193
+ align-items: flex-start;
194
+ }
195
+
196
+ .copilot-message-content {
197
+ padding: 12px 16px;
198
+ border-radius: 12px;
199
+ max-width: 85%;
200
+ word-wrap: break-word;
201
+ line-height: 1.5;
202
+ font-size: 14px;
203
+ font-weight: 500;
204
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
205
+ }
206
+
207
+ .copilot-message-user .copilot-message-content {
208
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
209
+ rgba(var(--primary-color, 99, 102, 241), 0.9) 100%);
210
+ color: white;
211
+ border-radius: 16px 4px 16px 16px;
212
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
213
+ }
214
+
215
+ .copilot-message-bot .copilot-message-content {
216
+ background: #f3f4f6;
217
+ color: var(--text-color, #1f2937);
218
+ border-radius: 4px 16px 16px 16px;
219
+ border: 1px solid #e5e7eb;
220
+ }
221
+
222
+ .copilot-message-time {
223
+ font-size: 11px;
224
+ color: #9ca3af;
225
+ padding: 0 4px;
226
+ }
227
+
228
+ /* Input Area */
229
+ .copilot-input-area {
230
+ display: flex;
231
+ gap: 10px;
232
+ padding: 14px 16px;
233
+ border-top: 1px solid var(--border-color, #e5e7eb);
234
+ background: linear-gradient(to top, rgba(var(--primary-color, 99, 102, 241), 0.02),
235
+ var(--bg-color, #ffffff));
236
+ backdrop-filter: blur(10px);
237
+ }
238
+
239
+ .copilot-input {
240
+ flex: 1;
241
+ padding: 11px 14px;
242
+ border: 1.5px solid var(--border-color, #e5e7eb);
243
+ border-radius: 10px;
244
+ font-size: 14px;
245
+ font-family: inherit;
246
+ color: var(--text-color, #1f2937);
247
+ background: white;
248
+ transition: var(--transition-smooth);
249
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
250
+ }
251
+
252
+ .copilot-input:focus {
253
+ outline: none;
254
+ border-color: var(--primary-color, #6366f1);
255
+ background: white;
256
+ box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1), 0 4px 12px rgba(99, 102, 241, 0.2);
257
+ transform: translateY(-1px);
258
+ }
259
+
260
+ .copilot-input::placeholder {
261
+ color: #d1d5db;
262
+ }
263
+
264
+ .copilot-send-btn {
265
+ padding: 11px 16px;
266
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
267
+ rgba(var(--primary-color, 99, 102, 241), 0.8) 100%);
268
+ color: white;
269
+ border: none;
270
+ border-radius: 10px;
271
+ cursor: pointer;
272
+ font-weight: 600;
273
+ font-size: 16px;
274
+ transition: var(--transition-smooth);
275
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
276
+ letter-spacing: 0.3px;
277
+ min-width: 50px;
278
+ flex-shrink: 0;
279
+ }
280
+
281
+ .copilot-send-btn:hover {
282
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%,
283
+ rgba(var(--primary-color, 99, 102, 241), 0.7) 100%);
284
+ transform: translateY(-2px);
285
+ box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4);
286
+ }
287
+
288
+ .copilot-send-btn:active {
289
+ transform: translateY(0);
290
+ box-shadow: 0 2px 8px rgba(99, 102, 241, 0.2);
291
+ }
292
+
293
+ .copilot-send-btn:disabled {
294
+ opacity: 0.6;
295
+ cursor: not-allowed;
296
+ transform: none;
297
+ }
298
+
299
+ /* Resize Handle */
300
+ .copilot-resize-handle {
301
+ position: absolute;
302
+ bottom: 0;
303
+ right: 0;
304
+ width: 24px;
305
+ height: 24px;
306
+ cursor: nwse-resize;
307
+ background: linear-gradient(135deg, transparent 50%, var(--primary-color, #6366f1) 50%);
308
+ border-radius: 0 0 16px 0;
309
+ opacity: 0.6;
310
+ transition: var(--transition-smooth);
311
+ }
312
+
313
+ .copilot-resize-handle:hover {
314
+ opacity: 1;
315
+ background: linear-gradient(135deg, transparent 50%, #4f46e5 50%);
316
+ box-shadow: -2px -2px 8px rgba(0, 0, 0, 0.1);
317
+ }
318
+
319
+ /* Scrollbar Styling */
320
+ .copilot-messages::-webkit-scrollbar {
321
+ width: 6px;
322
+ }
323
+
324
+ .copilot-messages::-webkit-scrollbar-track {
325
+ background: rgba(0, 0, 0, 0.03);
326
+ border-radius: 10px;
327
+ }
328
+
329
+ .copilot-messages::-webkit-scrollbar-thumb {
330
+ background: rgba(99, 102, 241, 0.3);
331
+ border-radius: 10px;
332
+ transition: var(--transition-smooth);
333
+ }
334
+
335
+ .copilot-messages::-webkit-scrollbar-thumb:hover {
336
+ background: rgba(99, 102, 241, 0.5);
337
+ }
338
+
339
+ /* Responsive Design */
340
+ @media (max-width: 480px) {
341
+ .floating-copilot {
342
+ width: 100vw !important;
343
+ height: 100vh !important;
344
+ border-radius: 0;
345
+ position: fixed !important;
346
+ top: 0 !important;
347
+ left: 0 !important;
348
+ right: 0 !important;
349
+ bottom: 0 !important;
350
+ }
351
+
352
+ .copilot-message-content {
353
+ max-width: 90%;
354
+ font-size: 15px;
355
+ }
356
+
357
+ .copilot-header {
358
+ padding: 14px 16px;
359
+ }
360
+
361
+ .copilot-input-area {
362
+ padding: 12px 14px;
363
+ }
364
+
365
+ .copilot-resize-handle {
366
+ display: none;
367
+ }
368
+
369
+ .copilot-messages {
370
+ padding: 12px;
371
+ }
372
+
373
+ .copilot-chat-icon {
374
+ width: 56px;
375
+ height: 56px;
376
+ font-size: 24px;
377
+ }
378
+ }
379
+
380
+ /* Dark mode support */
381
+ @media (prefers-color-scheme: dark) {
382
+ .floating-copilot {
383
+ background-color: #1f2937;
384
+ border-color: #374151;
385
+ }
386
+
387
+ .copilot-header {
388
+ border-bottom-color: rgba(0, 0, 0, 0.2);
389
+ }
390
+
391
+ .copilot-messages {
392
+ background: linear-gradient(to bottom, #1f2937 0%, rgba(99, 102, 241, 0.05) 100%);
393
+ }
394
+
395
+ .copilot-input {
396
+ background: #111827;
397
+ color: #f3f4f6;
398
+ border-color: #374151;
399
+ }
400
+
401
+ .copilot-input:focus {
402
+ background: #1f2937;
403
+ }
404
+
405
+ .copilot-input::placeholder {
406
+ color: #6b7280;
407
+ }
408
+
409
+ .copilot-message-bot .copilot-message-content {
410
+ background: #374151;
411
+ color: #f3f4f6;
412
+ border-color: #4b5563;
413
+ }
414
+
415
+ .copilot-empty-state {
416
+ color: #6b7280;
417
+ }
418
+ }
419
+
11
420
  .floating-copilot {
12
421
  display: flex;
13
422
  flex-direction: column;
@@ -6,7 +6,7 @@ export const FloatingCopilot = ({ config = {} }) => {
6
6
  const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
7
7
  const [messages, setMessages] = useState([]);
8
8
  const [inputValue, setInputValue] = useState('');
9
- const [isMinimized, setIsMinimized] = useState(finalConfig.minimized || false);
9
+ const [isOpen, setIsOpen] = useState(!finalConfig.minimized);
10
10
  const [isMaximized, setIsMaximized] = useState(finalConfig.maximized || false);
11
11
  const [position, setPosition] = useState({
12
12
  x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : 20,
@@ -122,11 +122,13 @@ export const FloatingCopilot = ({ config = {} }) => {
122
122
  setMessages((prev) => [...prev, botMessage]);
123
123
  }, 500);
124
124
  };
125
- // Handle minimize
126
- const handleMinimize = () => {
125
+ // Handle toggle open/close
126
+ const handleToggleOpen = () => {
127
127
  var _a;
128
- setIsMinimized(!isMinimized);
129
- (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
128
+ setIsOpen(!isOpen);
129
+ if (!isOpen) {
130
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
131
+ }
130
132
  };
131
133
  // Handle maximize
132
134
  const handleMaximize = () => {
@@ -137,6 +139,7 @@ export const FloatingCopilot = ({ config = {} }) => {
137
139
  // Handle close
138
140
  const handleClose = () => {
139
141
  var _a;
142
+ setIsOpen(false);
140
143
  (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
141
144
  };
142
145
  const getPositionStyle = () => {
@@ -179,30 +182,36 @@ export const FloatingCopilot = ({ config = {} }) => {
179
182
  '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
180
183
  });
181
184
  };
182
- return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''} ${isMinimized ? 'minimized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
183
- finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable ? 'grab' : 'default' } },
185
+ // Closed state - show only chat icon
186
+ if (!isOpen) {
187
+ return (React.createElement("div", { style: Object.assign(Object.assign({}, getPositionStyle()), getThemeStyle()), className: "copilot-wrapper" },
188
+ React.createElement("button", { className: "copilot-chat-icon", onClick: handleToggleOpen, title: "Open chat", "aria-label": "Open chat" }, "\uD83D\uDCAC")));
189
+ }
190
+ // Open state - show full chat
191
+ return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
192
+ finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable && !isMaximized ? 'grab' : 'default' } },
184
193
  React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
185
194
  React.createElement("div", { className: "copilot-buttons" },
186
- finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleMinimize, title: "Minimize" }, isMinimized ? '▲' : '▼')),
187
- finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: "Maximize" }, isMaximized ? '' : '')),
188
- finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close" }, "\u2715"))))),
189
- !isMinimized && (React.createElement(React.Fragment, null,
190
- React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
191
- React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
192
- messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
193
- React.createElement("div", { className: "copilot-message-content" }, msg.text),
194
- React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
195
- hour: '2-digit',
196
- minute: '2-digit',
197
- }))))),
198
- React.createElement("div", { ref: messagesEndRef })))),
199
- React.createElement("div", { className: "copilot-input-area" },
200
- React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
201
- if (e.key === 'Enter') {
202
- handleSendMessage();
203
- }
204
- } }),
205
- React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage }, "Send")),
206
- finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))))));
195
+ finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleToggleOpen, title: "Minimize", "aria-label": "Minimize" }, "\u2212")),
196
+ finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: isMaximized ? 'Restore' : 'Maximize', "aria-label": isMaximized ? 'Restore' : 'Maximize' }, isMaximized ? '' : '')),
197
+ finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close", "aria-label": "Close" }, "\u2715"))))),
198
+ React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
199
+ React.createElement("div", { className: "copilot-empty-icon" }, "\uD83D\uDCAC"),
200
+ React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
201
+ messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
202
+ React.createElement("div", { className: "copilot-message-content" }, msg.text),
203
+ React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
204
+ hour: '2-digit',
205
+ minute: '2-digit',
206
+ }))))),
207
+ React.createElement("div", { ref: messagesEndRef })))),
208
+ React.createElement("div", { className: "copilot-input-area" },
209
+ React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
210
+ if (e.key === 'Enter') {
211
+ handleSendMessage();
212
+ }
213
+ } }),
214
+ React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage, "aria-label": "Send message" }, "\u23CE")),
215
+ finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))));
207
216
  };
208
217
  export default FloatingCopilot;
package/dist/index.esm.js CHANGED
@@ -28,7 +28,7 @@ const FloatingCopilot = ({ config = {} }) => {
28
28
  const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
29
29
  const [messages, setMessages] = useState([]);
30
30
  const [inputValue, setInputValue] = useState('');
31
- const [isMinimized, setIsMinimized] = useState(finalConfig.minimized || false);
31
+ const [isOpen, setIsOpen] = useState(!finalConfig.minimized);
32
32
  const [isMaximized, setIsMaximized] = useState(finalConfig.maximized || false);
33
33
  const [position, setPosition] = useState({
34
34
  x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : 20,
@@ -144,11 +144,13 @@ const FloatingCopilot = ({ config = {} }) => {
144
144
  setMessages((prev) => [...prev, botMessage]);
145
145
  }, 500);
146
146
  };
147
- // Handle minimize
148
- const handleMinimize = () => {
147
+ // Handle toggle open/close
148
+ const handleToggleOpen = () => {
149
149
  var _a;
150
- setIsMinimized(!isMinimized);
151
- (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
150
+ setIsOpen(!isOpen);
151
+ if (!isOpen) {
152
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
153
+ }
152
154
  };
153
155
  // Handle maximize
154
156
  const handleMaximize = () => {
@@ -159,6 +161,7 @@ const FloatingCopilot = ({ config = {} }) => {
159
161
  // Handle close
160
162
  const handleClose = () => {
161
163
  var _a;
164
+ setIsOpen(false);
162
165
  (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
163
166
  };
164
167
  const getPositionStyle = () => {
@@ -201,31 +204,37 @@ const FloatingCopilot = ({ config = {} }) => {
201
204
  '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
202
205
  });
203
206
  };
204
- return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''} ${isMinimized ? 'minimized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
205
- finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable ? 'grab' : 'default' } },
207
+ // Closed state - show only chat icon
208
+ if (!isOpen) {
209
+ return (React.createElement("div", { style: Object.assign(Object.assign({}, getPositionStyle()), getThemeStyle()), className: "copilot-wrapper" },
210
+ React.createElement("button", { className: "copilot-chat-icon", onClick: handleToggleOpen, title: "Open chat", "aria-label": "Open chat" }, "\uD83D\uDCAC")));
211
+ }
212
+ // Open state - show full chat
213
+ return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
214
+ finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable && !isMaximized ? 'grab' : 'default' } },
206
215
  React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
207
216
  React.createElement("div", { className: "copilot-buttons" },
208
- finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleMinimize, title: "Minimize" }, isMinimized ? '▲' : '▼')),
209
- finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: "Maximize" }, isMaximized ? '' : '')),
210
- finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close" }, "\u2715"))))),
211
- !isMinimized && (React.createElement(React.Fragment, null,
212
- React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
213
- React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
214
- messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
215
- React.createElement("div", { className: "copilot-message-content" }, msg.text),
216
- React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
217
- hour: '2-digit',
218
- minute: '2-digit',
219
- }))))),
220
- React.createElement("div", { ref: messagesEndRef })))),
221
- React.createElement("div", { className: "copilot-input-area" },
222
- React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
223
- if (e.key === 'Enter') {
224
- handleSendMessage();
225
- }
226
- } }),
227
- React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage }, "Send")),
228
- finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))))));
217
+ finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleToggleOpen, title: "Minimize", "aria-label": "Minimize" }, "\u2212")),
218
+ finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: isMaximized ? 'Restore' : 'Maximize', "aria-label": isMaximized ? 'Restore' : 'Maximize' }, isMaximized ? '' : '')),
219
+ finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close", "aria-label": "Close" }, "\u2715"))))),
220
+ React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
221
+ React.createElement("div", { className: "copilot-empty-icon" }, "\uD83D\uDCAC"),
222
+ React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
223
+ messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
224
+ React.createElement("div", { className: "copilot-message-content" }, msg.text),
225
+ React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
226
+ hour: '2-digit',
227
+ minute: '2-digit',
228
+ }))))),
229
+ React.createElement("div", { ref: messagesEndRef })))),
230
+ React.createElement("div", { className: "copilot-input-area" },
231
+ React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
232
+ if (e.key === 'Enter') {
233
+ handleSendMessage();
234
+ }
235
+ } }),
236
+ React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage, "aria-label": "Send message" }, "\u23CE")),
237
+ finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))));
229
238
  };
230
239
 
231
240
  export { FloatingCopilot, FloatingCopilot as default, defaultConfig };
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ const FloatingCopilot = ({ config = {} }) => {
32
32
  const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
33
33
  const [messages, setMessages] = React.useState([]);
34
34
  const [inputValue, setInputValue] = React.useState('');
35
- const [isMinimized, setIsMinimized] = React.useState(finalConfig.minimized || false);
35
+ const [isOpen, setIsOpen] = React.useState(!finalConfig.minimized);
36
36
  const [isMaximized, setIsMaximized] = React.useState(finalConfig.maximized || false);
37
37
  const [position, setPosition] = React.useState({
38
38
  x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : 20,
@@ -148,11 +148,13 @@ const FloatingCopilot = ({ config = {} }) => {
148
148
  setMessages((prev) => [...prev, botMessage]);
149
149
  }, 500);
150
150
  };
151
- // Handle minimize
152
- const handleMinimize = () => {
151
+ // Handle toggle open/close
152
+ const handleToggleOpen = () => {
153
153
  var _a;
154
- setIsMinimized(!isMinimized);
155
- (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
154
+ setIsOpen(!isOpen);
155
+ if (!isOpen) {
156
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
157
+ }
156
158
  };
157
159
  // Handle maximize
158
160
  const handleMaximize = () => {
@@ -163,6 +165,7 @@ const FloatingCopilot = ({ config = {} }) => {
163
165
  // Handle close
164
166
  const handleClose = () => {
165
167
  var _a;
168
+ setIsOpen(false);
166
169
  (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
167
170
  };
168
171
  const getPositionStyle = () => {
@@ -205,31 +208,37 @@ const FloatingCopilot = ({ config = {} }) => {
205
208
  '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
206
209
  });
207
210
  };
208
- return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''} ${isMinimized ? 'minimized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
209
- finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable ? 'grab' : 'default' } },
211
+ // Closed state - show only chat icon
212
+ if (!isOpen) {
213
+ return (React.createElement("div", { style: Object.assign(Object.assign({}, getPositionStyle()), getThemeStyle()), className: "copilot-wrapper" },
214
+ React.createElement("button", { className: "copilot-chat-icon", onClick: handleToggleOpen, title: "Open chat", "aria-label": "Open chat" }, "\uD83D\uDCAC")));
215
+ }
216
+ // Open state - show full chat
217
+ return (React.createElement("div", { ref: containerRef, className: `floating-copilot ${isMaximized ? 'maximized' : ''}`, style: Object.assign(Object.assign(Object.assign({}, getPositionStyle()), { width: isMaximized ? '100%' : size.width, height: isMaximized ? '100%' : size.height }), getThemeStyle()) },
218
+ finalConfig.showHeader && (React.createElement("div", { className: "copilot-header", onMouseDown: handleMouseDownDrag, style: { cursor: finalConfig.draggable && !isMaximized ? 'grab' : 'default' } },
210
219
  React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
211
220
  React.createElement("div", { className: "copilot-buttons" },
212
- finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleMinimize, title: "Minimize" }, isMinimized ? '▲' : '▼')),
213
- finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: "Maximize" }, isMaximized ? '' : '')),
214
- finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close" }, "\u2715"))))),
215
- !isMinimized && (React.createElement(React.Fragment, null,
216
- React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
217
- React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
218
- messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
219
- React.createElement("div", { className: "copilot-message-content" }, msg.text),
220
- React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
221
- hour: '2-digit',
222
- minute: '2-digit',
223
- }))))),
224
- React.createElement("div", { ref: messagesEndRef })))),
225
- React.createElement("div", { className: "copilot-input-area" },
226
- React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
227
- if (e.key === 'Enter') {
228
- handleSendMessage();
229
- }
230
- } }),
231
- React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage }, "Send")),
232
- finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))))));
221
+ finalConfig.showMinimizeBtn && (React.createElement("button", { className: "copilot-btn copilot-minimize-btn", onClick: handleToggleOpen, title: "Minimize", "aria-label": "Minimize" }, "\u2212")),
222
+ finalConfig.showMaximizeBtn && (React.createElement("button", { className: "copilot-btn copilot-maximize-btn", onClick: handleMaximize, title: isMaximized ? 'Restore' : 'Maximize', "aria-label": isMaximized ? 'Restore' : 'Maximize' }, isMaximized ? '' : '')),
223
+ finalConfig.showCloseBtn && (React.createElement("button", { className: "copilot-btn copilot-close-btn", onClick: handleClose, title: "Close", "aria-label": "Close" }, "\u2715"))))),
224
+ React.createElement("div", { className: "copilot-messages" }, messages.length === 0 ? (React.createElement("div", { className: "copilot-empty-state" },
225
+ React.createElement("div", { className: "copilot-empty-icon" }, "\uD83D\uDCAC"),
226
+ React.createElement("p", null, "Start a conversation..."))) : (React.createElement(React.Fragment, null,
227
+ messages.map((msg) => (React.createElement("div", { key: msg.id, className: `copilot-message copilot-message-${msg.sender}` },
228
+ React.createElement("div", { className: "copilot-message-content" }, msg.text),
229
+ React.createElement("span", { className: "copilot-message-time" }, msg.timestamp.toLocaleTimeString([], {
230
+ hour: '2-digit',
231
+ minute: '2-digit',
232
+ }))))),
233
+ React.createElement("div", { ref: messagesEndRef })))),
234
+ React.createElement("div", { className: "copilot-input-area" },
235
+ React.createElement("input", { type: "text", className: "copilot-input", placeholder: finalConfig.placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: (e) => {
236
+ if (e.key === 'Enter') {
237
+ handleSendMessage();
238
+ }
239
+ } }),
240
+ React.createElement("button", { className: "copilot-send-btn", onClick: handleSendMessage, "aria-label": "Send message" }, "\u23CE")),
241
+ finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))));
233
242
  };
234
243
 
235
244
  exports.FloatingCopilot = FloatingCopilot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floating-copilot-widget",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A highly configurable floating chat widget plugin for React websites. Draggable, resizable, themeable, and production-ready.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",