ajaxter-chat 1.0.3 → 2.0.1

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.
Files changed (88) hide show
  1. package/README.md +96 -204
  2. package/dist/components/ChatScreen/index.d.ts +12 -0
  3. package/dist/components/ChatScreen/index.js +83 -0
  4. package/dist/components/ChatWidget.d.ts +0 -24
  5. package/dist/components/ChatWidget.js +129 -38
  6. package/dist/components/HomeScreen/index.d.ts +9 -0
  7. package/dist/components/HomeScreen/index.js +71 -0
  8. package/dist/components/MaintenanceView/index.d.ts +1 -1
  9. package/dist/components/MaintenanceView/index.js +15 -52
  10. package/dist/components/RecentChatsScreen/index.d.ts +16 -0
  11. package/dist/components/RecentChatsScreen/index.js +38 -0
  12. package/dist/components/Tabs/BottomTabs.d.ts +10 -0
  13. package/dist/components/Tabs/BottomTabs.js +29 -0
  14. package/dist/components/TicketScreen/index.d.ts +9 -0
  15. package/dist/components/TicketScreen/index.js +71 -0
  16. package/dist/components/UserListScreen/index.d.ts +13 -0
  17. package/dist/components/UserListScreen/index.js +64 -0
  18. package/dist/config/index.d.ts +0 -13
  19. package/dist/config/index.js +20 -95
  20. package/dist/hooks/useChat.d.ts +3 -7
  21. package/dist/hooks/useChat.js +8 -30
  22. package/dist/hooks/useUsers.d.ts +3 -10
  23. package/dist/hooks/useUsers.js +5 -11
  24. package/dist/index.d.ts +8 -7
  25. package/dist/index.js +7 -12
  26. package/dist/services/userService.d.ts +0 -5
  27. package/dist/services/userService.js +6 -15
  28. package/dist/src/components/ChatScreen/index.d.ts +12 -0
  29. package/dist/src/components/ChatScreen/index.js +83 -0
  30. package/dist/src/components/ChatWidget.d.ts +4 -0
  31. package/dist/src/components/ChatWidget.js +141 -0
  32. package/dist/src/components/HomeScreen/index.d.ts +9 -0
  33. package/dist/src/components/HomeScreen/index.js +71 -0
  34. package/dist/src/components/MaintenanceView/index.d.ts +7 -0
  35. package/dist/src/components/MaintenanceView/index.js +16 -0
  36. package/dist/src/components/RecentChatsScreen/index.d.ts +16 -0
  37. package/dist/src/components/RecentChatsScreen/index.js +38 -0
  38. package/dist/src/components/Tabs/BottomTabs.d.ts +10 -0
  39. package/dist/src/components/Tabs/BottomTabs.js +29 -0
  40. package/dist/src/components/TicketScreen/index.d.ts +9 -0
  41. package/dist/src/components/TicketScreen/index.js +71 -0
  42. package/dist/src/components/UserListScreen/index.d.ts +13 -0
  43. package/dist/src/components/UserListScreen/index.js +64 -0
  44. package/dist/src/config/index.d.ts +3 -0
  45. package/dist/src/config/index.js +38 -0
  46. package/dist/src/hooks/useChat.d.ts +8 -0
  47. package/dist/src/hooks/useChat.js +26 -0
  48. package/dist/src/hooks/useUsers.d.ts +7 -0
  49. package/dist/src/hooks/useUsers.js +26 -0
  50. package/dist/src/index.d.ts +14 -0
  51. package/dist/src/index.js +13 -0
  52. package/dist/src/services/userService.d.ts +2 -0
  53. package/dist/src/services/userService.js +9 -0
  54. package/dist/src/types/index.d.ts +59 -0
  55. package/dist/src/types/index.js +1 -0
  56. package/dist/src/utils/theme.d.ts +3 -0
  57. package/dist/src/utils/theme.js +13 -0
  58. package/dist/types/index.d.ts +23 -36
  59. package/dist/utils/theme.d.ts +0 -1
  60. package/dist/utils/theme.js +3 -18
  61. package/package.json +10 -20
  62. package/src/components/ChatScreen/index.tsx +205 -0
  63. package/src/components/ChatWidget.tsx +327 -0
  64. package/src/components/HomeScreen/index.tsx +130 -0
  65. package/src/components/MaintenanceView/index.tsx +41 -0
  66. package/src/components/RecentChatsScreen/index.tsx +108 -0
  67. package/src/components/Tabs/BottomTabs.tsx +82 -0
  68. package/src/components/TicketScreen/index.tsx +170 -0
  69. package/src/components/UserListScreen/index.tsx +181 -0
  70. package/src/config/index.ts +46 -0
  71. package/src/hooks/useChat.ts +31 -0
  72. package/src/hooks/useUsers.ts +27 -0
  73. package/src/index.ts +18 -0
  74. package/src/services/userService.ts +9 -0
  75. package/src/types/index.ts +82 -0
  76. package/src/utils/theme.ts +16 -0
  77. package/dist/components/BottomNav/index.d.ts +0 -10
  78. package/dist/components/BottomNav/index.js +0 -32
  79. package/dist/components/ChatBox/index.d.ts +0 -15
  80. package/dist/components/ChatBox/index.js +0 -228
  81. package/dist/components/ChatButton/index.d.ts +0 -9
  82. package/dist/components/ChatButton/index.js +0 -17
  83. package/dist/components/ChatWindow/index.d.ts +0 -10
  84. package/dist/components/ChatWindow/index.js +0 -286
  85. package/dist/components/HomeView/index.d.ts +0 -12
  86. package/dist/components/HomeView/index.js +0 -51
  87. package/dist/components/UserList/index.d.ts +0 -13
  88. package/dist/components/UserList/index.js +0 -136
package/README.md CHANGED
@@ -1,170 +1,81 @@
1
- # Chat Widget
1
+ # react-chat-widget-extension v2
2
2
 
3
- A reusable, fully configurable floating chat widget for **React.js** and **Next.js** applications.
4
-
5
- - ✅ Environment-variable-driven behavior (status, type, API endpoint)
6
- - ✅ Fully themeable via a `theme` prop (colors, fonts, button, position)
7
- - ✅ SSR-safe — works with Next.js App Router and Pages Router
8
- - ✅ TypeScript-first
9
- - ✅ WebSocket-ready architecture
10
- - ✅ Loading skeletons, empty states, error handling built in
3
+ A drop-in floating chat widget for **React.js** and **Next.js** with a multi-screen UI, ticket system, and full theme control.
11
4
 
12
5
  ---
13
6
 
14
- ## Folder Structure
7
+ ## Screens & Navigation Flow
15
8
 
16
9
  ```
17
- my_first_project/
18
- ├── src/
19
- ├── index.ts # Public API exports
20
- ├── types/
21
- │ └── index.ts # All TypeScript types & interfaces
22
- ├── config/
23
- │ └── index.ts # Env variable loader (Next.js + React safe)
24
- ├── services/
25
- │ │ └── userService.ts # Fetch users from API
26
- │ ├── hooks/
27
- │ │ ├── useUsers.ts # Fetch & filter users hook
28
- │ │ └── useChat.ts # Chat state & message management hook
29
- │ ├── utils/
30
- │ │ └── theme.ts # Theme merging & CSS variable utilities
31
- │ └── components/
32
- │ ├── ChatWidget.tsx # 🏠 Root widget — mount this in your app
33
- │ ├── ChatButton/
34
- │ │ └── index.tsx # Floating action button
35
- │ ├── ChatWindow/
36
- │ │ └── index.tsx # Expandable chat panel
37
- │ ├── UserList/
38
- │ │ └── index.tsx # User list with loading/error/empty states
39
- │ ├── ChatBox/
40
- │ │ └── index.tsx # Conversation panel + message input
41
- │ └── MaintenanceView/
42
- │ └── index.tsx # Shown when CHAT_STATUS=MAINTENANCE
43
- ├── examples/
44
- │ ├── react-app/
45
- │ │ ├── .env.example # React env variables template
46
- │ │ └── App.tsx # React usage example
47
- │ └── nextjs-app/
48
- │ ├── .env.local.example # Next.js env variables template
49
- │ ├── app/
50
- │ │ ├── layout.tsx # App Router: root layout
51
- │ │ ├── ChatWidgetWrapper.tsx # App Router: 'use client' boundary
52
- │ │ └── page.tsx # App Router: home page
53
- │ └── pages/
54
- │ ├── _app.tsx # Pages Router: global app
55
- │ └── index.tsx # Pages Router: index page
56
- ├── package.json
57
- ├── tsconfig.json
58
- └── README.md
59
- ```
60
-
61
- ---
62
-
63
- ## Installation
64
-
65
- ```bash
66
- npm install ajaxter-chat
67
- # or
68
- yarn add ajaxter-chat
10
+ Floating Button
11
+ └── Opens Widget Window
12
+ ├── [Home Screen] ← default on open
13
+ ├── Need Support → [User List Screen: developers] → [Chat Screen]
14
+ ├── New Convo → [User List Screen: users] → [Chat Screen]
15
+ └── Raise Ticket [Ticket Screen] (always shown)
16
+
17
+ ├── [Bottom Tab: Home] ← Home screen
18
+ ├── [Bottom Tab: Chats] ← Recent conversations list
19
+ └── [Bottom Tab: Tickets] ← All raised tickets + new ticket form
69
20
  ```
70
21
 
71
22
  ---
72
23
 
73
24
  ## Environment Variables
74
25
 
75
- ### React.js (.env)
76
-
26
+ ### React (.env)
77
27
  ```env
78
28
  REACT_APP_CHAT_HOST_URL=http://your-api.com
79
- REACT_APP_CHAT_HOST_PORT=4000
80
- REACT_APP_CHAT_USER_LIST=api/v1/chat/users
81
- REACT_APP_CHAT_STATUS=ACTIVE
82
- REACT_APP_CHAT_TYPE=BOTH
29
+ REACT_APP_CHAT_HOST_PORT=4000 # Optional — omit to use URL default port
30
+ REACT_APP_CHAT_USER_LIST=api/v1/users
31
+ REACT_APP_CHAT_STATUS=ACTIVE # ACTIVE | DISABLE | MAINTENANCE
32
+ REACT_APP_CHAT_TYPE=BOTH # SUPPORT | CHAT | BOTH
83
33
  ```
84
34
 
85
35
  ### Next.js (.env.local)
86
-
87
36
  ```env
88
37
  NEXT_PUBLIC_CHAT_HOST_URL=http://your-api.com
89
- NEXT_PUBLIC_CHAT_HOST_PORT=4000
90
- NEXT_PUBLIC_CHAT_USER_LIST=api/v1/chat/users
38
+ NEXT_PUBLIC_CHAT_HOST_PORT=4000 # Optional
39
+ NEXT_PUBLIC_CHAT_USER_LIST=api/v1/users
91
40
  NEXT_PUBLIC_CHAT_STATUS=ACTIVE
92
41
  NEXT_PUBLIC_CHAT_TYPE=BOTH
93
42
  ```
94
43
 
95
- ### Variable Reference
96
-
97
- | Variable | Type | Description |
98
- |--------------------|---------------------------------------|------------------------------------------|
99
- | `CHAT_HOST_URL` | string | Base URL of your chat/user API |
100
- | `CHAT_HOST_PORT` | number | Port for your API server |
101
- | `CHAT_USER_LIST` | string | User list URL — see **User List API** below |
102
- | `CHAT_STATUS` | `ACTIVE` \| `DISABLE` \| `MAINTENANCE` | Controls widget visibility & state |
103
- | `CHAT_TYPE` | `SUPPORT` \| `CHAT` \| `BOTH` | Controls which users are shown |
104
-
105
44
  ---
106
45
 
107
- ## CHAT_STATUS Behavior
46
+ ## CHAT_STATUS Behaviour
108
47
 
109
- | Value | Behavior |
110
- |-----------------|---------------------------------------------------------------|
111
- | `ACTIVE` | Widget is fully enabled |
112
- | `DISABLE` | Widget is **not rendered at all** — zero DOM footprint |
113
- | `MAINTENANCE` | Widget opens but shows a maintenance message (non-interactive)|
48
+ | Value | Behaviour |
49
+ |---------------|--------------------------------------------------------|
50
+ | `ACTIVE` | Widget fully enabled |
51
+ | `DISABLE` | Widget **not rendered at all** — zero DOM footprint |
52
+ | `MAINTENANCE` | Widget opens but shows a maintenance message |
114
53
 
115
54
  ---
116
55
 
117
- ## CHAT_TYPE Behavior
56
+ ## CHAT_TYPE Behaviour
57
+
58
+ | Value | Home Cards Shown | User List Filter |
59
+ |-----------|-------------------------------------|-------------------|
60
+ | `SUPPORT` | Need Support only | `type=developer` |
61
+ | `CHAT` | New Conversation only | `type=user` |
62
+ | `BOTH` | Both cards | Per card clicked |
118
63
 
119
- | Value | User List Shown | UI |
120
- |-----------|------------------------------------------|-----------------------------|
121
- | `SUPPORT` | Only `type: "developer"` users | Single panel |
122
- | `CHAT` | Only `type: "user"` users | Single panel |
123
- | `BOTH` | Both developers and users | Two tabs (Support / Users) |
64
+ > **Raise Ticket is always shown regardless of CHAT_TYPE.**
124
65
 
125
66
  ---
126
67
 
127
68
  ## User List API
128
69
 
129
- The widget calls `CHAT_USER_LIST` in three ways:
130
-
131
- 1. **Same-origin / BFF (recommended)** — value starts with `/`, e.g. `/api/v1/chat/users`. The browser only shows a request to **your** app; your route handler proxies to the real API server-side, so the upstream URL (e.g. `http://your-api.com:4000/...`) does not appear as the client request URL in DevTools.
132
- 2. **Full URL** — value starts with `http://` or `https://`; that exact URL is fetched (visible in Network).
133
- 3. **Legacy** — otherwise it is built as
134
- `CHAT_HOST_URL` + optional `:CHAT_HOST_PORT` + path.
135
-
136
- Example (Next.js route at `app/api/v1/chat/users/route.ts` that forwards to your backend):
137
-
138
- ```env
139
- NEXT_PUBLIC_CHAT_USER_LIST=/api/v1/chat/users
140
- ```
141
-
142
- Legacy example:
143
-
144
70
  ```
145
- GET ${CHAT_HOST_URL}:${CHAT_HOST_PORT}/${CHAT_USER_LIST}
71
+ GET {CHAT_HOST_URL}[:{CHAT_HOST_PORT}]/{CHAT_USER_LIST}
146
72
  ```
147
73
 
148
74
  Expected response:
149
-
150
75
  ```json
151
76
  [
152
- {
153
- "name": "Alice Dev",
154
- "uid": "uid_001",
155
- "email": "alice@company.com",
156
- "mobile": "+1234567890",
157
- "project": "Platform Team",
158
- "type": "developer"
159
- },
160
- {
161
- "name": "Bob Smith",
162
- "uid": "uid_002",
163
- "email": "bob@client.com",
164
- "mobile": "+0987654321",
165
- "project": "Client Portal",
166
- "type": "user"
167
- }
77
+ { "name": "Alice", "uid": "u1", "email": "alice@co.com", "mobile": "", "project": "Platform", "type": "developer" },
78
+ { "name": "Bob", "uid": "u2", "email": "bob@co.com", "mobile": "", "project": "Portal", "type": "user" }
168
79
  ]
169
80
  ```
170
81
 
@@ -172,132 +83,113 @@ Expected response:
172
83
 
173
84
  ## Usage
174
85
 
175
- ### React.js
176
-
86
+ ### React
177
87
  ```tsx
178
88
  // App.tsx
179
- import { ChatWidget } from 'ajaxter-chat';
89
+ import { ChatWidget } from 'react-chat-widget-extension';
180
90
 
181
- function App() {
91
+ export default function App() {
182
92
  return (
183
- <div>
184
- <main>Your app content</main>
185
-
93
+ <>
94
+ <main>Your app</main>
186
95
  <ChatWidget
187
96
  theme={{
188
- primaryColor: '#6C63FF',
189
- buttonColor: '#6C63FF',
190
- buttonTextColor: '#ffffff',
191
- buttonLabel: 'Chat with us',
97
+ primaryColor: '#1aaa96',
98
+ buttonLabel: 'Chat with us',
192
99
  buttonPosition: 'bottom-right',
193
- fontFamily: "'DM Sans', sans-serif",
194
- borderRadius: '16px',
195
100
  }}
196
101
  />
197
- </div>
102
+ </>
198
103
  );
199
104
  }
200
105
  ```
201
106
 
202
107
  ### Next.js — App Router
203
-
204
108
  ```tsx
205
109
  // app/ChatWidgetWrapper.tsx
206
110
  'use client';
207
- import { ChatWidget } from 'ajaxter-chat';
208
-
111
+ import { ChatWidget } from 'react-chat-widget-extension';
209
112
  export function ChatWidgetWrapper() {
210
- return <ChatWidget theme={{ primaryColor: '#0ea5e9' }} />;
113
+ return <ChatWidget theme={{ primaryColor: '#1aaa96' }} />;
211
114
  }
212
- ```
213
115
 
214
- ```tsx
215
116
  // app/layout.tsx
216
117
  import { ChatWidgetWrapper } from './ChatWidgetWrapper';
217
-
218
118
  export default function RootLayout({ children }) {
219
- return (
220
- <html lang="en">
221
- <body>
222
- {children}
223
- <ChatWidgetWrapper />
224
- </body>
225
- </html>
226
- );
119
+ return <html><body>{children}<ChatWidgetWrapper /></body></html>;
227
120
  }
228
121
  ```
229
122
 
230
123
  ### Next.js — Pages Router
231
-
232
124
  ```tsx
233
125
  // pages/_app.tsx
234
- import { ChatWidget } from 'ajaxter-chat';
235
-
126
+ import { ChatWidget } from 'react-chat-widget-extension';
236
127
  export default function MyApp({ Component, pageProps }) {
237
- return (
238
- <>
239
- <Component {...pageProps} />
240
- <ChatWidget theme={{ primaryColor: '#10b981' }} />
241
- </>
242
- );
128
+ return <><Component {...pageProps} /><ChatWidget theme={{ primaryColor: '#1aaa96' }} /></>;
243
129
  }
244
130
  ```
245
131
 
246
132
  ---
247
133
 
248
- ## Theme Props
134
+ ## Theme Props (all optional)
249
135
 
250
- All theme properties are **optional**. Defaults are used when omitted.
251
-
252
- ```tsx
253
- interface ChatWidgetTheme {
254
- fontFamily?: string; // Default: "'DM Sans', 'Segoe UI', sans-serif"
255
- primaryColor?: string; // Default: '#6C63FF' header, accents, active states
256
- backgroundColor?: string; // Default: '#ffffff' widget panel background
257
- buttonColor?: string; // Default: '#6C63FF' floating button background
258
- buttonTextColor?: string; // Default: '#ffffff' floating button text/icon color
259
- buttonLabel?: string; // Default: 'Chat with us'
260
- buttonPosition?: 'bottom-right' | 'bottom-left'; // Default: 'bottom-right'
261
- borderRadius?: string; // Default: '16px'
262
- }
263
- ```
136
+ | Prop | Type | Default | Description |
137
+ |-------------------|------------------------------------|----------------------------------|--------------------------------------|
138
+ | `primaryColor` | `string` | `'#1aaa96'` | Header, active states, send button |
139
+ | `buttonColor` | `string` | `'#1aaa96'` | Floating button background |
140
+ | `buttonTextColor` | `string` | `'#ffffff'` | Floating button text/icon |
141
+ | `buttonLabel` | `string` | `'Chat with us'` | Floating button label |
142
+ | `buttonPosition` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Floating button corner |
143
+ | `fontFamily` | `string` | `"'DM Sans', 'Segoe UI', ..."` | Font used across the widget |
144
+ | `borderRadius` | `string` | `'16px'` | Widget panel corner radius |
145
+ | `backgroundColor` | `string` | `'#ffffff'` | Widget panel background |
264
146
 
265
147
  ---
266
148
 
267
- ## WebSocket Integration
149
+ ## Folder Structure
150
+
151
+ ```
152
+ src/
153
+ ├── index.ts ← Public API exports
154
+ ├── types/index.ts ← All TypeScript types
155
+ ├── config/index.ts ← Env loader (NEXT_PUBLIC_ + REACT_APP_)
156
+ ├── services/userService.ts ← fetch() user list API
157
+ ├── hooks/
158
+ │ ├── useUsers.ts ← Fetch & filter users
159
+ │ └── useChat.ts ← Message state, WebSocket-ready
160
+ ├── utils/theme.ts ← defaultTheme + mergeTheme
161
+ └── components/
162
+ ├── ChatWidget.tsx ← 🏠 Root — mount this in your app
163
+ ├── HomeScreen/ ← Hi there + option cards
164
+ ├── UserListScreen/ ← Slide-in user picker
165
+ ├── ChatScreen/ ← Conversation + input bar
166
+ ├── RecentChatsScreen/ ← Bottom tab: Chats
167
+ ├── TicketScreen/ ← Bottom tab: Tickets + raise form
168
+ ├── MaintenanceView/ ← Shown when MAINTENANCE
169
+ └── Tabs/BottomTabs.tsx ← Home / Chats / Tickets tabs
170
+ ```
268
171
 
269
- The `useChat` hook is ready for WebSocket integration. Look for the `TODO` comments in:
172
+ ---
270
173
 
271
- - `src/hooks/useChat.ts` Add `socket.emit('message', newMsg)` in `sendMessage`
272
- - `src/hooks/useChat.ts` → Add `socket.on('message', ...)` listener in `selectUser`
273
- - `src/components/ChatWindow/index.tsx` → Initialize socket connection on mount
174
+ ## WebSocket Integration Points
274
175
 
275
- Example with socket.io:
176
+ Look for `// TODO:` comments in `src/hooks/useChat.ts`:
276
177
 
277
178
  ```ts
278
- // In useChat.tssendMessage
279
- socket.emit('chat:message', { to: activeUser.uid, text });
179
+ // In selectUserconnect and listen:
180
+ // socket.emit('join', user.uid);
181
+ // socket.on('message', (msg) => setMessages(prev => [...prev, msg]));
280
182
 
281
- // In useChat.tsselectUser
282
- socket.on('chat:message', (msg: ChatMessage) => {
283
- setMessages((prev) => [...prev, msg]);
284
- });
183
+ // In sendMessageemit outgoing:
184
+ // socket.emit('message', newMsg);
285
185
  ```
286
186
 
287
187
  ---
288
188
 
289
- ## Build
290
-
291
- ```bash
292
- cd my_first_project
293
- npm install
294
- npm run build # Compile TypeScript → dist/
295
- npm run type-check # Verify types without emitting
296
- npm run dev # Watch mode
297
- ```
298
-
299
- ---
189
+ ## Resize (Maximize / Minimize)
300
190
 
301
- ## License
191
+ The widget has a maximize/minimize toggle button in the top-right of the panel header.
192
+ - **Normal size**: 380×560px
193
+ - **Maximized**: 480×720px
194
+ - Both sizes respect `max-width: calc(100vw - 32px)` and `max-height: calc(100vh - 110px)` for mobile safety.
302
195
 
303
- MIT
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { ChatMessage, ChatUser, ChatWidgetTheme } from '../../types';
3
+ interface ChatScreenProps {
4
+ activeUser: ChatUser;
5
+ messages: ChatMessage[];
6
+ onSend: (text: string) => void;
7
+ onBack: () => void;
8
+ onClose: () => void;
9
+ theme?: ChatWidgetTheme;
10
+ }
11
+ export declare const ChatScreen: React.FC<ChatScreenProps>;
12
+ export {};
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { mergeTheme } from '../../utils/theme';
4
+ export const ChatScreen = ({ activeUser, messages, onSend, onBack, onClose, theme, }) => {
5
+ const t = mergeTheme(theme);
6
+ const [text, setText] = useState('');
7
+ const endRef = useRef(null);
8
+ const inputRef = useRef(null);
9
+ useEffect(() => { var _a; (_a = endRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
10
+ const handleSend = () => {
11
+ var _a;
12
+ if (!text.trim())
13
+ return;
14
+ onSend(text);
15
+ setText('');
16
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
17
+ };
18
+ const handleKey = (e) => {
19
+ if (e.key === 'Enter' && !e.shiftKey) {
20
+ e.preventDefault();
21
+ handleSend();
22
+ }
23
+ };
24
+ const initials = activeUser.name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
25
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideInRight 0.25s ease' }, children: [_jsxs("div", { style: {
26
+ backgroundColor: t.primaryColor,
27
+ padding: '14px 18px',
28
+ display: 'flex',
29
+ alignItems: 'center',
30
+ gap: '10px',
31
+ flexShrink: 0,
32
+ }, children: [_jsx("button", { onClick: onBack, style: iconBtnStyle, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("div", { style: {
33
+ width: 36, height: 36, borderRadius: '50%',
34
+ backgroundColor: 'rgba(255,255,255,0.25)',
35
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
36
+ fontWeight: 700, fontSize: '13px', color: '#fff', flexShrink: 0,
37
+ }, children: initials }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: '14px', color: '#fff', fontFamily: t.fontFamily }, children: activeUser.name }), _jsxs("div", { style: { fontSize: '11px', color: 'rgba(255,255,255,0.8)', display: 'flex', alignItems: 'center', gap: 4 }, children: [_jsx("span", { style: { width: 6, height: 6, borderRadius: '50%', backgroundColor: '#a8f0c6', display: 'inline-block' } }), "Online"] })] }), _jsx("button", { onClick: onClose, style: iconBtnStyle, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round" }) }) })] }), _jsxs("div", { style: {
38
+ flex: 1, overflowY: 'auto', padding: '18px 16px',
39
+ display: 'flex', flexDirection: 'column', gap: '10px',
40
+ backgroundColor: '#f7f8fc',
41
+ }, children: [messages.length === 0 && (_jsxs("div", { style: {
42
+ margin: 'auto', textAlign: 'center',
43
+ fontSize: '13px', color: '#b0bec5',
44
+ fontFamily: t.fontFamily,
45
+ }, children: [_jsx("div", { style: { fontSize: '28px', marginBottom: 8 }, children: "\uD83D\uDCAC" }), "Say hi to ", activeUser.name, "!"] })), messages.map(msg => (_jsx(Bubble, { msg: msg, primaryColor: t.primaryColor, font: t.fontFamily }, msg.id))), _jsx("div", { ref: endRef })] }), _jsxs("div", { style: {
46
+ borderTop: '1px solid #eef0f5',
47
+ padding: '10px 14px',
48
+ backgroundColor: '#fff',
49
+ display: 'flex',
50
+ alignItems: 'flex-end',
51
+ gap: '10px',
52
+ flexShrink: 0,
53
+ }, children: [_jsx("textarea", { ref: inputRef, value: text, onChange: e => setText(e.target.value), onKeyDown: handleKey, placeholder: "Type and press [enter]..", rows: 1, style: {
54
+ flex: 1, resize: 'none', border: 'none', outline: 'none',
55
+ fontFamily: t.fontFamily, fontSize: '14px', lineHeight: '1.5',
56
+ maxHeight: '80px', overflowY: 'auto', color: '#1a2332',
57
+ padding: '6px 0', backgroundColor: 'transparent',
58
+ } }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px', flexShrink: 0 }, children: [_jsx(IconBtn, { onClick: () => { }, title: "Reaction", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M14 9h.01M10 9h.01M12 2a10 10 0 100 20A10 10 0 0012 2zm0 14s-4-1.5-4-4", stroke: "#9aa3af", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M8 15s1.5 2 4 2 4-2 4-2", stroke: "#9aa3af", strokeWidth: "1.8", strokeLinecap: "round" })] }) }), _jsx(IconBtn, { onClick: () => { }, title: "Attach", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66L9.41 17.41a2 2 0 01-2.83-2.83l8.49-8.48", stroke: "#9aa3af", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx(IconBtn, { onClick: () => { }, title: "Emoji", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "#9aa3af", strokeWidth: "1.8" }), _jsx("path", { d: "M8 14s1.5 2 4 2 4-2 4-2", stroke: "#9aa3af", strokeWidth: "1.8", strokeLinecap: "round" }), _jsx("line", { x1: "9", y1: "9", x2: "9.01", y2: "9", stroke: "#9aa3af", strokeWidth: "2.5", strokeLinecap: "round" }), _jsx("line", { x1: "15", y1: "9", x2: "15.01", y2: "9", stroke: "#9aa3af", strokeWidth: "2.5", strokeLinecap: "round" })] }) }), text.trim() && (_jsx("button", { onClick: handleSend, style: {
59
+ width: 36, height: 36, borderRadius: '50%',
60
+ backgroundColor: t.primaryColor, border: 'none',
61
+ cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
62
+ transition: 'transform 0.15s',
63
+ }, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] })] })] }));
64
+ };
65
+ const Bubble = ({ msg, primaryColor, font }) => {
66
+ const isMe = msg.senderId === 'me';
67
+ const time = new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
68
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: isMe ? 'flex-end' : 'flex-start', gap: 3 }, children: [_jsx("div", { style: {
69
+ maxWidth: '75%', padding: '10px 14px',
70
+ borderRadius: isMe ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
71
+ backgroundColor: isMe ? primaryColor : '#fff',
72
+ color: isMe ? '#fff' : '#1a2332',
73
+ fontSize: '14px', lineHeight: '1.5',
74
+ boxShadow: '0 1px 4px rgba(0,0,0,0.07)',
75
+ fontFamily: font, wordBreak: 'break-word',
76
+ }, children: msg.text }), _jsx("span", { style: { fontSize: '11px', color: '#b0bec5', padding: '0 4px' }, children: time })] }));
77
+ };
78
+ const IconBtn = ({ onClick, title, children }) => (_jsx("button", { onClick: onClick, title: title, style: { background: 'none', border: 'none', cursor: 'pointer', padding: '4px', display: 'flex', alignItems: 'center', borderRadius: '6px' }, onMouseEnter: e => e.currentTarget.style.background = '#f3f4f6', onMouseLeave: e => e.currentTarget.style.background = 'none', children: children }));
79
+ const iconBtnStyle = {
80
+ background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '50%',
81
+ width: 34, height: 34, display: 'flex', alignItems: 'center', justifyContent: 'center',
82
+ cursor: 'pointer', flexShrink: 0,
83
+ };
@@ -1,28 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ChatWidgetProps } from '../types';
3
- /**
4
- * ChatWidget
5
- *
6
- * Drop-in chat widget for React.js and Next.js apps.
7
- * All behavior is configured via environment variables.
8
- * All UI styling is configured via the `theme` prop.
9
- *
10
- * @example
11
- * // Basic usage
12
- * <ChatWidget />
13
- *
14
- * @example
15
- * // With custom theme
16
- * <ChatWidget
17
- * theme={{
18
- * primaryColor: '#FF6B6B',
19
- * buttonColor: '#FF6B6B',
20
- * buttonLabel: 'Need Help?',
21
- * buttonPosition: 'bottom-left',
22
- * fontFamily: "'Inter', sans-serif",
23
- * borderRadius: '12px',
24
- * }}
25
- * />
26
- */
27
3
  export declare const ChatWidget: React.FC<ChatWidgetProps>;
28
4
  export default ChatWidget;