floating-copilot-widget 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Floating Copilot Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # Floating Copilot Widget
2
+
3
+ A lightweight, highly configurable floating chat widget plugin for React websites. Drop it into any React application and get an instantly customizable chat interface that can be dragged, resized, minimized, and maximized.
4
+
5
+ ## Features
6
+
7
+ ✨ **Easy Integration** - Simply import and use the component
8
+ 🎨 **Fully Customizable** - Configure colors, position, dimensions, and more
9
+ 🖱️ **Draggable & Resizable** - Users can move and resize the widget
10
+ 📱 **Responsive** - Adapts to mobile screens automatically
11
+ ♿ **Accessible** - Keyboard shortcuts and semantic HTML
12
+ 🎯 **Feature Rich** - Minimize, maximize, close buttons with callbacks
13
+ 💬 **Chat Interface** - Built-in message display with auto-scroll
14
+ ⚡ **Performance** - Lightweight with zero external dependencies
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install floating-copilot-widget
20
+ # or
21
+ yarn add floating-copilot-widget
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```jsx
27
+ import React from 'react';
28
+ import FloatingCopilot from 'floating-copilot-widget';
29
+ import 'floating-copilot-widget/dist/FloatingCopilot.css';
30
+
31
+ function App() {
32
+ return (
33
+ <div>
34
+ <FloatingCopilot
35
+ config={{
36
+ title: 'Chat Assistant',
37
+ position: 'bottom-right',
38
+ onMessage: (message) => console.log('User said:', message),
39
+ }}
40
+ />
41
+ </div>
42
+ );
43
+ }
44
+
45
+ export default App;
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ Pass a `config` object to customize the widget:
51
+
52
+ ```jsx
53
+ <FloatingCopilot
54
+ config={{
55
+ // Positioning
56
+ position: 'bottom-right', // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
57
+
58
+ // Dimensions
59
+ width: 350,
60
+ height: 500,
61
+
62
+ // Features
63
+ draggable: true,
64
+ resizable: true,
65
+
66
+ // Appearance
67
+ title: 'Chat Assistant',
68
+ placeholder: 'Type your message...',
69
+ theme: {
70
+ primaryColor: '#6366f1',
71
+ backgroundColor: '#ffffff',
72
+ textColor: '#1f2937',
73
+ borderColor: '#e5e7eb',
74
+ },
75
+
76
+ // State
77
+ minimized: false,
78
+ maximized: false,
79
+
80
+ // Controls
81
+ showHeader: true,
82
+ showMinimizeBtn: true,
83
+ showMaximizeBtn: true,
84
+ showCloseBtn: true,
85
+
86
+ // Layering
87
+ zIndex: 9999,
88
+
89
+ // Callbacks
90
+ onMessage: (message) => handleMessage(message),
91
+ onClose: () => handleClose(),
92
+ onMinimize: () => handleMinimize(),
93
+ onMaximize: () => handleMaximize(),
94
+ }}
95
+ />
96
+ ```
97
+
98
+ ## Configuration Options
99
+
100
+ ### Position
101
+ - `bottom-right` (default)
102
+ - `bottom-left`
103
+ - `top-right`
104
+ - `top-left`
105
+
106
+ ### Theme Colors
107
+ Customize the appearance with your brand colors:
108
+ ```jsx
109
+ theme: {
110
+ primaryColor: '#6366f1', // Button, user message background
111
+ backgroundColor: '#ffffff', // Widget background
112
+ textColor: '#1f2937', // Text color
113
+ borderColor: '#e5e7eb', // Border color
114
+ }
115
+ ```
116
+
117
+ ### Callbacks
118
+
119
+ ```jsx
120
+ // Called when user sends a message
121
+ onMessage: (message: string) => void
122
+
123
+ // Called when close button is clicked
124
+ onClose: () => void
125
+
126
+ // Called when minimize button is clicked
127
+ onMinimize: () => void
128
+
129
+ // Called when maximize button is clicked
130
+ onMaximize: () => void
131
+ ```
132
+
133
+ ## Advanced Usage
134
+
135
+ ### Custom Message Handler
136
+
137
+ ```jsx
138
+ <FloatingCopilot
139
+ config={{
140
+ onMessage: async (message) => {
141
+ // Send to your API
142
+ const response = await fetch('/api/chat', {
143
+ method: 'POST',
144
+ body: JSON.stringify({ message }),
145
+ });
146
+ // Handle response...
147
+ },
148
+ }}
149
+ />
150
+ ```
151
+
152
+ ### Conditional Rendering
153
+
154
+ ```jsx
155
+ const [showChat, setShowChat] = useState(true);
156
+
157
+ return showChat ? (
158
+ <FloatingCopilot
159
+ config={{
160
+ onClose: () => setShowChat(false),
161
+ }}
162
+ />
163
+ ) : null;
164
+ ```
165
+
166
+ ### Multiple Instances
167
+
168
+ ```jsx
169
+ <FloatingCopilot
170
+ config={{
171
+ position: 'bottom-right',
172
+ title: 'Chat',
173
+ zIndex: 9999,
174
+ }}
175
+ />
176
+
177
+ <FloatingCopilot
178
+ config={{
179
+ position: 'bottom-left',
180
+ title: 'Support',
181
+ zIndex: 9998,
182
+ }}
183
+ />
184
+ ```
185
+
186
+ ## Browser Support
187
+
188
+ - Chrome (latest)
189
+ - Firefox (latest)
190
+ - Safari (latest)
191
+ - Edge (latest)
192
+
193
+ ## Styling
194
+
195
+ The widget uses CSS variables for theming. You can override them globally:
196
+
197
+ ```css
198
+ :root {
199
+ --primary-color: #6366f1;
200
+ --bg-color: #ffffff;
201
+ --text-color: #1f2937;
202
+ --border-color: #e5e7eb;
203
+ }
204
+ ```
205
+
206
+ ## TypeScript Support
207
+
208
+ Full TypeScript support with exported types:
209
+
210
+ ```tsx
211
+ import { FloatingCopilot, FloatingCopilotConfig } from 'floating-copilot-widget';
212
+
213
+ const config: FloatingCopilotConfig = {
214
+ position: 'bottom-right',
215
+ // ... type-safe configuration
216
+ };
217
+
218
+ <FloatingCopilot config={config} />
219
+ ```
220
+
221
+ ## License
222
+
223
+ MIT
224
+
225
+ ## Contributing
226
+
227
+ Contributions are welcome! Please feel free to submit a Pull Request.
228
+
229
+ ## Support
230
+
231
+ For issues or questions, please open an issue on the GitHub repository.
@@ -0,0 +1,265 @@
1
+ /* Floating Copilot Widget Styles */
2
+
3
+ .floating-copilot {
4
+ display: flex;
5
+ flex-direction: column;
6
+ border-radius: 8px;
7
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
9
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
10
+ sans-serif;
11
+ background-color: var(--bg-color, #ffffff);
12
+ color: var(--text-color, #1f2937);
13
+ border: 1px solid var(--border-color, #e5e7eb);
14
+ overflow: hidden;
15
+ transition: all 0.3s ease;
16
+ }
17
+
18
+ .floating-copilot.maximized {
19
+ border-radius: 0;
20
+ }
21
+
22
+ .floating-copilot.minimized {
23
+ height: auto !important;
24
+ width: auto !important;
25
+ }
26
+
27
+ /* Header */
28
+ .copilot-header {
29
+ display: flex;
30
+ justify-content: space-between;
31
+ align-items: center;
32
+ padding: 12px 16px;
33
+ background: linear-gradient(135deg, var(--primary-color, #6366f1) 0%, #4f46e5 100%);
34
+ color: white;
35
+ border-bottom: 1px solid var(--border-color, #e5e7eb);
36
+ user-select: none;
37
+ cursor: grab;
38
+ transition: all 0.2s ease;
39
+ }
40
+
41
+ .copilot-header:active {
42
+ cursor: grabbing;
43
+ }
44
+
45
+ .copilot-title {
46
+ margin: 0;
47
+ font-size: 16px;
48
+ font-weight: 600;
49
+ flex: 1;
50
+ }
51
+
52
+ .copilot-buttons {
53
+ display: flex;
54
+ gap: 8px;
55
+ }
56
+
57
+ .copilot-btn {
58
+ background: rgba(255, 255, 255, 0.2);
59
+ border: none;
60
+ color: white;
61
+ width: 28px;
62
+ height: 28px;
63
+ border-radius: 4px;
64
+ cursor: pointer;
65
+ font-size: 12px;
66
+ display: flex;
67
+ align-items: center;
68
+ justify-content: center;
69
+ transition: all 0.2s ease;
70
+ }
71
+
72
+ .copilot-btn:hover {
73
+ background: rgba(255, 255, 255, 0.3);
74
+ transform: scale(1.05);
75
+ }
76
+
77
+ .copilot-btn:active {
78
+ transform: scale(0.95);
79
+ }
80
+
81
+ /* Messages Container */
82
+ .copilot-messages {
83
+ flex: 1;
84
+ overflow-y: auto;
85
+ padding: 16px;
86
+ display: flex;
87
+ flex-direction: column;
88
+ gap: 12px;
89
+ background: var(--bg-color, #ffffff);
90
+ }
91
+
92
+ .copilot-empty-state {
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: center;
96
+ height: 100%;
97
+ color: #9ca3af;
98
+ text-align: center;
99
+ font-size: 14px;
100
+ }
101
+
102
+ /* Message Styles */
103
+ .copilot-message {
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: 4px;
107
+ animation: slideIn 0.3s ease;
108
+ }
109
+
110
+ @keyframes slideIn {
111
+ from {
112
+ opacity: 0;
113
+ transform: translateY(10px);
114
+ }
115
+ to {
116
+ opacity: 1;
117
+ transform: translateY(0);
118
+ }
119
+ }
120
+
121
+ .copilot-message-user {
122
+ align-items: flex-end;
123
+ }
124
+
125
+ .copilot-message-bot {
126
+ align-items: flex-start;
127
+ }
128
+
129
+ .copilot-message-content {
130
+ padding: 10px 12px;
131
+ border-radius: 8px;
132
+ max-width: 85%;
133
+ word-wrap: break-word;
134
+ line-height: 1.4;
135
+ font-size: 14px;
136
+ }
137
+
138
+ .copilot-message-user .copilot-message-content {
139
+ background: var(--primary-color, #6366f1);
140
+ color: white;
141
+ border-radius: 16px 4px 16px 16px;
142
+ }
143
+
144
+ .copilot-message-bot .copilot-message-content {
145
+ background: #f3f4f6;
146
+ color: var(--text-color, #1f2937);
147
+ border-radius: 4px 16px 16px 16px;
148
+ }
149
+
150
+ .copilot-message-time {
151
+ font-size: 11px;
152
+ color: #9ca3af;
153
+ padding: 0 4px;
154
+ }
155
+
156
+ /* Input Area */
157
+ .copilot-input-area {
158
+ display: flex;
159
+ gap: 8px;
160
+ padding: 12px;
161
+ border-top: 1px solid var(--border-color, #e5e7eb);
162
+ background: var(--bg-color, #ffffff);
163
+ }
164
+
165
+ .copilot-input {
166
+ flex: 1;
167
+ padding: 10px 12px;
168
+ border: 1px solid var(--border-color, #e5e7eb);
169
+ border-radius: 6px;
170
+ font-size: 14px;
171
+ font-family: inherit;
172
+ color: var(--text-color, #1f2937);
173
+ background: #f9fafb;
174
+ transition: all 0.2s ease;
175
+ }
176
+
177
+ .copilot-input:focus {
178
+ outline: none;
179
+ border-color: var(--primary-color, #6366f1);
180
+ background: white;
181
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
182
+ }
183
+
184
+ .copilot-input::placeholder {
185
+ color: #d1d5db;
186
+ }
187
+
188
+ .copilot-send-btn {
189
+ padding: 10px 16px;
190
+ background: var(--primary-color, #6366f1);
191
+ color: white;
192
+ border: none;
193
+ border-radius: 6px;
194
+ cursor: pointer;
195
+ font-weight: 500;
196
+ font-size: 14px;
197
+ transition: all 0.2s ease;
198
+ }
199
+
200
+ .copilot-send-btn:hover {
201
+ background: #4f46e5;
202
+ transform: translateY(-1px);
203
+ box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);
204
+ }
205
+
206
+ .copilot-send-btn:active {
207
+ transform: translateY(0);
208
+ }
209
+
210
+ /* Resize Handle */
211
+ .copilot-resize-handle {
212
+ position: absolute;
213
+ bottom: 0;
214
+ right: 0;
215
+ width: 20px;
216
+ height: 20px;
217
+ cursor: nwse-resize;
218
+ background: linear-gradient(135deg, transparent 50%, var(--primary-color, #6366f1) 50%);
219
+ border-radius: 0 0 8px 0;
220
+ }
221
+
222
+ .copilot-resize-handle:hover {
223
+ background: linear-gradient(135deg, transparent 50%, #4f46e5 50%);
224
+ }
225
+
226
+ /* Scrollbar Styling */
227
+ .copilot-messages::-webkit-scrollbar {
228
+ width: 6px;
229
+ }
230
+
231
+ .copilot-messages::-webkit-scrollbar-track {
232
+ background: #f3f4f6;
233
+ border-radius: 10px;
234
+ }
235
+
236
+ .copilot-messages::-webkit-scrollbar-thumb {
237
+ background: #d1d5db;
238
+ border-radius: 10px;
239
+ }
240
+
241
+ .copilot-messages::-webkit-scrollbar-thumb:hover {
242
+ background: #9ca3af;
243
+ }
244
+
245
+ /* Responsive Design */
246
+ @media (max-width: 480px) {
247
+ .floating-copilot {
248
+ width: 100vw !important;
249
+ height: 100vh !important;
250
+ border-radius: 0;
251
+ position: fixed !important;
252
+ top: 0 !important;
253
+ left: 0 !important;
254
+ right: 0 !important;
255
+ bottom: 0 !important;
256
+ }
257
+
258
+ .copilot-message-content {
259
+ max-width: 90%;
260
+ }
261
+
262
+ .copilot-resize-handle {
263
+ display: none;
264
+ }
265
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { FloatingCopilotConfig } from './types';
3
+ import './FloatingCopilot.css';
4
+ interface FloatingCopilotProps {
5
+ config?: Partial<FloatingCopilotConfig>;
6
+ }
7
+ export declare const FloatingCopilot: React.FC<FloatingCopilotProps>;
8
+ export default FloatingCopilot;
@@ -0,0 +1,208 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { defaultConfig } from './types';
3
+ import './FloatingCopilot.css';
4
+ export const FloatingCopilot = ({ config = {} }) => {
5
+ var _a, _b;
6
+ const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
7
+ const [messages, setMessages] = useState([]);
8
+ const [inputValue, setInputValue] = useState('');
9
+ const [isMinimized, setIsMinimized] = useState(finalConfig.minimized || false);
10
+ const [isMaximized, setIsMaximized] = useState(finalConfig.maximized || false);
11
+ const [position, setPosition] = useState({
12
+ x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : -999,
13
+ y: ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) ? 20 : -999,
14
+ });
15
+ const [size, setSize] = useState({
16
+ width: finalConfig.width || 350,
17
+ height: finalConfig.height || 500,
18
+ });
19
+ const [isDragging, setIsDragging] = useState(false);
20
+ const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
21
+ const [isResizing, setIsResizing] = useState(false);
22
+ const containerRef = useRef(null);
23
+ const messagesEndRef = useRef(null);
24
+ // Auto-scroll to bottom when new messages arrive
25
+ useEffect(() => {
26
+ var _a;
27
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
28
+ }, [messages]);
29
+ // Handle mouse down for dragging
30
+ const handleMouseDownDrag = (e) => {
31
+ if (!finalConfig.draggable || isMaximized)
32
+ return;
33
+ const container = containerRef.current;
34
+ if (!container)
35
+ return;
36
+ const rect = container.getBoundingClientRect();
37
+ setDragOffset({
38
+ x: e.clientX - rect.left,
39
+ y: e.clientY - rect.top,
40
+ });
41
+ setIsDragging(true);
42
+ };
43
+ // Handle mouse move for dragging
44
+ useEffect(() => {
45
+ const handleMouseMove = (e) => {
46
+ if (!isDragging || !containerRef.current)
47
+ return;
48
+ const newX = e.clientX - dragOffset.x;
49
+ const newY = e.clientY - dragOffset.y;
50
+ setPosition({
51
+ x: Math.max(0, Math.min(newX, window.innerWidth - size.width)),
52
+ y: Math.max(0, Math.min(newY, window.innerHeight - size.height)),
53
+ });
54
+ };
55
+ const handleMouseUp = () => {
56
+ setIsDragging(false);
57
+ };
58
+ if (isDragging) {
59
+ document.addEventListener('mousemove', handleMouseMove);
60
+ document.addEventListener('mouseup', handleMouseUp);
61
+ }
62
+ return () => {
63
+ document.removeEventListener('mousemove', handleMouseMove);
64
+ document.removeEventListener('mouseup', handleMouseUp);
65
+ };
66
+ }, [isDragging, dragOffset, size]);
67
+ // Handle resize
68
+ const handleMouseDownResize = (e) => {
69
+ if (!finalConfig.resizable || isMaximized)
70
+ return;
71
+ e.preventDefault();
72
+ setIsResizing(true);
73
+ };
74
+ useEffect(() => {
75
+ const handleMouseMove = (e) => {
76
+ if (!isResizing || !containerRef.current)
77
+ return;
78
+ const container = containerRef.current;
79
+ const rect = container.getBoundingClientRect();
80
+ const newWidth = Math.max(250, e.clientX - rect.left);
81
+ const newHeight = Math.max(300, e.clientY - rect.top);
82
+ setSize({
83
+ width: newWidth,
84
+ height: newHeight,
85
+ });
86
+ };
87
+ const handleMouseUp = () => {
88
+ setIsResizing(false);
89
+ };
90
+ if (isResizing) {
91
+ document.addEventListener('mousemove', handleMouseMove);
92
+ document.addEventListener('mouseup', handleMouseUp);
93
+ }
94
+ return () => {
95
+ document.removeEventListener('mousemove', handleMouseMove);
96
+ document.removeEventListener('mouseup', handleMouseUp);
97
+ };
98
+ }, [isResizing]);
99
+ // Handle message send
100
+ const handleSendMessage = () => {
101
+ var _a;
102
+ if (!inputValue.trim())
103
+ return;
104
+ const userMessage = {
105
+ id: Date.now().toString(),
106
+ text: inputValue,
107
+ sender: 'user',
108
+ timestamp: new Date(),
109
+ };
110
+ setMessages((prev) => [...prev, userMessage]);
111
+ setInputValue('');
112
+ // Call the onMessage callback
113
+ (_a = finalConfig.onMessage) === null || _a === void 0 ? void 0 : _a.call(finalConfig, inputValue);
114
+ // Simulate bot response (replace with actual API call)
115
+ setTimeout(() => {
116
+ const botMessage = {
117
+ id: (Date.now() + 1).toString(),
118
+ text: 'Thanks for your message! This is a demo response.',
119
+ sender: 'bot',
120
+ timestamp: new Date(),
121
+ };
122
+ setMessages((prev) => [...prev, botMessage]);
123
+ }, 500);
124
+ };
125
+ // Handle minimize
126
+ const handleMinimize = () => {
127
+ var _a;
128
+ setIsMinimized(!isMinimized);
129
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
130
+ };
131
+ // Handle maximize
132
+ const handleMaximize = () => {
133
+ var _a;
134
+ setIsMaximized(!isMaximized);
135
+ (_a = finalConfig.onMaximize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
136
+ };
137
+ // Handle close
138
+ const handleClose = () => {
139
+ var _a;
140
+ (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
141
+ };
142
+ const getPositionStyle = () => {
143
+ var _a, _b;
144
+ if (isMaximized) {
145
+ return {
146
+ position: 'fixed',
147
+ top: 0,
148
+ left: 0,
149
+ right: 0,
150
+ bottom: 0,
151
+ width: '100%',
152
+ height: '100%',
153
+ };
154
+ }
155
+ const baseStyle = {
156
+ position: 'fixed',
157
+ zIndex: finalConfig.zIndex,
158
+ };
159
+ if ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) {
160
+ baseStyle.left = position.x;
161
+ }
162
+ else {
163
+ baseStyle.right = position.x;
164
+ }
165
+ if ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) {
166
+ baseStyle.top = position.y;
167
+ }
168
+ else {
169
+ baseStyle.bottom = position.y;
170
+ }
171
+ return baseStyle;
172
+ };
173
+ const getThemeStyle = () => {
174
+ var _a, _b, _c, _d;
175
+ return ({
176
+ '--primary-color': (_a = finalConfig.theme) === null || _a === void 0 ? void 0 : _a.primaryColor,
177
+ '--bg-color': (_b = finalConfig.theme) === null || _b === void 0 ? void 0 : _b.backgroundColor,
178
+ '--text-color': (_c = finalConfig.theme) === null || _c === void 0 ? void 0 : _c.textColor,
179
+ '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
180
+ });
181
+ };
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' } },
184
+ React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
185
+ 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" }))))));
207
+ };
208
+ export default FloatingCopilot;
@@ -0,0 +1,4 @@
1
+ import './FloatingCopilot.css';
2
+ export { FloatingCopilot, default } from './FloatingCopilot';
3
+ export type { FloatingCopilotConfig } from './types';
4
+ export { defaultConfig } from './types';
@@ -0,0 +1,231 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+
3
+ const defaultConfig = {
4
+ position: 'bottom-right',
5
+ width: 350,
6
+ height: 500,
7
+ draggable: true,
8
+ resizable: true,
9
+ minimized: false,
10
+ maximized: false,
11
+ zIndex: 9999,
12
+ showHeader: true,
13
+ showMinimizeBtn: true,
14
+ showMaximizeBtn: true,
15
+ showCloseBtn: true,
16
+ title: 'Chat Assistant',
17
+ placeholder: 'Type your message...',
18
+ theme: {
19
+ primaryColor: '#6366f1',
20
+ backgroundColor: '#ffffff',
21
+ textColor: '#1f2937',
22
+ borderColor: '#e5e7eb',
23
+ },
24
+ };
25
+
26
+ const FloatingCopilot = ({ config = {} }) => {
27
+ var _a, _b;
28
+ const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
29
+ const [messages, setMessages] = useState([]);
30
+ const [inputValue, setInputValue] = useState('');
31
+ const [isMinimized, setIsMinimized] = useState(finalConfig.minimized || false);
32
+ const [isMaximized, setIsMaximized] = useState(finalConfig.maximized || false);
33
+ const [position, setPosition] = useState({
34
+ x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : -999,
35
+ y: ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) ? 20 : -999,
36
+ });
37
+ const [size, setSize] = useState({
38
+ width: finalConfig.width || 350,
39
+ height: finalConfig.height || 500,
40
+ });
41
+ const [isDragging, setIsDragging] = useState(false);
42
+ const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
43
+ const [isResizing, setIsResizing] = useState(false);
44
+ const containerRef = useRef(null);
45
+ const messagesEndRef = useRef(null);
46
+ // Auto-scroll to bottom when new messages arrive
47
+ useEffect(() => {
48
+ var _a;
49
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
50
+ }, [messages]);
51
+ // Handle mouse down for dragging
52
+ const handleMouseDownDrag = (e) => {
53
+ if (!finalConfig.draggable || isMaximized)
54
+ return;
55
+ const container = containerRef.current;
56
+ if (!container)
57
+ return;
58
+ const rect = container.getBoundingClientRect();
59
+ setDragOffset({
60
+ x: e.clientX - rect.left,
61
+ y: e.clientY - rect.top,
62
+ });
63
+ setIsDragging(true);
64
+ };
65
+ // Handle mouse move for dragging
66
+ useEffect(() => {
67
+ const handleMouseMove = (e) => {
68
+ if (!isDragging || !containerRef.current)
69
+ return;
70
+ const newX = e.clientX - dragOffset.x;
71
+ const newY = e.clientY - dragOffset.y;
72
+ setPosition({
73
+ x: Math.max(0, Math.min(newX, window.innerWidth - size.width)),
74
+ y: Math.max(0, Math.min(newY, window.innerHeight - size.height)),
75
+ });
76
+ };
77
+ const handleMouseUp = () => {
78
+ setIsDragging(false);
79
+ };
80
+ if (isDragging) {
81
+ document.addEventListener('mousemove', handleMouseMove);
82
+ document.addEventListener('mouseup', handleMouseUp);
83
+ }
84
+ return () => {
85
+ document.removeEventListener('mousemove', handleMouseMove);
86
+ document.removeEventListener('mouseup', handleMouseUp);
87
+ };
88
+ }, [isDragging, dragOffset, size]);
89
+ // Handle resize
90
+ const handleMouseDownResize = (e) => {
91
+ if (!finalConfig.resizable || isMaximized)
92
+ return;
93
+ e.preventDefault();
94
+ setIsResizing(true);
95
+ };
96
+ useEffect(() => {
97
+ const handleMouseMove = (e) => {
98
+ if (!isResizing || !containerRef.current)
99
+ return;
100
+ const container = containerRef.current;
101
+ const rect = container.getBoundingClientRect();
102
+ const newWidth = Math.max(250, e.clientX - rect.left);
103
+ const newHeight = Math.max(300, e.clientY - rect.top);
104
+ setSize({
105
+ width: newWidth,
106
+ height: newHeight,
107
+ });
108
+ };
109
+ const handleMouseUp = () => {
110
+ setIsResizing(false);
111
+ };
112
+ if (isResizing) {
113
+ document.addEventListener('mousemove', handleMouseMove);
114
+ document.addEventListener('mouseup', handleMouseUp);
115
+ }
116
+ return () => {
117
+ document.removeEventListener('mousemove', handleMouseMove);
118
+ document.removeEventListener('mouseup', handleMouseUp);
119
+ };
120
+ }, [isResizing]);
121
+ // Handle message send
122
+ const handleSendMessage = () => {
123
+ var _a;
124
+ if (!inputValue.trim())
125
+ return;
126
+ const userMessage = {
127
+ id: Date.now().toString(),
128
+ text: inputValue,
129
+ sender: 'user',
130
+ timestamp: new Date(),
131
+ };
132
+ setMessages((prev) => [...prev, userMessage]);
133
+ setInputValue('');
134
+ // Call the onMessage callback
135
+ (_a = finalConfig.onMessage) === null || _a === void 0 ? void 0 : _a.call(finalConfig, inputValue);
136
+ // Simulate bot response (replace with actual API call)
137
+ setTimeout(() => {
138
+ const botMessage = {
139
+ id: (Date.now() + 1).toString(),
140
+ text: 'Thanks for your message! This is a demo response.',
141
+ sender: 'bot',
142
+ timestamp: new Date(),
143
+ };
144
+ setMessages((prev) => [...prev, botMessage]);
145
+ }, 500);
146
+ };
147
+ // Handle minimize
148
+ const handleMinimize = () => {
149
+ var _a;
150
+ setIsMinimized(!isMinimized);
151
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
152
+ };
153
+ // Handle maximize
154
+ const handleMaximize = () => {
155
+ var _a;
156
+ setIsMaximized(!isMaximized);
157
+ (_a = finalConfig.onMaximize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
158
+ };
159
+ // Handle close
160
+ const handleClose = () => {
161
+ var _a;
162
+ (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
163
+ };
164
+ const getPositionStyle = () => {
165
+ var _a, _b;
166
+ if (isMaximized) {
167
+ return {
168
+ position: 'fixed',
169
+ top: 0,
170
+ left: 0,
171
+ right: 0,
172
+ bottom: 0,
173
+ width: '100%',
174
+ height: '100%',
175
+ };
176
+ }
177
+ const baseStyle = {
178
+ position: 'fixed',
179
+ zIndex: finalConfig.zIndex,
180
+ };
181
+ if ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) {
182
+ baseStyle.left = position.x;
183
+ }
184
+ else {
185
+ baseStyle.right = position.x;
186
+ }
187
+ if ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) {
188
+ baseStyle.top = position.y;
189
+ }
190
+ else {
191
+ baseStyle.bottom = position.y;
192
+ }
193
+ return baseStyle;
194
+ };
195
+ const getThemeStyle = () => {
196
+ var _a, _b, _c, _d;
197
+ return ({
198
+ '--primary-color': (_a = finalConfig.theme) === null || _a === void 0 ? void 0 : _a.primaryColor,
199
+ '--bg-color': (_b = finalConfig.theme) === null || _b === void 0 ? void 0 : _b.backgroundColor,
200
+ '--text-color': (_c = finalConfig.theme) === null || _c === void 0 ? void 0 : _c.textColor,
201
+ '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
202
+ });
203
+ };
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' } },
206
+ React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
207
+ 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" }))))));
229
+ };
230
+
231
+ export { FloatingCopilot, FloatingCopilot as default, defaultConfig };
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+
7
+ const defaultConfig = {
8
+ position: 'bottom-right',
9
+ width: 350,
10
+ height: 500,
11
+ draggable: true,
12
+ resizable: true,
13
+ minimized: false,
14
+ maximized: false,
15
+ zIndex: 9999,
16
+ showHeader: true,
17
+ showMinimizeBtn: true,
18
+ showMaximizeBtn: true,
19
+ showCloseBtn: true,
20
+ title: 'Chat Assistant',
21
+ placeholder: 'Type your message...',
22
+ theme: {
23
+ primaryColor: '#6366f1',
24
+ backgroundColor: '#ffffff',
25
+ textColor: '#1f2937',
26
+ borderColor: '#e5e7eb',
27
+ },
28
+ };
29
+
30
+ const FloatingCopilot = ({ config = {} }) => {
31
+ var _a, _b;
32
+ const finalConfig = Object.assign(Object.assign({}, defaultConfig), config);
33
+ const [messages, setMessages] = React.useState([]);
34
+ const [inputValue, setInputValue] = React.useState('');
35
+ const [isMinimized, setIsMinimized] = React.useState(finalConfig.minimized || false);
36
+ const [isMaximized, setIsMaximized] = React.useState(finalConfig.maximized || false);
37
+ const [position, setPosition] = React.useState({
38
+ x: ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) ? 20 : -999,
39
+ y: ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) ? 20 : -999,
40
+ });
41
+ const [size, setSize] = React.useState({
42
+ width: finalConfig.width || 350,
43
+ height: finalConfig.height || 500,
44
+ });
45
+ const [isDragging, setIsDragging] = React.useState(false);
46
+ const [dragOffset, setDragOffset] = React.useState({ x: 0, y: 0 });
47
+ const [isResizing, setIsResizing] = React.useState(false);
48
+ const containerRef = React.useRef(null);
49
+ const messagesEndRef = React.useRef(null);
50
+ // Auto-scroll to bottom when new messages arrive
51
+ React.useEffect(() => {
52
+ var _a;
53
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
54
+ }, [messages]);
55
+ // Handle mouse down for dragging
56
+ const handleMouseDownDrag = (e) => {
57
+ if (!finalConfig.draggable || isMaximized)
58
+ return;
59
+ const container = containerRef.current;
60
+ if (!container)
61
+ return;
62
+ const rect = container.getBoundingClientRect();
63
+ setDragOffset({
64
+ x: e.clientX - rect.left,
65
+ y: e.clientY - rect.top,
66
+ });
67
+ setIsDragging(true);
68
+ };
69
+ // Handle mouse move for dragging
70
+ React.useEffect(() => {
71
+ const handleMouseMove = (e) => {
72
+ if (!isDragging || !containerRef.current)
73
+ return;
74
+ const newX = e.clientX - dragOffset.x;
75
+ const newY = e.clientY - dragOffset.y;
76
+ setPosition({
77
+ x: Math.max(0, Math.min(newX, window.innerWidth - size.width)),
78
+ y: Math.max(0, Math.min(newY, window.innerHeight - size.height)),
79
+ });
80
+ };
81
+ const handleMouseUp = () => {
82
+ setIsDragging(false);
83
+ };
84
+ if (isDragging) {
85
+ document.addEventListener('mousemove', handleMouseMove);
86
+ document.addEventListener('mouseup', handleMouseUp);
87
+ }
88
+ return () => {
89
+ document.removeEventListener('mousemove', handleMouseMove);
90
+ document.removeEventListener('mouseup', handleMouseUp);
91
+ };
92
+ }, [isDragging, dragOffset, size]);
93
+ // Handle resize
94
+ const handleMouseDownResize = (e) => {
95
+ if (!finalConfig.resizable || isMaximized)
96
+ return;
97
+ e.preventDefault();
98
+ setIsResizing(true);
99
+ };
100
+ React.useEffect(() => {
101
+ const handleMouseMove = (e) => {
102
+ if (!isResizing || !containerRef.current)
103
+ return;
104
+ const container = containerRef.current;
105
+ const rect = container.getBoundingClientRect();
106
+ const newWidth = Math.max(250, e.clientX - rect.left);
107
+ const newHeight = Math.max(300, e.clientY - rect.top);
108
+ setSize({
109
+ width: newWidth,
110
+ height: newHeight,
111
+ });
112
+ };
113
+ const handleMouseUp = () => {
114
+ setIsResizing(false);
115
+ };
116
+ if (isResizing) {
117
+ document.addEventListener('mousemove', handleMouseMove);
118
+ document.addEventListener('mouseup', handleMouseUp);
119
+ }
120
+ return () => {
121
+ document.removeEventListener('mousemove', handleMouseMove);
122
+ document.removeEventListener('mouseup', handleMouseUp);
123
+ };
124
+ }, [isResizing]);
125
+ // Handle message send
126
+ const handleSendMessage = () => {
127
+ var _a;
128
+ if (!inputValue.trim())
129
+ return;
130
+ const userMessage = {
131
+ id: Date.now().toString(),
132
+ text: inputValue,
133
+ sender: 'user',
134
+ timestamp: new Date(),
135
+ };
136
+ setMessages((prev) => [...prev, userMessage]);
137
+ setInputValue('');
138
+ // Call the onMessage callback
139
+ (_a = finalConfig.onMessage) === null || _a === void 0 ? void 0 : _a.call(finalConfig, inputValue);
140
+ // Simulate bot response (replace with actual API call)
141
+ setTimeout(() => {
142
+ const botMessage = {
143
+ id: (Date.now() + 1).toString(),
144
+ text: 'Thanks for your message! This is a demo response.',
145
+ sender: 'bot',
146
+ timestamp: new Date(),
147
+ };
148
+ setMessages((prev) => [...prev, botMessage]);
149
+ }, 500);
150
+ };
151
+ // Handle minimize
152
+ const handleMinimize = () => {
153
+ var _a;
154
+ setIsMinimized(!isMinimized);
155
+ (_a = finalConfig.onMinimize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
156
+ };
157
+ // Handle maximize
158
+ const handleMaximize = () => {
159
+ var _a;
160
+ setIsMaximized(!isMaximized);
161
+ (_a = finalConfig.onMaximize) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
162
+ };
163
+ // Handle close
164
+ const handleClose = () => {
165
+ var _a;
166
+ (_a = finalConfig.onClose) === null || _a === void 0 ? void 0 : _a.call(finalConfig);
167
+ };
168
+ const getPositionStyle = () => {
169
+ var _a, _b;
170
+ if (isMaximized) {
171
+ return {
172
+ position: 'fixed',
173
+ top: 0,
174
+ left: 0,
175
+ right: 0,
176
+ bottom: 0,
177
+ width: '100%',
178
+ height: '100%',
179
+ };
180
+ }
181
+ const baseStyle = {
182
+ position: 'fixed',
183
+ zIndex: finalConfig.zIndex,
184
+ };
185
+ if ((_a = finalConfig.position) === null || _a === void 0 ? void 0 : _a.includes('left')) {
186
+ baseStyle.left = position.x;
187
+ }
188
+ else {
189
+ baseStyle.right = position.x;
190
+ }
191
+ if ((_b = finalConfig.position) === null || _b === void 0 ? void 0 : _b.includes('top')) {
192
+ baseStyle.top = position.y;
193
+ }
194
+ else {
195
+ baseStyle.bottom = position.y;
196
+ }
197
+ return baseStyle;
198
+ };
199
+ const getThemeStyle = () => {
200
+ var _a, _b, _c, _d;
201
+ return ({
202
+ '--primary-color': (_a = finalConfig.theme) === null || _a === void 0 ? void 0 : _a.primaryColor,
203
+ '--bg-color': (_b = finalConfig.theme) === null || _b === void 0 ? void 0 : _b.backgroundColor,
204
+ '--text-color': (_c = finalConfig.theme) === null || _c === void 0 ? void 0 : _c.textColor,
205
+ '--border-color': (_d = finalConfig.theme) === null || _d === void 0 ? void 0 : _d.borderColor,
206
+ });
207
+ };
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' } },
210
+ React.createElement("h3", { className: "copilot-title" }, finalConfig.headerContent || finalConfig.title),
211
+ 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" }))))));
233
+ };
234
+
235
+ exports.FloatingCopilot = FloatingCopilot;
236
+ exports.default = FloatingCopilot;
237
+ exports.defaultConfig = defaultConfig;
@@ -0,0 +1,28 @@
1
+ export interface FloatingCopilotConfig {
2
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
3
+ width?: number;
4
+ height?: number;
5
+ draggable?: boolean;
6
+ resizable?: boolean;
7
+ theme?: {
8
+ primaryColor?: string;
9
+ backgroundColor?: string;
10
+ textColor?: string;
11
+ borderColor?: string;
12
+ };
13
+ title?: string;
14
+ placeholder?: string;
15
+ onMessage?: (message: string) => void;
16
+ onClose?: () => void;
17
+ onMinimize?: () => void;
18
+ onMaximize?: () => void;
19
+ minimized?: boolean;
20
+ maximized?: boolean;
21
+ zIndex?: number;
22
+ showHeader?: boolean;
23
+ showMinimizeBtn?: boolean;
24
+ showMaximizeBtn?: boolean;
25
+ showCloseBtn?: boolean;
26
+ headerContent?: string;
27
+ }
28
+ export declare const defaultConfig: FloatingCopilotConfig;
package/dist/types.js ADDED
@@ -0,0 +1,22 @@
1
+ export const defaultConfig = {
2
+ position: 'bottom-right',
3
+ width: 350,
4
+ height: 500,
5
+ draggable: true,
6
+ resizable: true,
7
+ minimized: false,
8
+ maximized: false,
9
+ zIndex: 9999,
10
+ showHeader: true,
11
+ showMinimizeBtn: true,
12
+ showMaximizeBtn: true,
13
+ showCloseBtn: true,
14
+ title: 'Chat Assistant',
15
+ placeholder: 'Type your message...',
16
+ theme: {
17
+ primaryColor: '#6366f1',
18
+ backgroundColor: '#ffffff',
19
+ textColor: '#1f2937',
20
+ borderColor: '#e5e7eb',
21
+ },
22
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "floating-copilot-widget",
3
+ "version": "1.0.0",
4
+ "description": "A highly configurable floating chat widget plugin for React websites. Draggable, resizable, themeable, and production-ready.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/yourusername/floating-copilot-widget.git"
16
+ },
17
+ "homepage": "https://github.com/yourusername/floating-copilot-widget",
18
+ "bugs": {
19
+ "url": "https://github.com/yourusername/floating-copilot-widget/issues"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc && rollup -c && node scripts/copy-css.js",
23
+ "dev": "tsc --watch",
24
+ "test": "jest",
25
+ "demo": "react-scripts start"
26
+ },
27
+ "keywords": [
28
+ "react",
29
+ "floating",
30
+ "chat",
31
+ "widget",
32
+ "plugin",
33
+ "modal",
34
+ "draggable",
35
+ "resizable",
36
+ "minimize",
37
+ "maximize",
38
+ "configurable"
39
+ ],
40
+ "author": "Your Name <your.email@example.com>",
41
+ "license": "MIT",
42
+ "engines": {
43
+ "node": ">=14.0.0",
44
+ "npm": ">=6.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
48
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "^18.0.0",
52
+ "@types/react-dom": "^18.0.0",
53
+ "react": "^18.2.0",
54
+ "react-dom": "^18.2.0",
55
+ "typescript": "^4.9.5",
56
+ "rollup": "^3.0.0",
57
+ "rollup-plugin-node-resolve": "^5.0.0",
58
+ "rollup-plugin-commonjs": "^10.0.0",
59
+ "rollup-plugin-typescript2": "^0.34.0",
60
+ "react-scripts": "5.0.1"
61
+ },
62
+ "dependencies": {}
63
+ }