@realtimexsco/live-chat 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -1628
- package/dist/index.cjs +311 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +78 -10
- package/dist/index.d.ts +78 -10
- package/dist/index.mjs +311 -147
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,1672 +1,73 @@
|
|
|
1
1
|
# @realtimexsco/live-chat
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Drop-in real-time chat UI for React and Next.js — direct messages, group chats, reactions, replies, forwarding, pinned/starred messages, and more. Built on Socket.IO, Zustand, Tailwind CSS v4, and Radix UI.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@realtimexsco/live-chat)
|
|
6
|
+
[](https://www.npmjs.com/package/@realtimexsco/live-chat)
|
|
7
|
+
[](./LICENSE)
|
|
4
8
|
|
|
5
9
|
| | |
|
|
6
10
|
|---|---|
|
|
7
|
-
| **Package
|
|
8
|
-
| **
|
|
9
|
-
| **Styles entry** | `@realtimexsco/live-chat/styles.css` |
|
|
11
|
+
| **Package** | [`@realtimexsco/live-chat`](https://www.npmjs.com/package/@realtimexsco/live-chat) |
|
|
12
|
+
| **Styles** | `@realtimexsco/live-chat/styles.css` |
|
|
10
13
|
| **Requires** | React 17+, Tailwind CSS **v4**, Zustand 4+ |
|
|
11
|
-
| **
|
|
12
|
-
|
|
13
|
-
Socket.IO client, REST API client, Zustand store, Radix UI, emoji picker, and all chat UI are **bundled inside the package**. Your app only installs a few peer dependencies.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Start here (5-minute overview)
|
|
18
|
-
|
|
19
|
-
1. **Install** the package + peers (`react`, `react-dom`, `zustand`, `tailwindcss` v4).
|
|
20
|
-
2. **Import CSS** — `@import "@realtimexsco/live-chat/styles.css"` and add Tailwind `@source` for the package `dist` files.
|
|
21
|
-
3. **Create** `chat.config.ts` with `clientId`, `accessToken`, `loggedUserDetails`, `apiUrl`, `socketUrl`.
|
|
22
|
-
4. **Render** `<ChatMain {...chatConfig} />` — the package includes a built-in viewport wrapper. For admin templates use `viewportHeight="calc(100dvh - 4rem)"`; for full-page chat use `viewportHeight="screen"`.
|
|
23
|
-
5. **Optional** — pass `components`, `classNames`, or `features` to customize. **Omit any slot → package default is used automatically.**
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
// Full page
|
|
27
|
-
<ChatMain {...chatConfig} viewportHeight="screen" />
|
|
28
|
-
|
|
29
|
-
// Admin shell with 4rem header (Elstar, Metronic, etc.)
|
|
30
|
-
<ChatMain {...chatConfig} viewportHeight="calc(100dvh - 4rem)" />
|
|
31
|
-
|
|
32
|
-
// Inside your own bounded flex column (parent must have height + min-h-0)
|
|
33
|
-
<div className="flex min-h-0 flex-1 overflow-hidden">
|
|
34
|
-
<ChatMain {...chatConfig} viewportHeight="full" />
|
|
35
|
-
</div>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**Do not** pass empty or placeholder components for slots you want to keep default — simply omit those keys from `components`.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Table of contents
|
|
43
|
-
|
|
44
|
-
1. [Chat features included](#chat-features-included)
|
|
45
|
-
2. [What you install vs what is bundled](#what-you-install-vs-what-is-bundled)
|
|
46
|
-
3. [Backend credentials](#backend-credentials)
|
|
47
|
-
4. [Installation step by step](#installation-step-by-step)
|
|
48
|
-
5. [Tailwind CSS v4 setup (required)](#tailwind-css-v4-setup-required)
|
|
49
|
-
6. [Project config file](#project-config-file)
|
|
50
|
-
7. [Quick start — minimum working chat](#quick-start--minimum-working-chat)
|
|
51
|
-
8. [Complete ChatMain example](#complete-chatmain-example)
|
|
52
|
-
9. [Customization — three ways](#customization--three-ways)
|
|
53
|
-
10. [Default component fallback (important)](#default-component-fallback-important)
|
|
54
|
-
11. [Which slots are wired](#which-slots-are-wired)
|
|
55
|
-
12. [Production integration pattern (admin templates)](#production-integration-pattern-admin-templates)
|
|
56
|
-
13. [Customization examples (Case 1–3)](#customization-examples-case-13)
|
|
57
|
-
14. [Phone & video calling](#phone--video-calling)
|
|
58
|
-
15. [Theme, light/dark, date/time](#theme-lightdark-datetime)
|
|
59
|
-
16. [Layout sections (`layout` prop)](#layout-sections-layout-prop)
|
|
60
|
-
17. [All component slots + examples](#all-component-slots--examples)
|
|
61
|
-
18. [All classNames keys](#all-classnames-keys)
|
|
62
|
-
19. [Wrapping package defaults (`packageDefaultComponents`)](#wrapping-package-defaults-packagedefaultcomponents)
|
|
63
|
-
20. [ChatMain props reference](#chatmain-props-reference)
|
|
64
|
-
21. [Chat provider (composable mode)](#chat-provider-composable-mode)
|
|
65
|
-
22. [Hooks & store](#hooks--store)
|
|
66
|
-
23. [React (Vite) — full setup](#react-vite--full-setup)
|
|
67
|
-
24. [Next.js — full setup](#nextjs--full-setup)
|
|
68
|
-
25. [Environment variables](#environment-variables)
|
|
69
|
-
26. [Dev proxy (CORS)](#dev-proxy-cors)
|
|
70
|
-
27. [Architecture](#architecture)
|
|
71
|
-
28. [All exports](#all-exports)
|
|
72
|
-
29. [Troubleshooting](#troubleshooting)
|
|
73
|
-
30. [Setup checklist](#setup-checklist)
|
|
74
|
-
31. [Package development (maintainers)](#package-development-maintainers)
|
|
75
|
-
32. [License](#license)
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Chat features included
|
|
80
|
-
|
|
81
|
-
| Feature | Supported |
|
|
82
|
-
|---------|-----------|
|
|
83
|
-
| Direct messages (1-to-1) | Yes |
|
|
84
|
-
| Group chats | Yes |
|
|
85
|
-
| Real-time messages (Socket.IO) | Yes |
|
|
86
|
-
| Optimistic send (instant UI) | Yes |
|
|
87
|
-
| Reactions, replies, forward | Yes |
|
|
88
|
-
| Edit / delete (me / everyone) | Yes |
|
|
89
|
-
| Pin & star messages | Yes |
|
|
90
|
-
| Attachments (images, files) | Yes |
|
|
91
|
-
| In-chat message search | Yes |
|
|
92
|
-
| Typing indicators | Yes |
|
|
93
|
-
| Read receipts (sent / delivered / read) | Yes |
|
|
94
|
-
| New chat / user list modal | Yes |
|
|
95
|
-
| Group members, admins, permissions | Yes |
|
|
96
|
-
| Light / dark mode | Yes |
|
|
97
|
-
| Locale & timezone formatting | Yes |
|
|
98
|
-
| Phone / video call hooks | Yes (you wire WebRTC) |
|
|
99
|
-
| Full UI customization | Yes |
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## What you install vs what is bundled
|
|
104
|
-
|
|
105
|
-
### You must install (peer dependencies)
|
|
106
|
-
|
|
107
|
-
| Package | Version | When | Why |
|
|
108
|
-
|---------|---------|------|-----|
|
|
109
|
-
| `react` | ≥ 17 | Always | UI framework |
|
|
110
|
-
| `react-dom` | ≥ 17 | Always | DOM rendering |
|
|
111
|
-
| `zustand` | ≥ 4 | Always | Chat state store |
|
|
112
|
-
| `tailwindcss` | **v4** | Always | Package uses Tailwind utilities |
|
|
113
|
-
| `@tailwindcss/vite` | v4 | Vite only | Tailwind plugin |
|
|
114
|
-
| `@tailwindcss/postcss` | v4 | Next.js only | Tailwind PostCSS plugin |
|
|
115
|
-
| `next` | ≥ 13 | Next.js only | App Router |
|
|
116
|
-
| `react-hot-toast` | ≥ 2 | Optional | Only if you use `showNotification` helper |
|
|
117
|
-
|
|
118
|
-
### Bundled inside the package (do not install separately)
|
|
119
|
-
|
|
120
|
-
`axios`, `socket.io-client`, `radix-ui`, `lucide-react`, `emoji-picker-react`, `clsx`, `tailwind-merge`, `class-variance-authority`, and all chat components.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## Backend credentials
|
|
125
|
-
|
|
126
|
-
| Field | Example | Notes |
|
|
127
|
-
|-------|---------|-------|
|
|
128
|
-
| `clientId` | `"6a35339216e46130366cda93"` | RealtimeX tenant / client id |
|
|
129
|
-
| `accessToken` | JWT string | User access token |
|
|
130
|
-
| `loggedUserDetails._id` | `"6a3533c416e46130366cda98"` | **Must match `_id` inside JWT** |
|
|
131
|
-
| `loggedUserDetails.name` | `"chat1"` | Display name |
|
|
132
|
-
| `loggedUserDetails.email` | `"chat1@example.com"` | Used for client-user login |
|
|
133
|
-
| `apiUrl` | `https://realtimex.softwareco.com/api/v1` | REST API — **must end with** `/api/v1` (**required**, pass from your app) |
|
|
134
|
-
| `socketUrl` | `https://realtimex.softwareco.com` | Socket host — **no** `/api/v1`; connects at `/connection`. Optional — derived from `apiUrl` if omitted |
|
|
135
|
-
| `themeColor` | `"#6366f1"` | Brand accent (optional) |
|
|
14
|
+
| **License** | [MIT](./LICENSE) |
|
|
136
15
|
|
|
137
|
-
|
|
16
|
+
Socket.IO, REST client, Zustand store, Radix UI, emoji picker, and chat UI are **bundled**. Your app only installs peer dependencies.
|
|
138
17
|
|
|
139
18
|
---
|
|
140
19
|
|
|
141
|
-
##
|
|
142
|
-
|
|
143
|
-
### 1. Install the package and peers
|
|
144
|
-
|
|
145
|
-
**npm:**
|
|
20
|
+
## Install
|
|
146
21
|
|
|
147
22
|
```bash
|
|
148
23
|
npm install @realtimexsco/live-chat react react-dom zustand tailwindcss
|
|
149
24
|
```
|
|
150
25
|
|
|
151
|
-
**
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
pnpm add @realtimexsco/live-chat react react-dom zustand tailwindcss
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### 2. Install Tailwind v4 plugin for your framework
|
|
158
|
-
|
|
159
|
-
**Vite:**
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
pnpm add -D @tailwindcss/vite @vitejs/plugin-react vite
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**Next.js:**
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
pnpm add -D @tailwindcss/postcss
|
|
169
|
-
# next is usually already installed
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 3. Verify install
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
npm ls @realtimexsco/live-chat
|
|
176
|
-
ls node_modules/@realtimexsco/live-chat/dist/index.d.ts # TypeScript types must exist
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### 4. Configure CSS, config file, and chat page (see sections below)
|
|
180
|
-
|
|
181
|
-
### 5. Run your app and open the chat route
|
|
182
|
-
|
|
183
|
-
No `.npmrc` or private token is required — the package is on the public npm registry.
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Tailwind CSS v4 setup (required)
|
|
188
|
-
|
|
189
|
-
The package will look unstyled without these three steps:
|
|
190
|
-
|
|
191
|
-
1. `@import` Tailwind + package `styles.css`
|
|
192
|
-
2. `@source` the package `dist` files so Tailwind scans bundled classes
|
|
193
|
-
3. Define `--chat-theme*` CSS variables in `:root`
|
|
194
|
-
|
|
195
|
-
### Vite — `src/index.css`
|
|
196
|
-
|
|
197
|
-
```css
|
|
198
|
-
@import "tailwindcss";
|
|
199
|
-
@import "@realtimexsco/live-chat/styles.css";
|
|
200
|
-
|
|
201
|
-
@source "../node_modules/@realtimexsco/live-chat/dist/index.mjs";
|
|
202
|
-
@source "../node_modules/@realtimexsco/live-chat/dist/index.cjs";
|
|
203
|
-
@source "../**/*.{js,jsx,ts,tsx}";
|
|
204
|
-
|
|
205
|
-
:root {
|
|
206
|
-
--radius: 0.625rem;
|
|
207
|
-
--background: oklch(1 0 0);
|
|
208
|
-
--foreground: oklch(0.145 0 0);
|
|
209
|
-
--primary: oklch(0.205 0 0);
|
|
210
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
211
|
-
--muted: oklch(0.97 0 0);
|
|
212
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
213
|
-
--border: oklch(0.922 0 0);
|
|
214
|
-
--ring: oklch(0.708 0 0);
|
|
215
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
216
|
-
--card: oklch(1 0 0);
|
|
217
|
-
--card-foreground: oklch(0.145 0 0);
|
|
218
|
-
--popover: oklch(1 0 0);
|
|
219
|
-
--popover-foreground: oklch(0.145 0 0);
|
|
220
|
-
--accent: oklch(0.97 0 0);
|
|
221
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
222
|
-
--secondary: oklch(0.97 0 0);
|
|
223
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
224
|
-
--input: oklch(0.922 0 0);
|
|
225
|
-
|
|
226
|
-
/* Overridden at runtime by ChatMain `themeColor` */
|
|
227
|
-
--chat-theme: #6366f1;
|
|
228
|
-
--chat-theme-5: #6366f10D;
|
|
229
|
-
--chat-theme-10: #6366f11A;
|
|
230
|
-
--chat-theme-20: #6366f133;
|
|
231
|
-
--chat-theme-40: #6366f166;
|
|
232
|
-
--chat-theme-60: #6366f199;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
@theme inline {
|
|
236
|
-
--color-background: var(--background);
|
|
237
|
-
--color-foreground: var(--foreground);
|
|
238
|
-
--color-primary: var(--primary);
|
|
239
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
240
|
-
--color-muted: var(--muted);
|
|
241
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
242
|
-
--color-border: var(--border);
|
|
243
|
-
--color-ring: var(--ring);
|
|
244
|
-
--color-destructive: var(--destructive);
|
|
245
|
-
--color-card: var(--card);
|
|
246
|
-
--color-card-foreground: var(--card-foreground);
|
|
247
|
-
--color-popover: var(--popover);
|
|
248
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
249
|
-
--color-accent: var(--accent);
|
|
250
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
251
|
-
--color-secondary: var(--secondary);
|
|
252
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
253
|
-
--color-input: var(--input);
|
|
254
|
-
--color-chat-theme: var(--chat-theme);
|
|
255
|
-
--color-chat-theme-5: var(--chat-theme-5);
|
|
256
|
-
--color-chat-theme-10: var(--chat-theme-10);
|
|
257
|
-
--color-chat-theme-20: var(--chat-theme-20);
|
|
258
|
-
--color-chat-theme-40: var(--chat-theme-40);
|
|
259
|
-
--color-chat-theme-60: var(--chat-theme-60);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
@layer base {
|
|
263
|
-
html, body, #root { height: 100%; }
|
|
264
|
-
body { @apply bg-background text-foreground; }
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Next.js — `src/app/globals.css`
|
|
269
|
-
|
|
270
|
-
> `globals.css` is inside `src/app/`, so `@source` uses **`../../node_modules`** (not `../`).
|
|
271
|
-
|
|
272
|
-
```css
|
|
273
|
-
@import "tailwindcss";
|
|
274
|
-
@import "@realtimexsco/live-chat/styles.css";
|
|
275
|
-
|
|
276
|
-
@source "../../node_modules/@realtimexsco/live-chat/dist/index.mjs";
|
|
277
|
-
@source "../../node_modules/@realtimexsco/live-chat/dist/index.cjs";
|
|
278
|
-
|
|
279
|
-
/* Copy :root, @theme inline, and @layer base from the Vite example above */
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### `@source` path cheat sheet
|
|
283
|
-
|
|
284
|
-
| CSS file location | `@source` prefix |
|
|
285
|
-
|-------------------|------------------|
|
|
286
|
-
| `src/index.css` (Vite) | `../node_modules/...` |
|
|
287
|
-
| `src/app/globals.css` (Next.js) | `../../node_modules/...` |
|
|
288
|
-
|
|
289
|
-
Wrong path = broken or unstyled chat UI.
|
|
290
|
-
|
|
291
|
-
### Vite — `vite.config.ts`
|
|
292
|
-
|
|
293
|
-
```ts
|
|
294
|
-
import path from "path";
|
|
295
|
-
import { fileURLToPath } from "url";
|
|
296
|
-
import { defineConfig } from "vite";
|
|
297
|
-
import react from "@vitejs/plugin-react";
|
|
298
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
299
|
-
|
|
300
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
301
|
-
|
|
302
|
-
export default defineConfig({
|
|
303
|
-
plugins: [react(), tailwindcss()],
|
|
304
|
-
resolve: {
|
|
305
|
-
alias: { "@": path.resolve(__dirname, "src") },
|
|
306
|
-
dedupe: ["react", "react-dom", "zustand", "socket.io-client", "@realtimexsco/live-chat"],
|
|
307
|
-
},
|
|
308
|
-
optimizeDeps: {
|
|
309
|
-
exclude: ["@realtimexsco/live-chat"],
|
|
310
|
-
include: ["zustand", "socket.io-client"],
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Next.js — `next.config.ts`
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
import type { NextConfig } from "next";
|
|
319
|
-
|
|
320
|
-
const nextConfig: NextConfig = {
|
|
321
|
-
transpilePackages: ["@realtimexsco/live-chat"],
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
export default nextConfig;
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Next.js — `postcss.config.mjs`
|
|
328
|
-
|
|
329
|
-
```js
|
|
330
|
-
const config = { plugins: { "@tailwindcss/postcss": {} } };
|
|
331
|
-
export default config;
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
---
|
|
335
|
-
|
|
336
|
-
## Project config file
|
|
337
|
-
|
|
338
|
-
Create `src/configs/chat.config.ts`:
|
|
339
|
-
|
|
340
|
-
```ts
|
|
341
|
-
/** Optional: read _id from JWT so it always matches the token */
|
|
342
|
-
function userIdFromToken(token: string): string | undefined {
|
|
343
|
-
try {
|
|
344
|
-
const payload = JSON.parse(
|
|
345
|
-
atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"))
|
|
346
|
-
);
|
|
347
|
-
return payload._id || payload.id;
|
|
348
|
-
} catch {
|
|
349
|
-
return undefined;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const accessToken = "YOUR_JWT_ACCESS_TOKEN";
|
|
354
|
-
|
|
355
|
-
export const chatConfig = {
|
|
356
|
-
clientId: "YOUR_CLIENT_ID",
|
|
357
|
-
accessToken,
|
|
358
|
-
loggedUserDetails: {
|
|
359
|
-
_id: userIdFromToken(accessToken) ?? "YOUR_USER_ID",
|
|
360
|
-
name: "Your Name",
|
|
361
|
-
email: "you@example.com",
|
|
362
|
-
},
|
|
363
|
-
apiUrl: "https://realtimex.softwareco.com/api/v1",
|
|
364
|
-
socketUrl: "https://realtimex.softwareco.com", // optional — auto-derived from apiUrl
|
|
365
|
-
themeColor: "#6366f1",
|
|
366
|
-
} as const;
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## Quick start — minimum working chat
|
|
372
|
-
|
|
373
|
-
```tsx
|
|
374
|
-
"use client"; // Next.js only — required on any file that imports chat
|
|
375
|
-
|
|
376
|
-
import ChatMain from "@realtimexsco/live-chat";
|
|
377
|
-
import { chatConfig } from "@/configs/chat.config";
|
|
378
|
-
|
|
379
|
-
export default function ChatPage() {
|
|
380
|
-
return (
|
|
381
|
-
<div className="h-dvh min-h-0 overflow-hidden">
|
|
382
|
-
<ChatMain
|
|
383
|
-
clientId={chatConfig.clientId}
|
|
384
|
-
accessToken={chatConfig.accessToken}
|
|
385
|
-
loggedUserDetails={chatConfig.loggedUserDetails}
|
|
386
|
-
apiUrl={chatConfig.apiUrl}
|
|
387
|
-
socketUrl={chatConfig.socketUrl}
|
|
388
|
-
themeColor={chatConfig.themeColor}
|
|
389
|
-
/>
|
|
390
|
-
</div>
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
**Container height is required.** `ChatMain` includes a built-in viewport (`chat-package-viewport`). Set `viewportHeight="screen"` for full page, or `viewportHeight="calc(100dvh - 4rem)"` below a fixed header. Alternatively wrap with `h-dvh min-h-0 overflow-hidden` and use default `viewportHeight="full"`.
|
|
396
|
-
|
|
397
|
-
---
|
|
398
|
-
|
|
399
|
-
## Complete ChatMain example
|
|
400
|
-
|
|
401
|
-
All common props: theme, locale, layout, customization, calls, alerts.
|
|
402
|
-
|
|
403
|
-
```tsx
|
|
404
|
-
"use client";
|
|
405
|
-
|
|
406
|
-
import { useState } from "react";
|
|
407
|
-
import ChatMain, {
|
|
408
|
-
type ChatColorMode,
|
|
409
|
-
type ChatComponents,
|
|
410
|
-
type ChatClassNames,
|
|
411
|
-
type ChatFeatures,
|
|
412
|
-
type AvatarSlotProps,
|
|
413
|
-
defaultChatLayoutConfig,
|
|
414
|
-
} from "@realtimexsco/live-chat";
|
|
415
|
-
import { chatConfig } from "@/configs/chat.config";
|
|
416
|
-
|
|
417
|
-
const MyAvatar = ({ src, name, size }: AvatarSlotProps) => (
|
|
418
|
-
<img
|
|
419
|
-
src={src || undefined}
|
|
420
|
-
alt={name}
|
|
421
|
-
className={`rounded-full object-cover avatar--${size}`}
|
|
422
|
-
style={{ width: 36, height: 36 }}
|
|
423
|
-
/>
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
const components: ChatComponents = {
|
|
427
|
-
Avatar: MyAvatar,
|
|
428
|
-
// ChatLayout: MyFullCustomUI, // Case 1 — replace entire UI
|
|
429
|
-
// MessageItem: MyMessageBubble, // Case 2 — single slot
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const classNames: ChatClassNames = {
|
|
433
|
-
sidebar: "bg-slate-950",
|
|
434
|
-
channelHeader: "border-b-2 border-indigo-500",
|
|
435
|
-
messageBubbleSender: "rounded-3xl shadow-md",
|
|
436
|
-
messageBubbleReceiver: "rounded-3xl",
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
const features: ChatFeatures = {
|
|
440
|
-
showPhoneCall: true,
|
|
441
|
-
showVideoCall: true,
|
|
442
|
-
onPhoneCall: ({ activeChannel, conversationId }) => {
|
|
443
|
-
console.log("Voice call", activeChannel.name, conversationId);
|
|
444
|
-
},
|
|
445
|
-
onVideoCall: ({ activeChannel, conversationId }) => {
|
|
446
|
-
console.log("Video call", activeChannel.name, conversationId);
|
|
447
|
-
},
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
export default function ChatPage() {
|
|
451
|
-
const [colorMode, setColorMode] = useState<ChatColorMode>("light");
|
|
452
|
-
const [error, setError] = useState<string | null>(null);
|
|
453
|
-
|
|
454
|
-
return (
|
|
455
|
-
<div className="h-dvh min-h-0 overflow-hidden">
|
|
456
|
-
<ChatMain
|
|
457
|
-
clientId={chatConfig.clientId}
|
|
458
|
-
accessToken={chatConfig.accessToken}
|
|
459
|
-
loggedUserDetails={chatConfig.loggedUserDetails}
|
|
460
|
-
apiUrl={chatConfig.apiUrl}
|
|
461
|
-
socketUrl={chatConfig.socketUrl}
|
|
462
|
-
themeColor={chatConfig.themeColor}
|
|
463
|
-
colorMode={colorMode}
|
|
464
|
-
onColorModeChange={setColorMode}
|
|
465
|
-
showColorModeToggle={false}
|
|
466
|
-
locale="en-US"
|
|
467
|
-
timeZone="Asia/Kolkata"
|
|
468
|
-
hour12={false}
|
|
469
|
-
showDateTimeSettings
|
|
470
|
-
layout={{ ...defaultChatLayoutConfig }}
|
|
471
|
-
components={components}
|
|
472
|
-
classNames={classNames}
|
|
473
|
-
features={features}
|
|
474
|
-
error={error}
|
|
475
|
-
onErrorDismiss={() => setError(null)}
|
|
476
|
-
/>
|
|
477
|
-
</div>
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
---
|
|
483
|
-
|
|
484
|
-
## Customization — three ways
|
|
485
|
-
|
|
486
|
-
You can combine all three.
|
|
487
|
-
|
|
488
|
-
| Case | Prop | What it does |
|
|
489
|
-
|------|------|--------------|
|
|
490
|
-
| **1** | `components.ChatLayout` | Replace the **entire** chat UI shell |
|
|
491
|
-
| **2** | `components.*` | Replace **one** component (avatar, header, message bubble, drawer, etc.) |
|
|
492
|
-
| **3** | `classNames.*` | Override **Tailwind classes** per region — no new React components |
|
|
493
|
-
|
|
494
|
-
Omit any slot or className key → **package default is used automatically**.
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## Default component fallback (important)
|
|
499
|
-
|
|
500
|
-
Customization is **opt-in per slot**. You never need to register every component.
|
|
501
|
-
|
|
502
|
-
### How it works internally
|
|
503
|
-
|
|
504
|
-
```
|
|
505
|
-
ChatMain components={{ MembersDrawer: MyDrawer }}
|
|
506
|
-
↓
|
|
507
|
-
ChatCustomizationProvider merges your config
|
|
508
|
-
↓
|
|
509
|
-
At render: resolveComponent("MembersDrawer", PackageMembersDrawer)
|
|
510
|
-
↓
|
|
511
|
-
Custom passed? → use MyDrawer
|
|
512
|
-
Not passed? → use PackageMembersDrawer (built-in default)
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
Rules:
|
|
516
|
-
|
|
517
|
-
| You pass | Result |
|
|
518
|
-
|----------|--------|
|
|
519
|
-
| No `components` prop at all | **Full default chat UI** |
|
|
520
|
-
| `components={{ Avatar: MyAvatar }}` | Custom avatar only; **all other slots use defaults** |
|
|
521
|
-
| `components={{ MembersDrawer: undefined }}` | Treated as not passed → **default drawer** |
|
|
522
|
-
| `classNames={{ sidebar: "..." }}` | Your classes **merge on top of** package defaults |
|
|
523
|
-
|
|
524
|
-
### Code pattern inside the package
|
|
525
|
-
|
|
526
|
-
Every wired slot follows this pattern:
|
|
527
|
-
|
|
528
|
-
```tsx
|
|
529
|
-
const MembersDrawerSlot = resolveComponent("MembersDrawer", MembersDrawer);
|
|
530
|
-
return <MembersDrawerSlot isOpen={...} onOpenChange={...} ... />;
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
Your custom component receives the **same props** as the package default (`MembersDrawerSlotProps`, etc.). Import the prop type from the package for TypeScript.
|
|
534
|
-
|
|
535
|
-
### Wrapping instead of rebuilding
|
|
536
|
-
|
|
537
|
-
Use `packageDefaultComponents` when you only need to restyle or add a wrapper:
|
|
538
|
-
|
|
539
|
-
```tsx
|
|
540
|
-
import { packageDefaultComponents, type MembersDrawerSlotProps } from "@realtimexsco/live-chat";
|
|
541
|
-
|
|
542
|
-
const MyMembersDrawer = (props: MembersDrawerSlotProps) => (
|
|
543
|
-
<div className="my-drawer-shell">
|
|
544
|
-
<packageDefaultComponents.MembersDrawer! {...props} />
|
|
545
|
-
</div>
|
|
546
|
-
);
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
---
|
|
550
|
-
|
|
551
|
-
## Which slots are wired
|
|
552
|
-
|
|
553
|
-
All slots below are **honored at runtime** when you pass them on `ChatMain` `components` (or `Chat` `uiConfig.components`). Slots not listed as wired may still be typed for future use or require replacing a parent slot (e.g. `ChannelHeader`).
|
|
554
|
-
|
|
555
|
-
| Slot | Wired in | Fallback when omitted |
|
|
556
|
-
|------|----------|------------------------|
|
|
557
|
-
| `ChatLayout` | `ChatLayout.tsx` | `DefaultChatLayout` |
|
|
558
|
-
| `LoggedUserDetails` | `DefaultChatLayout` | Package default |
|
|
559
|
-
| `ChannelList` | `DefaultChatLayout` | Package default |
|
|
560
|
-
| `ChannelHeader` | `DefaultChatLayout` | Package default |
|
|
561
|
-
| `MessageList` | `DefaultChatLayout` | Package default |
|
|
562
|
-
| `MessageInput` | `DefaultChatLayout` | Package default |
|
|
563
|
-
| `ForwardModal` | `DefaultChatLayout` | Package default |
|
|
564
|
-
| `ChatPanelAlerts` | `DefaultChatLayout` | Package default |
|
|
565
|
-
| `ChannelListItem` | `ChannelListItem` wrapper | `DefaultChannelListItem` |
|
|
566
|
-
| `Avatar` | `ChatAvatar` | `DefaultChatAvatar` |
|
|
567
|
-
| `HeaderCallActions` | `HeaderCallActions` | Built-in phone/video group |
|
|
568
|
-
| `PhoneCallButton` | `HeaderCallActions` | Built-in button |
|
|
569
|
-
| `VideoCallButton` | `HeaderCallActions` | Built-in button |
|
|
570
|
-
| `HeaderLeftSide` | `ChannelHeaderView` | Package default |
|
|
571
|
-
| `HeaderRightSide` | `ChannelHeaderView` | Package default |
|
|
572
|
-
| `ChatActionModal` | `ChannelHeaderView` | Package default |
|
|
573
|
-
| `ChannelDetailsDrawer` | `ChannelHeaderView` | Package default |
|
|
574
|
-
| `MembersDrawer` | `ChannelHeaderView` | Package default |
|
|
575
|
-
| `AdminsDrawer` | `ChannelHeaderView` | Package default |
|
|
576
|
-
| `PermissionDrawer` | `ChannelHeaderView` | Package default |
|
|
577
|
-
| `AttachmentsDrawer` | `ChannelHeaderView` | Package default |
|
|
578
|
-
| `PinnedMessagesDrawer` | `ChannelHeaderView` | Package default |
|
|
579
|
-
| `StarredMessagesDrawer` | `ChannelHeaderView` | Package default |
|
|
580
|
-
|
|
581
|
-
> **Replace entire header:** Pass `components.ChannelHeader` with your own component (use `useChannelHeader` hook for state/handlers). That replaces the full header **and** all drawers inside it.
|
|
582
|
-
|
|
583
|
-
### Advanced slots (replace parent component)
|
|
584
|
-
|
|
585
|
-
These slots are **typed and exported** but used inside inner components. To customize them, either replace the parent slot or copy the parent and wire your component:
|
|
586
|
-
|
|
587
|
-
| Slot | Customize by replacing |
|
|
588
|
-
|------|------------------------|
|
|
589
|
-
| `MessageItem` | `MessageList` (pass your list that renders custom items) |
|
|
590
|
-
| `MessageToolbar`, `MessageStatus`, `MessageAttachments`, `MessageReactions`, `MessageReplySnippet` | `MessageItem` or `MessageList` |
|
|
591
|
-
| `HeaderSearchOverlay` | `HeaderRightSide` or `ChannelHeader` |
|
|
592
|
-
| `ChatThemeToggle`, `ChatDateTimeSettings`, `ChatSocketStatus` | Used inside header/sidebar — replace parent or `ChannelHeader` |
|
|
593
|
-
|
|
594
|
-
For most apps, `components` + `classNames` on the [wired slots](#which-slots-are-wired) table is enough without touching advanced slots.
|
|
595
|
-
|
|
596
|
-
---
|
|
597
|
-
|
|
598
|
-
## Production integration pattern (admin templates)
|
|
599
|
-
|
|
600
|
-
Recommended structure for apps like **Elstar**, **Metronic**, or any admin shell:
|
|
601
|
-
|
|
602
|
-
```
|
|
603
|
-
src/
|
|
604
|
-
├── configs/
|
|
605
|
-
│ ├── chat.config.ts # credentials only
|
|
606
|
-
│ ├── chat.customization.config.ts # components + classNames
|
|
607
|
-
│ └── chat.layout.config.ts # layout section toggles
|
|
608
|
-
├── components/chat/custom/
|
|
609
|
-
│ ├── ElstarMembersDrawer.tsx # custom drawer example
|
|
610
|
-
│ ├── ElstarChatAvatar.tsx
|
|
611
|
-
│ └── index.ts
|
|
612
|
-
└── views/Chat.tsx # wires ChatMain
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
### `chat.config.ts` — credentials only
|
|
616
|
-
|
|
617
|
-
```ts
|
|
618
|
-
export const chatConfig = {
|
|
619
|
-
clientId: "YOUR_CLIENT_ID",
|
|
620
|
-
accessToken: "YOUR_JWT",
|
|
621
|
-
loggedUserDetails: { _id: "...", name: "...", email: "..." },
|
|
622
|
-
apiUrl: "https://api.example.com/api/v1",
|
|
623
|
-
socketUrl: "https://api.example.com",
|
|
624
|
-
themeColor: "#6366f1",
|
|
625
|
-
} as const;
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
### `chat.customization.config.ts` — UI overrides
|
|
629
|
-
|
|
630
|
-
```ts
|
|
631
|
-
import type { ChatClassNames, ChatComponents } from "@realtimexsco/live-chat";
|
|
632
|
-
import {
|
|
633
|
-
ElstarChatAvatar,
|
|
634
|
-
ElstarHeaderCallActions,
|
|
635
|
-
ElstarMembersDrawer,
|
|
636
|
-
ElstarPhoneCallButton,
|
|
637
|
-
ElstarVideoCallButton,
|
|
638
|
-
} from "@/components/chat/custom";
|
|
639
|
-
|
|
640
|
-
/** Only register slots you want to customize. All others use package defaults. */
|
|
641
|
-
export const chatComponents: ChatComponents = {
|
|
642
|
-
Avatar: ElstarChatAvatar,
|
|
643
|
-
HeaderCallActions: ElstarHeaderCallActions,
|
|
644
|
-
PhoneCallButton: ElstarPhoneCallButton,
|
|
645
|
-
VideoCallButton: ElstarVideoCallButton,
|
|
646
|
-
MembersDrawer: ElstarMembersDrawer,
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
export const chatClassNames: ChatClassNames = {
|
|
650
|
-
shell: "chat-container-root",
|
|
651
|
-
channelListItemActive: "bg-indigo-50 ring-1 ring-indigo-200",
|
|
652
|
-
messageBubbleSender: "rounded-2xl shadow-sm",
|
|
653
|
-
drawer: "z-[60]",
|
|
654
|
-
drawerContent: "rounded-l-2xl",
|
|
655
|
-
};
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
### `views/Chat.tsx` — single entry
|
|
659
|
-
|
|
660
|
-
```tsx
|
|
661
|
-
import ChatMain, { type ChatColorMode } from "@realtimexsco/live-chat";
|
|
662
|
-
import { chatConfig } from "@/configs/chat.config";
|
|
663
|
-
import { chatComponents, chatClassNames } from "@/configs/chat.customization.config";
|
|
664
|
-
import { chatLayoutConfig } from "@/configs/chat.layout.config";
|
|
665
|
-
|
|
666
|
-
export default function ChatPage() {
|
|
667
|
-
return (
|
|
668
|
-
<div className="h-dvh min-h-0 overflow-hidden">
|
|
669
|
-
<ChatMain
|
|
670
|
-
{...chatConfig}
|
|
671
|
-
layout={chatLayoutConfig}
|
|
672
|
-
components={chatComponents}
|
|
673
|
-
classNames={chatClassNames}
|
|
674
|
-
showColorModeToggle={false}
|
|
675
|
-
colorMode="light" // sync with your app theme
|
|
676
|
-
/>
|
|
677
|
-
</div>
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
### Full custom `MembersDrawer` example
|
|
683
|
-
|
|
684
|
-
Use the package store inside your drawer — same data/actions as the default drawer:
|
|
685
|
-
|
|
686
|
-
```tsx
|
|
687
|
-
import { useState, useMemo } from "react";
|
|
688
|
-
import {
|
|
689
|
-
useChatStore,
|
|
690
|
-
type MembersDrawerSlotProps,
|
|
691
|
-
} from "@realtimexsco/live-chat";
|
|
692
|
-
import Drawer from "@/components/ui/Drawer"; // your design system
|
|
693
|
-
|
|
694
|
-
const MyMembersDrawer = ({
|
|
695
|
-
isOpen,
|
|
696
|
-
onOpenChange,
|
|
697
|
-
conversationId,
|
|
698
|
-
conversationInfo,
|
|
699
|
-
}: MembersDrawerSlotProps) => {
|
|
700
|
-
const allUsers = useChatStore((s) => s.allUsers);
|
|
701
|
-
const manageGroupMembers = useChatStore((s) => s.manageGroupMembers);
|
|
702
|
-
const loggedUserDetails = useChatStore((s) => s.loggedUserDetails);
|
|
703
|
-
|
|
704
|
-
const participants = conversationInfo?.participants ?? [];
|
|
705
|
-
|
|
706
|
-
return (
|
|
707
|
-
<Drawer isOpen={isOpen} onClose={() => onOpenChange(false)} title="Members">
|
|
708
|
-
{/* Your UI — add/remove members via manageGroupMembers */}
|
|
709
|
-
<ul>
|
|
710
|
-
{participants.map((p) => (
|
|
711
|
-
<li key={typeof p === "string" ? p : p._id}>{typeof p === "string" ? p : p.name}</li>
|
|
712
|
-
))}
|
|
713
|
-
</ul>
|
|
714
|
-
</Drawer>
|
|
715
|
-
);
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
export default MyMembersDrawer;
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
Register it: `components={{ MembersDrawer: MyMembersDrawer }}`. If you **remove** that line, the package default members drawer appears again.
|
|
722
|
-
|
|
723
|
-
---
|
|
724
|
-
|
|
725
|
-
## Customization examples (Case 1–3)
|
|
726
|
-
|
|
727
|
-
### Case 1 — Replace entire chat UI
|
|
728
|
-
|
|
729
|
-
```tsx
|
|
730
|
-
import ChatMain, {
|
|
731
|
-
useChatController,
|
|
732
|
-
DefaultChatLayout,
|
|
733
|
-
type ChatLayoutSlotProps,
|
|
734
|
-
} from "@realtimexsco/live-chat";
|
|
735
|
-
|
|
736
|
-
// Option A: wrap the default layout
|
|
737
|
-
function MyChatShell(props: ChatLayoutSlotProps) {
|
|
738
|
-
return (
|
|
739
|
-
<div className="flex h-full flex-col">
|
|
740
|
-
<header className="shrink-0 border-b px-4 py-2 font-semibold">My App Chat</header>
|
|
741
|
-
<div className="min-h-0 flex-1">
|
|
742
|
-
<DefaultChatLayout {...props} shellClassName="rounded-none shadow-none" />
|
|
743
|
-
</div>
|
|
744
|
-
</div>
|
|
745
|
-
);
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
// Option B: build from scratch with useChatController()
|
|
749
|
-
function MyFullChatUI(_props: ChatLayoutSlotProps) {
|
|
750
|
-
const {
|
|
751
|
-
activeChannel,
|
|
752
|
-
conversationId,
|
|
753
|
-
conversationMessages,
|
|
754
|
-
handleChannelSelect,
|
|
755
|
-
handleSendMessage,
|
|
756
|
-
setActiveChannel,
|
|
757
|
-
state,
|
|
758
|
-
updateState,
|
|
759
|
-
} = useChatController();
|
|
760
|
-
|
|
761
|
-
return (
|
|
762
|
-
<div className="flex h-full">
|
|
763
|
-
{/* Your sidebar, header, messages, input — full control */}
|
|
764
|
-
</div>
|
|
765
|
-
);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
<ChatMain
|
|
769
|
-
{...chatConfig}
|
|
770
|
-
clientId={chatConfig.clientId}
|
|
771
|
-
components={{ ChatLayout: MyChatShell }}
|
|
772
|
-
/>;
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
### Case 2 — Replace individual components
|
|
776
|
-
|
|
777
|
-
```tsx
|
|
778
|
-
<ChatMain
|
|
779
|
-
{...chatConfig}
|
|
780
|
-
clientId={chatConfig.clientId}
|
|
781
|
-
components={{
|
|
782
|
-
Avatar: MyAvatar,
|
|
783
|
-
ChannelListItem: MyConversationRow,
|
|
784
|
-
MessageItem: MyMessageBubble,
|
|
785
|
-
MessageInput: MyComposer,
|
|
786
|
-
PhoneCallButton: MyPhoneBtn,
|
|
787
|
-
MembersDrawer: MyMembersPanel,
|
|
788
|
-
}}
|
|
789
|
-
/>
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
### Case 3 — Style with classNames only
|
|
793
|
-
|
|
794
|
-
```tsx
|
|
795
|
-
<ChatMain
|
|
796
|
-
{...chatConfig}
|
|
797
|
-
clientId={chatConfig.clientId}
|
|
798
|
-
classNames={{
|
|
799
|
-
channelListItemActive: "bg-indigo-50 ring-1 ring-indigo-200",
|
|
800
|
-
messageBubbleSender: "rounded-2xl shadow-sm",
|
|
801
|
-
messageBubbleReceiver: "rounded-2xl bg-white",
|
|
802
|
-
messageInput: "border-t border-gray-200",
|
|
803
|
-
}}
|
|
804
|
-
/>
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
---
|
|
808
|
-
|
|
809
|
-
## Phone & video calling
|
|
810
|
-
|
|
811
|
-
Call buttons appear in **DM chats only** (hidden for groups).
|
|
812
|
-
|
|
813
|
-
### Option A — Keep default buttons, add callbacks
|
|
814
|
-
|
|
815
|
-
```tsx
|
|
816
|
-
features={{
|
|
817
|
-
showPhoneCall: true,
|
|
818
|
-
showVideoCall: true,
|
|
819
|
-
onPhoneCall: ({ activeChannel, conversationId }) => {
|
|
820
|
-
yourVoiceSDK.start(activeChannel.id, conversationId);
|
|
821
|
-
},
|
|
822
|
-
onVideoCall: ({ activeChannel, conversationId }) => {
|
|
823
|
-
yourVideoSDK.start(activeChannel.id, conversationId);
|
|
824
|
-
},
|
|
825
|
-
}}
|
|
826
|
-
```
|
|
827
|
-
|
|
828
|
-
### Option B — Replace the call button group
|
|
829
|
-
|
|
830
|
-
```tsx
|
|
831
|
-
components={{
|
|
832
|
-
HeaderCallActions: ({ onPhoneCall, onVideoCall, activeChannel }) => (
|
|
833
|
-
<div className="flex gap-2">
|
|
834
|
-
<button type="button" onClick={onPhoneCall}>Call {activeChannel.name}</button>
|
|
835
|
-
<button type="button" onClick={onVideoCall}>Video</button>
|
|
836
|
-
</div>
|
|
837
|
-
),
|
|
838
|
-
}}
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
> Do **not** import `HeaderCallActions` from the package inside your custom `HeaderCallActions` — that causes infinite recursion. Render your own buttons instead.
|
|
842
|
-
|
|
843
|
-
### Option C — Replace individual buttons
|
|
844
|
-
|
|
845
|
-
```tsx
|
|
846
|
-
components={{
|
|
847
|
-
PhoneCallButton: ({ onPhoneCall, className }) => (
|
|
848
|
-
<button type="button" className={className} onClick={onPhoneCall}>📞</button>
|
|
849
|
-
),
|
|
850
|
-
VideoCallButton: ({ onVideoCall, className }) => (
|
|
851
|
-
<button type="button" className={className} onClick={onVideoCall}>📹</button>
|
|
852
|
-
),
|
|
853
|
-
}}
|
|
854
|
-
```
|
|
855
|
-
|
|
856
|
-
### Hide calls
|
|
857
|
-
|
|
858
|
-
```tsx
|
|
859
|
-
features={{ showPhoneCall: false, showVideoCall: false }}
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
---
|
|
863
|
-
|
|
864
|
-
## Theme, light/dark, date/time
|
|
865
|
-
|
|
866
|
-
### Brand color
|
|
867
|
-
|
|
868
|
-
```tsx
|
|
869
|
-
<ChatMain {...chatConfig} clientId={chatConfig.clientId} themeColor="#7c3aed" />
|
|
870
|
-
```
|
|
871
|
-
|
|
872
|
-
Runtime updates `--chat-theme` CSS variables automatically.
|
|
873
|
-
|
|
874
|
-
### Light / dark mode
|
|
875
|
-
|
|
876
|
-
| Pattern | Props |
|
|
877
|
-
|---------|-------|
|
|
878
|
-
| Your app controls theme (e.g. admin template) | `colorMode={mode}` `onColorModeChange={setMode}` `showColorModeToggle={false}` |
|
|
879
|
-
| Chat manages its own theme | `defaultColorMode="light"` (built-in toggle shown) |
|
|
880
|
-
| Start dark | `defaultColorMode="dark"` |
|
|
881
|
-
|
|
882
|
-
### Date / time
|
|
883
|
-
|
|
884
|
-
```tsx
|
|
885
|
-
<ChatMain
|
|
886
|
-
{...chatConfig}
|
|
887
|
-
clientId={chatConfig.clientId}
|
|
888
|
-
locale="en-GB"
|
|
889
|
-
timeZone="Europe/London"
|
|
890
|
-
hour12={false}
|
|
891
|
-
showDateTimeSettings={false}
|
|
892
|
-
onDateTimePreferencesChange={(prefs) => console.log(prefs)}
|
|
893
|
-
/>
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
---
|
|
897
|
-
|
|
898
|
-
## Layout sections (`layout` prop)
|
|
899
|
-
|
|
900
|
-
Toggle parts of the default UI without writing new components.
|
|
901
|
-
|
|
902
|
-
```ts
|
|
903
|
-
import { defaultChatLayoutConfig } from "@realtimexsco/live-chat";
|
|
904
|
-
|
|
905
|
-
export const chatLayoutConfig = {
|
|
906
|
-
...defaultChatLayoutConfig,
|
|
907
|
-
// sidebar: true, // left panel wrapper
|
|
908
|
-
// loggedUserDetails: true, // profile + new chat button
|
|
909
|
-
// channelList: true, // conversation list
|
|
910
|
-
// header: true, // channel header bar
|
|
911
|
-
// messageList: true, // message bubbles
|
|
912
|
-
// input: true, // composer
|
|
913
|
-
// forwardModal: true, // forward dialog
|
|
914
|
-
};
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
Examples:
|
|
918
|
-
|
|
919
|
-
```tsx
|
|
920
|
-
layout={{ input: false }} // read-only (no composer)
|
|
921
|
-
layout={{ sidebar: false }} // hide sidebar — messages only
|
|
922
|
-
layout={{ forwardModal: false }} // disable forward modal
|
|
923
|
-
layout={{ loggedUserDetails: false, channelList: true }} // list without profile block
|
|
924
|
-
```
|
|
925
|
-
|
|
926
|
-
---
|
|
927
|
-
|
|
928
|
-
## All component slots + examples
|
|
929
|
-
|
|
930
|
-
Pass only the slots you want to override via `components` on `ChatMain` (or `uiConfig` on `Chat`).
|
|
931
|
-
|
|
932
|
-
Import prop types from the package for TypeScript, e.g. `AvatarSlotProps`, `MessageItemSlotProps`.
|
|
933
|
-
|
|
934
|
-
| Slot | Replaces | Prop type |
|
|
935
|
-
|------|----------|-----------|
|
|
936
|
-
| `ChatLayout` | Entire chat shell | `ChatLayoutSlotProps` |
|
|
937
|
-
| `LoggedUserDetails` | Sidebar profile + new chat | `LoggedUserDetailsSlotProps` |
|
|
938
|
-
| `ChannelList` | Conversation list | `ChannelListSlotProps` |
|
|
939
|
-
| `ChannelListItem` | One conversation row | `ChannelListItemSlotProps` |
|
|
940
|
-
| `ChannelHeader` | Full header bar | `ChannelHeaderSlotProps` |
|
|
941
|
-
| `HeaderLeftSide` | Back, name, pin/star | `HeaderLeftSideSlotProps` |
|
|
942
|
-
| `HeaderRightSide` | Search, menu, settings | `HeaderRightSideSlotProps` |
|
|
943
|
-
| `HeaderCallActions` | Phone + video group | `HeaderCallActionsSlotProps` |
|
|
944
|
-
| `PhoneCallButton` | Voice call button | `PhoneCallButtonSlotProps` |
|
|
945
|
-
| `VideoCallButton` | Video call button | `VideoCallButtonSlotProps` |
|
|
946
|
-
| `HeaderSearchOverlay` | Message search dropdown | `HeaderSearchOverlaySlotProps` |
|
|
947
|
-
| `MessageList` | Scrollable messages area | `ActiveChannelMessagesSlotProps` |
|
|
948
|
-
| `MessageItem` | Single message bubble | `MessageItemSlotProps` |
|
|
949
|
-
| `MessageInput` | Composer | `ChannelMessageBoxSlotProps` |
|
|
950
|
-
| `ForwardModal` | Forward dialog | `ForwardModalSlotProps` |
|
|
951
|
-
| `ChatPanelAlerts` | Error/info banner | `ChatPanelAlertsSlotProps` |
|
|
952
|
-
| `ChatActionModal` | Clear/delete/block confirm | `ChatActionModalSlotProps` |
|
|
953
|
-
| `ChannelDetailsDrawer` | Channel details sheet | `ChannelDetailsDrawerSlotProps` |
|
|
954
|
-
| `MembersDrawer` | Group members sheet | `MembersDrawerSlotProps` |
|
|
955
|
-
| `AdminsDrawer` | Group admins sheet | `AdminsDrawerSlotProps` |
|
|
956
|
-
| `PermissionDrawer` | Permissions sheet | `PermissionDrawerSlotProps` |
|
|
957
|
-
| `AttachmentsDrawer` | Attachments sheet | `AttachmentsDrawerSlotProps` |
|
|
958
|
-
| `PinnedMessagesDrawer` | Pinned messages sheet | `PinnedMessagesDrawerSlotProps` |
|
|
959
|
-
| `StarredMessagesDrawer` | Starred messages sheet | `StarredMessagesDrawerSlotProps` |
|
|
960
|
-
| `Avatar` | Avatar everywhere | `AvatarSlotProps` |
|
|
961
|
-
| `MessageToolbar` | Reply/forward/edit menu | `MessageToolbarSlotProps` |
|
|
962
|
-
| `MessageStatus` | Sent/delivered/read ticks | `MessageStatusSlotProps` |
|
|
963
|
-
| `MessageAttachments` | Files/images in bubble | `MessageAttachmentsSlotProps` |
|
|
964
|
-
| `MessageReactions` | Emoji chips | `MessageReactionsSlotProps` |
|
|
965
|
-
| `MessageReplySnippet` | Quoted reply in bubble | `MessageReplySnippetSlotProps` |
|
|
966
|
-
| `ChatThemeToggle` | Light/dark toggle | `{ className?: string }` |
|
|
967
|
-
| `ChatDateTimeSettings` | Date/time settings button | `Record<string, never>` |
|
|
968
|
-
| `ChatSocketStatus` | Connection indicator | `{ className?: string }` |
|
|
969
|
-
|
|
970
|
-
### Code examples for common slots
|
|
971
|
-
|
|
972
|
-
**MembersDrawer** (full custom drawer — Elstar-style)
|
|
973
|
-
|
|
974
|
-
```tsx
|
|
975
|
-
import { useChatStore, type MembersDrawerSlotProps } from "@realtimexsco/live-chat";
|
|
976
|
-
|
|
977
|
-
const MyMembersDrawer = ({
|
|
978
|
-
isOpen,
|
|
979
|
-
onOpenChange,
|
|
980
|
-
conversationId,
|
|
981
|
-
conversationInfo,
|
|
982
|
-
}: MembersDrawerSlotProps) => {
|
|
983
|
-
const manageGroupMembers = useChatStore((s) => s.manageGroupMembers);
|
|
984
|
-
const participants = conversationInfo?.participants ?? [];
|
|
985
|
-
|
|
986
|
-
if (!isOpen) return null;
|
|
987
|
-
|
|
988
|
-
return (
|
|
989
|
-
<aside className="members-drawer">
|
|
990
|
-
<header>
|
|
991
|
-
<h2>Members ({participants.length})</h2>
|
|
992
|
-
<button type="button" onClick={() => onOpenChange(false)}>Close</button>
|
|
993
|
-
</header>
|
|
994
|
-
<ul>
|
|
995
|
-
{participants.map((p, i) => {
|
|
996
|
-
const id = typeof p === "string" ? p : p._id;
|
|
997
|
-
const name = typeof p === "string" ? "User" : p.name;
|
|
998
|
-
return <li key={`${id}-${i}`}>{name}</li>;
|
|
999
|
-
})}
|
|
1000
|
-
</ul>
|
|
1001
|
-
</aside>
|
|
1002
|
-
);
|
|
1003
|
-
};
|
|
1004
|
-
```
|
|
1005
|
-
|
|
1006
|
-
**ChannelDetailsDrawer**
|
|
1007
|
-
|
|
1008
|
-
```tsx
|
|
1009
|
-
import type { ChannelDetailsDrawerSlotProps } from "@realtimexsco/live-chat";
|
|
1010
|
-
|
|
1011
|
-
const MyDetailsDrawer = ({ isOpen, onOpenChange, activeChannel, conversationInfo }: ChannelDetailsDrawerSlotProps) => (
|
|
1012
|
-
<dialog open={isOpen} onClose={() => onOpenChange(false)}>
|
|
1013
|
-
<h2>{activeChannel.name}</h2>
|
|
1014
|
-
<p>{conversationInfo?.groupDescription ?? "Direct message"}</p>
|
|
1015
|
-
</dialog>
|
|
1016
|
-
);
|
|
1017
|
-
```
|
|
1018
|
-
|
|
1019
|
-
**Avatar**
|
|
1020
|
-
|
|
1021
|
-
```tsx
|
|
1022
|
-
import type { AvatarSlotProps } from "@realtimexsco/live-chat";
|
|
1023
|
-
|
|
1024
|
-
const MyAvatar = ({ src, name, size = "md", isOnline, showOnline }: AvatarSlotProps) => (
|
|
1025
|
-
<div className="relative">
|
|
1026
|
-
<img src={src || undefined} alt={name} className={`avatar avatar--${size}`} />
|
|
1027
|
-
{showOnline && isOnline && <span className="online-dot" />}
|
|
1028
|
-
</div>
|
|
1029
|
-
);
|
|
1030
|
-
```
|
|
1031
|
-
|
|
1032
|
-
**MessageItem** (custom bubble)
|
|
1033
|
-
|
|
1034
|
-
```tsx
|
|
1035
|
-
import type { MessageItemSlotProps } from "@realtimexsco/live-chat";
|
|
1036
|
-
|
|
1037
|
-
const MyMessageItem = ({ isSender, message, createdAt }: MessageItemSlotProps) => (
|
|
1038
|
-
<div className={isSender ? "text-right" : "text-left"}>
|
|
1039
|
-
<div className={isSender ? "bubble-sent" : "bubble-received"}>{message}</div>
|
|
1040
|
-
<time className="text-xs opacity-60">{createdAt}</time>
|
|
1041
|
-
</div>
|
|
1042
|
-
);
|
|
1043
|
-
```
|
|
1044
|
-
|
|
1045
|
-
**ChannelListItem**
|
|
1046
|
-
|
|
1047
|
-
```tsx
|
|
1048
|
-
import type { ChannelListItemSlotProps } from "@realtimexsco/live-chat";
|
|
1049
|
-
|
|
1050
|
-
const MyRow = ({ channel, isActive, onSelect }: ChannelListItemSlotProps) => (
|
|
1051
|
-
<button
|
|
1052
|
-
type="button"
|
|
1053
|
-
className={isActive ? "row-active" : "row"}
|
|
1054
|
-
onClick={() => onSelect(channel)}
|
|
1055
|
-
>
|
|
1056
|
-
{channel.name}
|
|
1057
|
-
{channel.unreadCount ? ` (${channel.unreadCount})` : ""}
|
|
1058
|
-
</button>
|
|
1059
|
-
);
|
|
1060
|
-
```
|
|
1061
|
-
|
|
1062
|
-
**MessageInput**
|
|
1063
|
-
|
|
1064
|
-
```tsx
|
|
1065
|
-
import type { ChannelMessageBoxSlotProps } from "@realtimexsco/live-chat";
|
|
1066
|
-
|
|
1067
|
-
const MyInput = ({ onSendMessage, replyTo, onCancelReply }: ChannelMessageBoxSlotProps) => {
|
|
1068
|
-
const [text, setText] = useState("");
|
|
1069
|
-
return (
|
|
1070
|
-
<div>
|
|
1071
|
-
{replyTo && <button type="button" onClick={onCancelReply}>Cancel reply</button>}
|
|
1072
|
-
<input value={text} onChange={(e) => setText(e.target.value)} />
|
|
1073
|
-
<button type="button" onClick={() => { onSendMessage?.(text, [], replyTo); setText(""); }}>
|
|
1074
|
-
Send
|
|
1075
|
-
</button>
|
|
1076
|
-
</div>
|
|
1077
|
-
);
|
|
1078
|
-
};
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
---
|
|
1082
|
-
|
|
1083
|
-
## All classNames keys
|
|
1084
|
-
|
|
1085
|
-
Merged with package defaults — your classes extend styling without replacing components.
|
|
1086
|
-
|
|
1087
|
-
| Key | UI region |
|
|
1088
|
-
|-----|-----------|
|
|
1089
|
-
| `shell` | Outermost chat wrapper |
|
|
1090
|
-
| `mainPanel` | Inner rounded panel |
|
|
1091
|
-
| `sidebar` | Left sidebar |
|
|
1092
|
-
| `loggedUserDetails` | Profile block at top |
|
|
1093
|
-
| `channelList` | Conversation list container |
|
|
1094
|
-
| `channelListItem` | Each conversation row |
|
|
1095
|
-
| `channelListItemActive` | Selected conversation row |
|
|
1096
|
-
| `channelHeader` | Header bar |
|
|
1097
|
-
| `headerLeft` | Header left section |
|
|
1098
|
-
| `headerRight` | Header right section |
|
|
1099
|
-
| `headerCallActions` | Call buttons wrapper |
|
|
1100
|
-
| `phoneCallButton` | Phone button |
|
|
1101
|
-
| `videoCallButton` | Video button |
|
|
1102
|
-
| `messageList` | Messages scroll area |
|
|
1103
|
-
| `messageItem` | Message row wrapper |
|
|
1104
|
-
| `messageBubble` | Bubble (both sides) |
|
|
1105
|
-
| `messageBubbleSender` | Outgoing bubble |
|
|
1106
|
-
| `messageBubbleReceiver` | Incoming bubble |
|
|
1107
|
-
| `messageInput` | Composer container |
|
|
1108
|
-
| `messageInputTextarea` | Textarea element |
|
|
1109
|
-
| `avatar` | Avatar wrapper |
|
|
1110
|
-
| `avatarFallback` | Initials fallback |
|
|
1111
|
-
| `dateDivider` | "Today" / date separator |
|
|
1112
|
-
| `emptyState` | No messages placeholder |
|
|
1113
|
-
| `forwardModal` | Forward dialog |
|
|
1114
|
-
| `chatPanelAlerts` | Error/info alert bar |
|
|
1115
|
-
| `drawer` | Drawer overlay/shell |
|
|
1116
|
-
| `drawerContent` | Drawer panel body |
|
|
1117
|
-
| `searchOverlay` | In-header search results |
|
|
1118
|
-
|
|
1119
|
-
```tsx
|
|
1120
|
-
classNames={{
|
|
1121
|
-
shell: "chat-container-root",
|
|
1122
|
-
channelListItemActive: "bg-indigo-50 dark:bg-indigo-500/10",
|
|
1123
|
-
messageBubbleSender: "rounded-2xl shadow-sm",
|
|
1124
|
-
messageBubbleReceiver: "rounded-2xl",
|
|
1125
|
-
drawer: "z-[60]",
|
|
1126
|
-
}}
|
|
1127
|
-
```
|
|
1128
|
-
|
|
1129
|
-
---
|
|
1130
|
-
|
|
1131
|
-
## Wrapping package defaults (`packageDefaultComponents`)
|
|
1132
|
-
|
|
1133
|
-
The package exports every built-in slot component so you can wrap defaults with your theme instead of rebuilding from scratch.
|
|
1134
|
-
|
|
1135
|
-
```tsx
|
|
1136
|
-
import {
|
|
1137
|
-
packageDefaultComponents,
|
|
1138
|
-
type ChatComponents,
|
|
1139
|
-
} from "@realtimexsco/live-chat";
|
|
1140
|
-
|
|
1141
|
-
function withTheme<P extends object>(
|
|
1142
|
-
Default: React.ComponentType<P>,
|
|
1143
|
-
className: string
|
|
1144
|
-
): React.ComponentType<P> {
|
|
1145
|
-
return (props) => (
|
|
1146
|
-
<div className={className}>
|
|
1147
|
-
<Default {...props} />
|
|
1148
|
-
</div>
|
|
1149
|
-
);
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
const components: ChatComponents = {
|
|
1153
|
-
MessageItem: withTheme(packageDefaultComponents.MessageItem!, "my-message"),
|
|
1154
|
-
ChannelListItem: withTheme(packageDefaultComponents.ChannelListItem!, "my-row"),
|
|
1155
|
-
Avatar: MyFullyCustomAvatar, // or use DefaultChatAvatar from package
|
|
1156
|
-
};
|
|
1157
|
-
```
|
|
1158
|
-
|
|
1159
|
-
Also exported for reference:
|
|
1160
|
-
|
|
1161
|
-
- `packageDefaultComponents` — map of all slot defaults
|
|
1162
|
-
- `DefaultChatAvatar` — inner avatar (use when customizing `Avatar` slot)
|
|
1163
|
-
- `DefaultChannelListItem` — inner list row (use when customizing `ChannelListItem` slot)
|
|
1164
|
-
|
|
1165
|
-
---
|
|
1166
|
-
|
|
1167
|
-
## ChatMain props reference
|
|
1168
|
-
|
|
1169
|
-
| Prop | Type | Default | Description |
|
|
1170
|
-
|------|------|---------|-------------|
|
|
1171
|
-
| `clientId` | `string` | — | **Required.** Tenant / client id |
|
|
1172
|
-
| `accessToken` | `string` | — | **Required.** JWT access token |
|
|
1173
|
-
| `loggedUserDetails` | `object` | — | **Required.** `{ _id, name, email }` — `_id` must match JWT |
|
|
1174
|
-
| `apiUrl` | `string` | — | **Required.** REST API ending with `/api/v1` (pass from your env/config) |
|
|
1175
|
-
| `socketUrl` | `string` | derived | Optional socket host (no `/api/v1`). Defaults to `apiUrl` without `/api/v1` |
|
|
1176
|
-
| `viewportHeight` | `"full" \| "screen" \| string` | `"full"` | Chat root height. Use `"screen"` for full page, or `"calc(100dvh - 4rem)"` below fixed header |
|
|
1177
|
-
| `viewportClassName` | `string` | — | Extra classes on the built-in viewport wrapper |
|
|
1178
|
-
| `colorMode` | `"light" \| "dark"` | — | Controlled light/dark (use with your app theme) |
|
|
1179
|
-
| `defaultColorMode` | `"light" \| "dark"` | `"light"` | Initial mode when uncontrolled |
|
|
1180
|
-
| `onColorModeChange` | `(mode) => void` | — | Called when theme changes |
|
|
1181
|
-
| `showColorModeToggle` | `boolean` | `true` | Show built-in light/dark toggle |
|
|
1182
|
-
| `locale` | `string` | browser | BCP 47 locale, e.g. `"en-US"` |
|
|
1183
|
-
| `timeZone` | `string` | browser | IANA timezone, e.g. `"Asia/Kolkata"` |
|
|
1184
|
-
| `hour12` | `boolean` | locale | `true` = 12-hour clock |
|
|
1185
|
-
| `defaultLocale` | `string` | — | Initial locale when uncontrolled |
|
|
1186
|
-
| `defaultTimeZone` | `string` | — | Initial timezone when uncontrolled |
|
|
1187
|
-
| `defaultHour12` | `boolean` | — | Initial 12/24h when uncontrolled |
|
|
1188
|
-
| `onDateTimePreferencesChange` | `(prefs) => void` | — | User changed date/time settings |
|
|
1189
|
-
| `showDateTimeSettings` | `boolean` | `true` | Show in-panel date/time button |
|
|
1190
|
-
| `layout` | `ChatLayoutConfig` | all `true` | Toggle UI sections |
|
|
1191
|
-
| `components` | `ChatComponents` | — | Replace UI components (Case 1 & 2) |
|
|
1192
|
-
| `classNames` | `ChatClassNames` | — | Per-region CSS classes (Case 3) |
|
|
1193
|
-
| `features` | `ChatFeatures` | — | Phone/video call flags & callbacks |
|
|
1194
|
-
| `uiConfig` | `UIConfig` | — | Advanced: merged with `components` / `classNames` / `features` |
|
|
1195
|
-
| `error` | `string \| null` | — | Error message in alert bar |
|
|
1196
|
-
| `info` | `string \| null` | — | Info message in alert bar |
|
|
1197
|
-
| `onErrorDismiss` | `() => void` | — | Dismiss error |
|
|
1198
|
-
| `onInfoDismiss` | `() => void` | — | Dismiss info |
|
|
1199
|
-
|
|
1200
|
-
---
|
|
1201
|
-
|
|
1202
|
-
## Chat provider (composable mode)
|
|
1203
|
-
|
|
1204
|
-
Use `Chat` + `ChatLayout` when you need a custom page wrapper but not a full `ChatMain` replacement.
|
|
1205
|
-
|
|
1206
|
-
```tsx
|
|
1207
|
-
"use client";
|
|
1208
|
-
|
|
1209
|
-
import { Chat, ChatLayout, type ChatComponents } from "@realtimexsco/live-chat";
|
|
1210
|
-
import { chatConfig } from "@/configs/chat.config";
|
|
1211
|
-
|
|
1212
|
-
const components: ChatComponents = {
|
|
1213
|
-
Avatar: MyAvatar,
|
|
1214
|
-
};
|
|
1215
|
-
|
|
1216
|
-
export default function ChatPage() {
|
|
1217
|
-
return (
|
|
1218
|
-
<div className="h-dvh min-h-0 overflow-hidden">
|
|
1219
|
-
<Chat
|
|
1220
|
-
client={{ id: chatConfig.clientId }}
|
|
1221
|
-
accessToken={chatConfig.accessToken}
|
|
1222
|
-
loggedUserDetails={chatConfig.loggedUserDetails}
|
|
1223
|
-
apiUrl={chatConfig.apiUrl}
|
|
1224
|
-
socketUrl={chatConfig.socketUrl}
|
|
1225
|
-
themeColor={chatConfig.themeColor}
|
|
1226
|
-
uiConfig={{
|
|
1227
|
-
components,
|
|
1228
|
-
classNames: { sidebar: "bg-slate-900" },
|
|
1229
|
-
features: {
|
|
1230
|
-
onPhoneCall: (ctx) => console.log("call", ctx),
|
|
1231
|
-
},
|
|
1232
|
-
}}
|
|
1233
|
-
>
|
|
1234
|
-
<ChatLayout themeColor={chatConfig.themeColor} />
|
|
1235
|
-
</Chat>
|
|
1236
|
-
</div>
|
|
1237
|
-
);
|
|
1238
|
-
}
|
|
1239
|
-
```
|
|
1240
|
-
|
|
1241
|
-
### `Chat` provider props
|
|
1242
|
-
|
|
1243
|
-
| Prop | Type | Required | Description |
|
|
1244
|
-
|------|------|----------|-------------|
|
|
1245
|
-
| `client` | `{ id: string }` | Yes | Client id |
|
|
1246
|
-
| `accessToken` | `string` | Yes | JWT |
|
|
1247
|
-
| `loggedUserDetails` | `object` | Yes | User profile |
|
|
1248
|
-
| `apiUrl` | `string` | No | REST base URL |
|
|
1249
|
-
| `socketUrl` | `string` | No | Socket host |
|
|
1250
|
-
| `themeColor` | `string` | No | Accent color |
|
|
1251
|
-
| `uiConfig` | `UIConfig` | No | `components`, `classNames`, `features` |
|
|
1252
|
-
| `onMessageReceived` | `(msg) => void` | No | Background message callback |
|
|
1253
|
-
| `onSocketConnected` | `(id) => void` | No | Socket connected |
|
|
1254
|
-
| `onSocketError` | `(err) => void` | No | Socket error |
|
|
1255
|
-
| `children` | `ReactNode` | Yes | Usually `<ChatLayout />` |
|
|
1256
|
-
|
|
1257
|
-
---
|
|
1258
|
-
|
|
1259
|
-
## Hooks & store
|
|
1260
|
-
|
|
1261
|
-
| Hook / export | Purpose |
|
|
1262
|
-
|---------------|---------|
|
|
1263
|
-
| `useChatController()` | State + handlers inside custom `ChatLayout` (Case 1) |
|
|
1264
|
-
| `useChatStore()` | Zustand store — messages, conversations, socket actions |
|
|
1265
|
-
| `useChatCustomization()` | Current `components` / `classNames` inside custom children |
|
|
1266
|
-
| `useChatFeatures()` | Phone/video flags and callbacks |
|
|
1267
|
-
| `useChatTheme()` | `themeColor`, `isDark`, CSS variables |
|
|
1268
|
-
| `useChatLocale()` | Format dates/times with current locale |
|
|
1269
|
-
| `useChatAlerts()` | Error/info alert state |
|
|
1270
|
-
| `useChatContext()` | Low-level chat provider context |
|
|
1271
|
-
|
|
1272
|
-
```tsx
|
|
1273
|
-
import { useChatStore } from "@realtimexsco/live-chat";
|
|
1274
|
-
|
|
1275
|
-
const conversations = useChatStore((s) => s.conversations);
|
|
1276
|
-
const emitDmSend = useChatStore((s) => s.emitDmSend);
|
|
1277
|
-
```
|
|
1278
|
-
|
|
1279
|
-
---
|
|
1280
|
-
|
|
1281
|
-
## React (Vite) — full setup
|
|
1282
|
-
|
|
1283
|
-
### 1. Create project
|
|
1284
|
-
|
|
1285
|
-
```bash
|
|
1286
|
-
pnpm create vite my-chat-app --template react-ts
|
|
1287
|
-
cd my-chat-app
|
|
1288
|
-
```
|
|
1289
|
-
|
|
1290
|
-
### 2. Install
|
|
1291
|
-
|
|
1292
|
-
```bash
|
|
1293
|
-
pnpm add @realtimexsco/live-chat react react-dom zustand tailwindcss
|
|
1294
|
-
pnpm add -D @tailwindcss/vite @vitejs/plugin-react
|
|
1295
|
-
```
|
|
1296
|
-
|
|
1297
|
-
### 3. File structure
|
|
1298
|
-
|
|
1299
|
-
```
|
|
1300
|
-
src/
|
|
1301
|
-
├── main.tsx
|
|
1302
|
-
├── App.tsx
|
|
1303
|
-
├── index.css ← Tailwind + package CSS (see above)
|
|
1304
|
-
└── configs/
|
|
1305
|
-
└── chat.config.ts
|
|
1306
|
-
```
|
|
1307
|
-
|
|
1308
|
-
### 4. `src/main.tsx`
|
|
1309
|
-
|
|
1310
|
-
```tsx
|
|
1311
|
-
import { createRoot } from "react-dom/client";
|
|
1312
|
-
import "./index.css";
|
|
1313
|
-
import App from "./App";
|
|
1314
|
-
|
|
1315
|
-
createRoot(document.getElementById("root")!).render(<App />);
|
|
1316
|
-
```
|
|
1317
|
-
|
|
1318
|
-
### 5. `src/App.tsx`
|
|
1319
|
-
|
|
1320
|
-
```tsx
|
|
1321
|
-
import ChatMain from "@realtimexsco/live-chat";
|
|
1322
|
-
import { chatConfig } from "./configs/chat.config";
|
|
1323
|
-
|
|
1324
|
-
export default function App() {
|
|
1325
|
-
return (
|
|
1326
|
-
<div className="h-dvh min-h-0 overflow-hidden">
|
|
1327
|
-
<ChatMain
|
|
1328
|
-
clientId={chatConfig.clientId}
|
|
1329
|
-
accessToken={chatConfig.accessToken}
|
|
1330
|
-
loggedUserDetails={chatConfig.loggedUserDetails}
|
|
1331
|
-
apiUrl={chatConfig.apiUrl}
|
|
1332
|
-
socketUrl={chatConfig.socketUrl}
|
|
1333
|
-
themeColor={chatConfig.themeColor}
|
|
1334
|
-
/>
|
|
1335
|
-
</div>
|
|
1336
|
-
);
|
|
1337
|
-
}
|
|
1338
|
-
```
|
|
1339
|
-
|
|
1340
|
-
### 6. Run
|
|
1341
|
-
|
|
1342
|
-
```bash
|
|
1343
|
-
pnpm dev
|
|
1344
|
-
```
|
|
26
|
+
**Vite:** `npm i -D @tailwindcss/vite` · **Next.js:** `npm i -D @tailwindcss/postcss`
|
|
1345
27
|
|
|
1346
28
|
---
|
|
1347
29
|
|
|
1348
|
-
##
|
|
1349
|
-
|
|
1350
|
-
### 1. Create project
|
|
1351
|
-
|
|
1352
|
-
```bash
|
|
1353
|
-
pnpm create next-app@latest my-chat-app --typescript --tailwind --app --src-dir
|
|
1354
|
-
cd my-chat-app
|
|
1355
|
-
```
|
|
1356
|
-
|
|
1357
|
-
### 2. Install
|
|
30
|
+
## Quick start
|
|
1358
31
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
```
|
|
1363
|
-
|
|
1364
|
-
### 3. `src/app/chat/page.tsx`
|
|
32
|
+
1. Import CSS — `@import "@realtimexsco/live-chat/styles.css"` and add Tailwind `@source` for the package `dist` files.
|
|
33
|
+
2. Create `chat.config.ts` with `clientId`, `accessToken`, `loggedUserDetails`, `apiUrl`, `socketUrl`.
|
|
34
|
+
3. Render `<ChatMain {...chatConfig} />`.
|
|
1365
35
|
|
|
1366
36
|
```tsx
|
|
1367
|
-
"use client";
|
|
1368
|
-
|
|
1369
37
|
import ChatMain from "@realtimexsco/live-chat";
|
|
1370
38
|
import { chatConfig } from "@/configs/chat.config";
|
|
1371
39
|
|
|
1372
40
|
export default function ChatPage() {
|
|
1373
41
|
return (
|
|
1374
42
|
<div className="h-dvh min-h-0 overflow-hidden">
|
|
1375
|
-
<ChatMain
|
|
1376
|
-
clientId={chatConfig.clientId}
|
|
1377
|
-
accessToken={chatConfig.accessToken}
|
|
1378
|
-
loggedUserDetails={chatConfig.loggedUserDetails}
|
|
1379
|
-
apiUrl={chatConfig.apiUrl}
|
|
1380
|
-
socketUrl={chatConfig.socketUrl}
|
|
1381
|
-
themeColor={chatConfig.themeColor}
|
|
1382
|
-
/>
|
|
43
|
+
<ChatMain {...chatConfig} viewportHeight="screen" />
|
|
1383
44
|
</div>
|
|
1384
45
|
);
|
|
1385
46
|
}
|
|
1386
47
|
```
|
|
1387
48
|
|
|
1388
|
-
### 4. Run
|
|
1389
|
-
|
|
1390
|
-
```bash
|
|
1391
|
-
pnpm dev
|
|
1392
|
-
```
|
|
1393
|
-
|
|
1394
|
-
Open `http://localhost:3000/chat`
|
|
1395
|
-
|
|
1396
|
-
---
|
|
1397
|
-
|
|
1398
|
-
## Environment variables
|
|
1399
|
-
|
|
1400
|
-
Optional — use in `chat.config.ts`:
|
|
1401
|
-
|
|
1402
|
-
```env
|
|
1403
|
-
# .env.local (Next.js) or .env (Vite with VITE_ prefix)
|
|
1404
|
-
NEXT_PUBLIC_CHAT_CLIENT_ID=your-client-id
|
|
1405
|
-
NEXT_PUBLIC_API_V1_BASE_URL=https://realtimex.softwareco.com/api/v1
|
|
1406
|
-
NEXT_PUBLIC_SOCKET_URL=https://realtimex.softwareco.com
|
|
1407
|
-
```
|
|
1408
|
-
|
|
1409
|
-
```ts
|
|
1410
|
-
export const chatConfig = {
|
|
1411
|
-
clientId: process.env.NEXT_PUBLIC_CHAT_CLIENT_ID ?? "",
|
|
1412
|
-
accessToken: "YOUR_JWT_ACCESS_TOKEN",
|
|
1413
|
-
apiUrl: process.env.NEXT_PUBLIC_API_V1_BASE_URL ?? "",
|
|
1414
|
-
socketUrl:
|
|
1415
|
-
process.env.NEXT_PUBLIC_SOCKET_URL ??
|
|
1416
|
-
(process.env.NEXT_PUBLIC_API_V1_BASE_URL ?? "").replace(/\/api\/v1\/?$/, ""),
|
|
1417
|
-
// ...
|
|
1418
|
-
};
|
|
1419
|
-
```
|
|
1420
|
-
|
|
1421
|
-
Vite uses `import.meta.env.VITE_*` instead of `NEXT_PUBLIC_*`.
|
|
1422
|
-
|
|
1423
|
-
---
|
|
1424
|
-
|
|
1425
|
-
## Dev proxy (CORS)
|
|
1426
|
-
|
|
1427
|
-
If the API blocks browser requests during local dev, proxy through your dev server.
|
|
1428
|
-
|
|
1429
|
-
**Vite `vite.config.ts`:**
|
|
1430
|
-
|
|
1431
|
-
```ts
|
|
1432
|
-
server: {
|
|
1433
|
-
proxy: {
|
|
1434
|
-
"/chat-api": {
|
|
1435
|
-
target: "https://YOUR_API_HOST",
|
|
1436
|
-
changeOrigin: true,
|
|
1437
|
-
rewrite: (path) => path.replace(/^\/chat-api/, "/api/v1"),
|
|
1438
|
-
},
|
|
1439
|
-
},
|
|
1440
|
-
},
|
|
1441
|
-
```
|
|
1442
|
-
|
|
1443
|
-
Then set `apiUrl: "/chat-api"` in `chat.config.ts` for local development.
|
|
1444
|
-
|
|
1445
|
-
---
|
|
1446
|
-
|
|
1447
|
-
## Architecture
|
|
1448
|
-
|
|
1449
|
-
```
|
|
1450
|
-
ChatMain
|
|
1451
|
-
├── ChatThemeProvider (themeColor, light/dark)
|
|
1452
|
-
├── ChatLocaleProvider (locale, timezone, hour12)
|
|
1453
|
-
├── Chat
|
|
1454
|
-
│ ├── Auth + REST API + Socket.IO + Zustand store
|
|
1455
|
-
│ └── ChatCustomizationProvider (components, classNames, features)
|
|
1456
|
-
│ └── ChatLayout (resolveComponent → DefaultChatLayout or custom)
|
|
1457
|
-
│ ├── Sidebar: LoggedUserDetails + ChannelList
|
|
1458
|
-
│ └── Main: ChannelHeader + MessageList + MessageInput
|
|
1459
|
-
│ └── ChannelHeaderView
|
|
1460
|
-
│ ├── resolveComponent → drawers (Members, Details, …)
|
|
1461
|
-
│ └── resolveComponent → modals (Clear, Delete, Block)
|
|
1462
|
-
└── ChatAlertsProvider (error / info banner)
|
|
1463
|
-
```
|
|
1464
|
-
|
|
1465
|
-
**Customization flow:**
|
|
1466
|
-
|
|
1467
|
-
1. You pass `components` / `classNames` / `features` on `ChatMain`.
|
|
1468
|
-
2. `ChatCustomizationProvider` merges your config (unset slots stay empty).
|
|
1469
|
-
3. Each render site calls `resolveComponent(slot, PackageDefault)` — custom wins, else default.
|
|
1470
|
-
4. No `components` prop → every slot uses package defaults (full default chat UI).
|
|
1471
|
-
|
|
1472
|
-
**Runtime flow:**
|
|
1473
|
-
|
|
1474
|
-
1. `ChatMain` runs client-user login, sets JWT, connects socket.
|
|
1475
|
-
2. User picks a conversation → messages fetch + socket room join.
|
|
1476
|
-
3. Send is optimistic — message appears immediately, reconciles on server ack.
|
|
1477
|
-
4. Socket events update Zustand → UI re-renders automatically.
|
|
1478
|
-
|
|
1479
|
-
---
|
|
1480
|
-
|
|
1481
|
-
## All exports
|
|
1482
|
-
|
|
1483
|
-
```ts
|
|
1484
|
-
import ChatMain, {
|
|
1485
|
-
// ── Providers & layout ──
|
|
1486
|
-
Chat,
|
|
1487
|
-
ChatLayout,
|
|
1488
|
-
DefaultChatLayout,
|
|
1489
|
-
Channel,
|
|
1490
|
-
ChatThemeProvider,
|
|
1491
|
-
ChatLocaleProvider,
|
|
1492
|
-
ChatAlertsProvider,
|
|
1493
|
-
ChatCustomizationProvider,
|
|
1494
|
-
|
|
1495
|
-
// ── UI components (standalone or customization reference) ──
|
|
1496
|
-
ChannelList,
|
|
1497
|
-
ChannelHeader,
|
|
1498
|
-
MessageList,
|
|
1499
|
-
MessageInput,
|
|
1500
|
-
LoggedUserDetails,
|
|
1501
|
-
ForwardModal,
|
|
1502
|
-
MessageItem,
|
|
1503
|
-
ChatAvatar,
|
|
1504
|
-
DefaultChatAvatar,
|
|
1505
|
-
ChannelListItem,
|
|
1506
|
-
DefaultChannelListItem,
|
|
1507
|
-
HeaderCallActions,
|
|
1508
|
-
packageDefaultComponents,
|
|
1509
|
-
|
|
1510
|
-
// ── Hooks ──
|
|
1511
|
-
useChatStore,
|
|
1512
|
-
useChatController,
|
|
1513
|
-
useChatContext,
|
|
1514
|
-
useChatCustomization,
|
|
1515
|
-
useChatCustomizationOptional,
|
|
1516
|
-
useChatFeatures,
|
|
1517
|
-
useChatFeaturesOptional,
|
|
1518
|
-
useChatTheme,
|
|
1519
|
-
useChatLocale,
|
|
1520
|
-
useChatAlerts,
|
|
1521
|
-
|
|
1522
|
-
// ── Layout helpers ──
|
|
1523
|
-
mergeChatLayoutConfig,
|
|
1524
|
-
defaultChatLayoutConfig,
|
|
1525
|
-
mergeChatCustomization,
|
|
1526
|
-
defaultChatClassNames,
|
|
1527
|
-
defaultChatComponents,
|
|
1528
|
-
defaultChatFeatures,
|
|
1529
|
-
|
|
1530
|
-
// ── API / socket helpers ──
|
|
1531
|
-
setChatClientId,
|
|
1532
|
-
setChatAccessToken,
|
|
1533
|
-
setChatBaseURL,
|
|
1534
|
-
socketService,
|
|
1535
|
-
getSocketConfig,
|
|
1536
|
-
showNotification,
|
|
1537
|
-
downloadFile,
|
|
1538
|
-
|
|
1539
|
-
// ── Types ──
|
|
1540
|
-
type ChatComponents,
|
|
1541
|
-
type ChatClassNames,
|
|
1542
|
-
type ChatFeatures,
|
|
1543
|
-
type ChatCallContext,
|
|
1544
|
-
type ChatLayoutConfig,
|
|
1545
|
-
type ChatColorMode,
|
|
1546
|
-
type ChatCustomizationConfig,
|
|
1547
|
-
type UIConfig,
|
|
1548
|
-
type IChannel,
|
|
1549
|
-
type IMessage,
|
|
1550
|
-
type IAttachment,
|
|
1551
|
-
type AvatarSlotProps,
|
|
1552
|
-
type MessageItemSlotProps,
|
|
1553
|
-
type ChannelHeaderSlotProps,
|
|
1554
|
-
type ChannelListItemSlotProps,
|
|
1555
|
-
type ChatLayoutSlotProps,
|
|
1556
|
-
type HeaderCallActionsSlotProps,
|
|
1557
|
-
type PhoneCallButtonSlotProps,
|
|
1558
|
-
type VideoCallButtonSlotProps,
|
|
1559
|
-
type ActiveChannelMessagesSlotProps,
|
|
1560
|
-
type ChannelMessageBoxSlotProps,
|
|
1561
|
-
type ForwardModalSlotProps,
|
|
1562
|
-
type MembersDrawerSlotProps,
|
|
1563
|
-
// … all *SlotProps types are exported
|
|
1564
|
-
} from "@realtimexsco/live-chat";
|
|
1565
|
-
```
|
|
1566
|
-
|
|
1567
|
-
**CSS import (not from JS):**
|
|
1568
|
-
|
|
1569
|
-
```css
|
|
1570
|
-
@import "@realtimexsco/live-chat/styles.css";
|
|
1571
|
-
```
|
|
1572
|
-
|
|
1573
|
-
---
|
|
1574
|
-
|
|
1575
|
-
## Troubleshooting
|
|
1576
|
-
|
|
1577
|
-
| Problem | Cause | Fix |
|
|
1578
|
-
|---------|-------|-----|
|
|
1579
|
-
| Unstyled / broken UI | Missing Tailwind `@source` | Add `@source` to package `dist/index.mjs` and `dist/index.cjs` |
|
|
1580
|
-
| No styles at all | Missing `styles.css` import | `@import "@realtimexsco/live-chat/styles.css"` |
|
|
1581
|
-
| Wrong `@source` depth | Next.js vs Vite path | Use `../../node_modules` in `src/app/globals.css` |
|
|
1582
|
-
| TypeScript: no declaration file | Published tarball missing `dist/index.d.ts` | Reinstall latest version; verify `dist/index.d.ts` exists |
|
|
1583
|
-
| Next.js build error | Package not transpiled | `transpilePackages: ["@realtimexsco/live-chat"]` |
|
|
1584
|
-
| `use client` error | Server Component import | Add `"use client"` to chat page |
|
|
1585
|
-
| Whole page scrolls, not messages | Missing height chain | Set `viewportHeight="screen"` or `viewportHeight="calc(100dvh - 4rem)"` on `<ChatMain />` |
|
|
1586
|
-
| Messages don't load | Wrong credentials / CORS | Check `apiUrl`, JWT, proxy in dev |
|
|
1587
|
-
| Socket won't connect | Wrong `socketUrl` | No `/api/v1` on socket URL |
|
|
1588
|
-
| Duplicate React hooks error | Duplicate React copies | `dedupe: ["react", "react-dom"]` in Vite |
|
|
1589
|
-
| Sent message on **left** and **right** | `_id` mismatch or duplicate echo | Ensure `loggedUserDetails._id` matches JWT `_id` |
|
|
1590
|
-
| Custom layout has no data | Missing hook | Call `useChatController()` inside custom `ChatLayout` |
|
|
1591
|
-
| Custom `MembersDrawer` still shows package UI | Old package version (< 1.1.55) | Upgrade to **1.1.55+** — drawer slots now use `resolveComponent` |
|
|
1592
|
-
| Custom drawer works but other slots are default | Expected behavior | Only pass slots you want to override in `components` |
|
|
1593
|
-
| Passed `components` but slot unchanged | Slot not wired or parent replaced | See [Which slots are wired](#which-slots-are-wired); use `ChannelHeader` to replace all header drawers |
|
|
1594
|
-
| Custom `HeaderCallActions` crashes | Recursive import | Don't import package `HeaderCallActions` inside your slot |
|
|
1595
|
-
| Vite stale UI after upgrade | Cached prebundle | `rm -rf node_modules/.vite && pnpm dev` |
|
|
1596
|
-
| Rate limit banner | API returned 429 | Wait for cooldown; reduce rapid API calls in dev |
|
|
1597
|
-
|
|
1598
49
|
---
|
|
1599
50
|
|
|
1600
|
-
##
|
|
1601
|
-
|
|
1602
|
-
Copy this list when integrating into a new project:
|
|
51
|
+
## Features
|
|
1603
52
|
|
|
1604
|
-
|
|
1605
|
-
- [ ] `pnpm add @realtimexsco/live-chat react react-dom zustand tailwindcss`
|
|
1606
|
-
- [ ] Tailwind v4 plugin installed (`@tailwindcss/vite` or `@tailwindcss/postcss`)
|
|
1607
|
-
- [ ] `index.css` / `globals.css` imports `tailwindcss` + `@realtimexsco/live-chat/styles.css`
|
|
1608
|
-
- [ ] `@source` points to `dist/index.mjs` and `dist/index.cjs` (correct depth for your CSS path)
|
|
1609
|
-
- [ ] `:root` has `--chat-theme` and `--chat-theme-5` … `--chat-theme-60`
|
|
1610
|
-
- [ ] `@theme inline` maps `--color-chat-theme*` variables
|
|
1611
|
-
- [ ] `chat.config.ts` with real `clientId`, `accessToken`, `apiUrl`, `socketUrl`
|
|
1612
|
-
- [ ] `loggedUserDetails._id` matches JWT `_id`
|
|
1613
|
-
- [ ] Chat page wrapped in `h-dvh min-h-0 overflow-hidden`
|
|
1614
|
-
- [ ] Next.js: `"use client"` on chat page + `transpilePackages`
|
|
1615
|
-
- [ ] Vite: `optimizeDeps.exclude` includes `@realtimexsco/live-chat`
|
|
1616
|
-
- [ ] Optional: `components` for custom UI (Case 1 / 2)
|
|
1617
|
-
- [ ] Optional: `classNames` for theme tweaks (Case 3)
|
|
1618
|
-
- [ ] Optional: `features` for phone/video callbacks
|
|
1619
|
-
- [ ] Optional: `layout` to hide sections
|
|
1620
|
-
- [ ] Optional: `colorMode` synced with your app theme
|
|
1621
|
-
- [ ] Verify: `node_modules/@realtimexsco/live-chat/dist/index.d.ts` exists
|
|
1622
|
-
- [ ] Use package **≥ 1.1.56** for drawer customization + default fallback fixes
|
|
53
|
+
DMs · groups · Socket.IO · reactions · replies · forward · edit/delete · pin/star · attachments · search · typing · read receipts · light/dark · locale/timezone · full UI customization
|
|
1623
54
|
|
|
1624
55
|
---
|
|
1625
56
|
|
|
1626
|
-
##
|
|
1627
|
-
|
|
1628
|
-
This package is built from the **live-chat-frontend** reference app. Source lives in `src/`; published output is `dist/`.
|
|
1629
|
-
|
|
1630
|
-
### Sync from frontend
|
|
1631
|
-
|
|
1632
|
-
```bash
|
|
1633
|
-
cd chat-ui-package
|
|
1634
|
-
pnpm sync # copies app/chat → src/chat, patches API client & types, fixes imports
|
|
1635
|
-
pnpm build # tsup → dist/
|
|
1636
|
-
```
|
|
1637
|
-
|
|
1638
|
-
`scripts/sync-from-frontend.mjs` copies UI from the frontend repo. Protected files (not overwritten):
|
|
1639
|
-
|
|
1640
|
-
- `src/index.ts`, `ChatMain.tsx`, `ChatContext.tsx`, `DefaultChatLayout.tsx`
|
|
1641
|
-
- `src/chat/channel-header/ChannelHeaderView.tsx` (customization wiring)
|
|
1642
|
-
- Store/context entrypoints
|
|
1643
|
-
|
|
1644
|
-
After UI changes in **live-chat-frontend**, run `pnpm sync` then `pnpm build`, bump version, publish.
|
|
1645
|
-
|
|
1646
|
-
### Local install in consumer app (e.g. Elstar)
|
|
1647
|
-
|
|
1648
|
-
```bash
|
|
1649
|
-
cd chat-ui-package && pnpm pack --pack-destination .
|
|
1650
|
-
```
|
|
1651
|
-
|
|
1652
|
-
In consumer `package.json`:
|
|
1653
|
-
|
|
1654
|
-
```json
|
|
1655
|
-
"@realtimexsco/live-chat": "file:../path/to/realtimexsco-live-chat-1.1.0.tgz"
|
|
1656
|
-
```
|
|
1657
|
-
|
|
1658
|
-
Then `pnpm install` in the consumer app.
|
|
1659
|
-
|
|
1660
|
-
### Version history (customization)
|
|
57
|
+
## More information
|
|
1661
58
|
|
|
1662
|
-
|
|
|
1663
|
-
|
|
1664
|
-
|
|
|
1665
|
-
|
|
|
1666
|
-
|
|
|
59
|
+
| Topic | Link |
|
|
60
|
+
|-------|------|
|
|
61
|
+
| Full setup guide (Tailwind, Vite, Next.js, config) | [docs/full-guide.md](./docs/full-guide.md) |
|
|
62
|
+
| Customization (`components`, `classNames`, `features`) | [Customization](./docs/full-guide.md#customization--three-ways) |
|
|
63
|
+
| ChatMain props & API | [Props reference](./docs/full-guide.md#chatmain-props-reference) |
|
|
64
|
+
| Hooks & store | [Hooks & store](./docs/full-guide.md#hooks--store) |
|
|
65
|
+
| Dev proxy (CORS) | [Dev proxy](./docs/full-guide.md#dev-proxy-cors) |
|
|
66
|
+
| npm package | [npmjs.com/package/@realtimexsco/live-chat](https://www.npmjs.com/package/@realtimexsco/live-chat) |
|
|
67
|
+
| License | [MIT License](./LICENSE) |
|
|
1667
68
|
|
|
1668
69
|
---
|
|
1669
70
|
|
|
1670
71
|
## License
|
|
1671
72
|
|
|
1672
|
-
[MIT](LICENSE)
|
|
73
|
+
[MIT](./LICENSE) © RealtimeX
|