hermes-chat-react 0.1.2 → 0.1.4
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/dist/{chunk-OMLFDWYU.js → chunk-6L73MEPH.js} +16 -2
- package/dist/chunk-6L73MEPH.js.map +1 -0
- package/dist/cli.cjs +87 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +64 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +15 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/dist/react.cjs +1763 -522
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +624 -22
- package/dist/react.d.ts +624 -22
- package/dist/react.js +1657 -463
- package/dist/react.js.map +1 -1
- package/package.json +13 -3
- package/dist/chunk-OMLFDWYU.js.map +0 -1
package/dist/react.cjs
CHANGED
|
@@ -30,20 +30,53 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/react.ts
|
|
31
31
|
var react_exports = {};
|
|
32
32
|
__export(react_exports, {
|
|
33
|
+
Avatar: () => Avatar,
|
|
34
|
+
Chat: () => Chat,
|
|
35
|
+
ChatContext: () => ChatContext,
|
|
33
36
|
ChatInput: () => ChatInput,
|
|
37
|
+
ChatProvider: () => ChatProvider,
|
|
38
|
+
ComponentContext: () => ComponentContext,
|
|
39
|
+
ComponentProvider: () => ComponentProvider,
|
|
40
|
+
DateSeparator: () => DateSeparator,
|
|
41
|
+
EmptyStateIndicator: () => EmptyStateIndicator,
|
|
34
42
|
HermesClient: () => HermesClient,
|
|
43
|
+
LoadingErrorIndicator: () => LoadingErrorIndicator,
|
|
44
|
+
LoadingIndicator: () => LoadingIndicator,
|
|
35
45
|
MediaMessage: () => MediaMessage,
|
|
46
|
+
Message: () => Message,
|
|
47
|
+
MessageActions: () => MessageActions,
|
|
48
|
+
MessageContext: () => MessageContext,
|
|
36
49
|
MessageList: () => MessageList,
|
|
50
|
+
MessageProvider: () => MessageProvider,
|
|
51
|
+
MessageStatus: () => MessageStatus,
|
|
52
|
+
Modal: () => Modal,
|
|
37
53
|
OnlineBadge: () => OnlineBadge,
|
|
38
54
|
ReactionPicker: () => ReactionPicker,
|
|
55
|
+
Room: () => Room,
|
|
56
|
+
RoomActionContext: () => RoomActionContext,
|
|
57
|
+
RoomActionProvider: () => RoomActionProvider,
|
|
39
58
|
RoomList: () => RoomList,
|
|
40
|
-
|
|
59
|
+
RoomStateContext: () => RoomStateContext,
|
|
60
|
+
RoomStateProvider: () => RoomStateProvider,
|
|
61
|
+
Search: () => Search,
|
|
62
|
+
Thread: () => Thread,
|
|
63
|
+
ThreadHeader: () => ThreadHeader,
|
|
64
|
+
TypingContext: () => TypingContext,
|
|
65
|
+
TypingIndicator: () => TypingIndicator,
|
|
66
|
+
TypingProvider: () => TypingProvider,
|
|
67
|
+
Window: () => Window,
|
|
68
|
+
useChatContext: () => useChatContext,
|
|
69
|
+
useComponentContext: () => useComponentContext,
|
|
70
|
+
useMessageContext: () => useMessageContext,
|
|
41
71
|
useMessages: () => useMessages,
|
|
42
72
|
usePresence: () => usePresence,
|
|
43
73
|
useReactions: () => useReactions,
|
|
44
74
|
useReadReceipts: () => useReadReceipts,
|
|
75
|
+
useRoomActionContext: () => useRoomActionContext,
|
|
76
|
+
useRoomStateContext: () => useRoomStateContext,
|
|
45
77
|
useRooms: () => useRooms,
|
|
46
78
|
useTyping: () => useTyping,
|
|
79
|
+
useTypingContext: () => useTypingContext,
|
|
47
80
|
useUpload: () => useUpload
|
|
48
81
|
});
|
|
49
82
|
module.exports = __toCommonJS(react_exports);
|
|
@@ -125,7 +158,7 @@ var HermesClient = class extends EventEmitter {
|
|
|
125
158
|
apiKey: cfg.apiKey,
|
|
126
159
|
secret: cfg.secret,
|
|
127
160
|
userId: cfg.userId,
|
|
128
|
-
displayName: cfg.displayName
|
|
161
|
+
displayName: cfg.displayName,
|
|
129
162
|
avatar: cfg.avatar,
|
|
130
163
|
email: cfg.email
|
|
131
164
|
})
|
|
@@ -236,6 +269,20 @@ var HermesClient = class extends EventEmitter {
|
|
|
236
269
|
const res = await this._emit("room:list");
|
|
237
270
|
return res.rooms;
|
|
238
271
|
}
|
|
272
|
+
async getUsers() {
|
|
273
|
+
if (!this.token) throw new Error("Not connected");
|
|
274
|
+
const res = await fetch(`${this.config.endpoint}/hermes/users`, {
|
|
275
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
276
|
+
});
|
|
277
|
+
const data = await res.json();
|
|
278
|
+
if (!data.success) throw new Error(data.message || "Failed to fetch users");
|
|
279
|
+
return data.users.map((u) => ({
|
|
280
|
+
userId: u._id,
|
|
281
|
+
displayName: u.displayName,
|
|
282
|
+
avatar: u.avatar,
|
|
283
|
+
email: u.email
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
239
286
|
async addMember(roomId, newMemberId) {
|
|
240
287
|
await this._emit("room:member:add", { roomId, newMemberId });
|
|
241
288
|
}
|
|
@@ -278,17 +325,128 @@ var HermesClient = class extends EventEmitter {
|
|
|
278
325
|
}
|
|
279
326
|
};
|
|
280
327
|
|
|
281
|
-
// src/react/
|
|
328
|
+
// src/react/context/ChatContext.tsx
|
|
282
329
|
var import_react = require("react");
|
|
330
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
331
|
+
var ChatContext = (0, import_react.createContext)(
|
|
332
|
+
void 0
|
|
333
|
+
);
|
|
334
|
+
var ChatProvider = ({
|
|
335
|
+
children,
|
|
336
|
+
value
|
|
337
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatContext.Provider, { value, children });
|
|
338
|
+
var useChatContext = (componentName) => {
|
|
339
|
+
const contextValue = (0, import_react.useContext)(ChatContext);
|
|
340
|
+
if (!contextValue) {
|
|
341
|
+
console.warn(
|
|
342
|
+
`useChatContext was called outside of ChatProvider. Make sure this hook is called within a child of the <Chat> component.${componentName ? ` Errored in: ${componentName}` : ""}`
|
|
343
|
+
);
|
|
344
|
+
return {};
|
|
345
|
+
}
|
|
346
|
+
return contextValue;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// src/react/context/RoomStateContext.tsx
|
|
350
|
+
var import_react2 = require("react");
|
|
351
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
352
|
+
var RoomStateContext = (0, import_react2.createContext)(void 0);
|
|
353
|
+
var RoomStateProvider = ({
|
|
354
|
+
children,
|
|
355
|
+
value
|
|
356
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoomStateContext.Provider, { value, children });
|
|
357
|
+
var useRoomStateContext = (componentName) => {
|
|
358
|
+
const contextValue = (0, import_react2.useContext)(RoomStateContext);
|
|
359
|
+
if (!contextValue) {
|
|
360
|
+
console.warn(
|
|
361
|
+
`useRoomStateContext was called outside of RoomStateProvider. Make sure this hook is called within a child of the <Room> component.${componentName ? ` Errored in: ${componentName}` : ""}`
|
|
362
|
+
);
|
|
363
|
+
return {};
|
|
364
|
+
}
|
|
365
|
+
return contextValue;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// src/react/context/RoomActionContext.tsx
|
|
369
|
+
var import_react3 = require("react");
|
|
370
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
371
|
+
var RoomActionContext = (0, import_react3.createContext)(void 0);
|
|
372
|
+
var RoomActionProvider = ({
|
|
373
|
+
children,
|
|
374
|
+
value
|
|
375
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RoomActionContext.Provider, { value, children });
|
|
376
|
+
var useRoomActionContext = (componentName) => {
|
|
377
|
+
const contextValue = (0, import_react3.useContext)(RoomActionContext);
|
|
378
|
+
if (!contextValue) {
|
|
379
|
+
console.warn(
|
|
380
|
+
`useRoomActionContext was called outside of RoomActionProvider. Make sure this hook is called within a child of the <Room> component.${componentName ? ` Errored in: ${componentName}` : ""}`
|
|
381
|
+
);
|
|
382
|
+
return {};
|
|
383
|
+
}
|
|
384
|
+
return contextValue;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/react/context/MessageContext.tsx
|
|
388
|
+
var import_react4 = require("react");
|
|
389
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
390
|
+
var MessageContext = (0, import_react4.createContext)(
|
|
391
|
+
void 0
|
|
392
|
+
);
|
|
393
|
+
var MessageProvider = ({
|
|
394
|
+
children,
|
|
395
|
+
value
|
|
396
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageContext.Provider, { value, children });
|
|
397
|
+
var useMessageContext = (componentName) => {
|
|
398
|
+
const contextValue = (0, import_react4.useContext)(MessageContext);
|
|
399
|
+
if (!contextValue) {
|
|
400
|
+
console.warn(
|
|
401
|
+
`useMessageContext was called outside of MessageProvider.${componentName ? ` Errored in: ${componentName}` : ""}`
|
|
402
|
+
);
|
|
403
|
+
return {};
|
|
404
|
+
}
|
|
405
|
+
return contextValue;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// src/react/context/ComponentContext.tsx
|
|
409
|
+
var import_react5 = require("react");
|
|
410
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
411
|
+
var ComponentContext = (0, import_react5.createContext)({});
|
|
412
|
+
var ComponentProvider = ({
|
|
413
|
+
children,
|
|
414
|
+
value
|
|
415
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ComponentContext.Provider, { value, children });
|
|
416
|
+
var useComponentContext = (_componentName) => (0, import_react5.useContext)(ComponentContext);
|
|
417
|
+
|
|
418
|
+
// src/react/context/TypingContext.tsx
|
|
419
|
+
var import_react6 = require("react");
|
|
420
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
421
|
+
var TypingContext = (0, import_react6.createContext)(
|
|
422
|
+
void 0
|
|
423
|
+
);
|
|
424
|
+
var TypingProvider = ({
|
|
425
|
+
children,
|
|
426
|
+
value
|
|
427
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TypingContext.Provider, { value, children });
|
|
428
|
+
var useTypingContext = (componentName) => {
|
|
429
|
+
const contextValue = (0, import_react6.useContext)(TypingContext);
|
|
430
|
+
if (!contextValue) {
|
|
431
|
+
console.warn(
|
|
432
|
+
`useTypingContext was called outside of TypingProvider.${componentName ? ` Errored in: ${componentName}` : ""}`
|
|
433
|
+
);
|
|
434
|
+
return {};
|
|
435
|
+
}
|
|
436
|
+
return contextValue;
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/react/hooks/useMessages.ts
|
|
440
|
+
var import_react7 = require("react");
|
|
283
441
|
var useMessages = (client, roomId) => {
|
|
284
|
-
const [messages, setMessages] = (0,
|
|
285
|
-
const [loading, setLoading] = (0,
|
|
286
|
-
const [loadingMore, setLoadingMore] = (0,
|
|
287
|
-
const [hasMore, setHasMore] = (0,
|
|
288
|
-
const [error, setError] = (0,
|
|
289
|
-
const [typingUsers, setTypingUsers] = (0,
|
|
290
|
-
const oldestMessageId = (0,
|
|
291
|
-
(0,
|
|
442
|
+
const [messages, setMessages] = (0, import_react7.useState)([]);
|
|
443
|
+
const [loading, setLoading] = (0, import_react7.useState)(false);
|
|
444
|
+
const [loadingMore, setLoadingMore] = (0, import_react7.useState)(false);
|
|
445
|
+
const [hasMore, setHasMore] = (0, import_react7.useState)(false);
|
|
446
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
447
|
+
const [typingUsers, setTypingUsers] = (0, import_react7.useState)([]);
|
|
448
|
+
const oldestMessageId = (0, import_react7.useRef)(void 0);
|
|
449
|
+
(0, import_react7.useEffect)(() => {
|
|
292
450
|
if (!roomId || !client.isConnected) return;
|
|
293
451
|
setMessages([]);
|
|
294
452
|
setHasMore(false);
|
|
@@ -301,7 +459,7 @@ var useMessages = (client, roomId) => {
|
|
|
301
459
|
if (msgs.length > 0) oldestMessageId.current = msgs[0]._id;
|
|
302
460
|
}).catch((err) => setError(err.message)).finally(() => setLoading(false));
|
|
303
461
|
}, [roomId, client.isConnected]);
|
|
304
|
-
(0,
|
|
462
|
+
(0, import_react7.useEffect)(() => {
|
|
305
463
|
if (!roomId) return;
|
|
306
464
|
const onReceive = (msg) => {
|
|
307
465
|
if (msg.roomId !== roomId) return;
|
|
@@ -331,7 +489,7 @@ var useMessages = (client, roomId) => {
|
|
|
331
489
|
client.off("message:edited", onEdited);
|
|
332
490
|
};
|
|
333
491
|
}, [roomId, client]);
|
|
334
|
-
(0,
|
|
492
|
+
(0, import_react7.useEffect)(() => {
|
|
335
493
|
const onReaction = ({ messageId, reactions }) => {
|
|
336
494
|
setMessages(
|
|
337
495
|
(prev) => prev.map((m) => m._id === messageId ? { ...m, reactions } : m)
|
|
@@ -342,7 +500,7 @@ var useMessages = (client, roomId) => {
|
|
|
342
500
|
client.off("reaction:updated", onReaction);
|
|
343
501
|
};
|
|
344
502
|
}, [client]);
|
|
345
|
-
(0,
|
|
503
|
+
(0, import_react7.useEffect)(() => {
|
|
346
504
|
if (!roomId) return;
|
|
347
505
|
const onStarted = ({ userId, displayName, roomId: rid }) => {
|
|
348
506
|
if (rid !== roomId) return;
|
|
@@ -363,7 +521,7 @@ var useMessages = (client, roomId) => {
|
|
|
363
521
|
setTypingUsers([]);
|
|
364
522
|
};
|
|
365
523
|
}, [roomId, client]);
|
|
366
|
-
const loadMore = (0,
|
|
524
|
+
const loadMore = (0, import_react7.useCallback)(async () => {
|
|
367
525
|
if (!roomId || loadingMore || !hasMore) return;
|
|
368
526
|
setLoadingMore(true);
|
|
369
527
|
try {
|
|
@@ -380,28 +538,28 @@ var useMessages = (client, roomId) => {
|
|
|
380
538
|
setLoadingMore(false);
|
|
381
539
|
}
|
|
382
540
|
}, [roomId, loadingMore, hasMore, client]);
|
|
383
|
-
const sendMessage = (0,
|
|
541
|
+
const sendMessage = (0, import_react7.useCallback)(
|
|
384
542
|
async (input) => {
|
|
385
543
|
if (!roomId) throw new Error("No room selected");
|
|
386
544
|
return client.sendMessage({ ...input, roomId });
|
|
387
545
|
},
|
|
388
546
|
[roomId, client]
|
|
389
547
|
);
|
|
390
|
-
const editMessage = (0,
|
|
548
|
+
const editMessage = (0, import_react7.useCallback)(
|
|
391
549
|
async (messageId, text) => {
|
|
392
550
|
if (!roomId) throw new Error("No room selected");
|
|
393
551
|
return client.editMessage(messageId, roomId, text);
|
|
394
552
|
},
|
|
395
553
|
[roomId, client]
|
|
396
554
|
);
|
|
397
|
-
const deleteMessage = (0,
|
|
555
|
+
const deleteMessage = (0, import_react7.useCallback)(
|
|
398
556
|
async (messageId) => {
|
|
399
557
|
if (!roomId) throw new Error("No room selected");
|
|
400
558
|
return client.deleteMessage(messageId, roomId);
|
|
401
559
|
},
|
|
402
560
|
[roomId, client]
|
|
403
561
|
);
|
|
404
|
-
const addReaction = (0,
|
|
562
|
+
const addReaction = (0, import_react7.useCallback)(
|
|
405
563
|
async (messageId, emoji) => {
|
|
406
564
|
if (!roomId) throw new Error("No room selected");
|
|
407
565
|
return client.addReaction(messageId, roomId, emoji);
|
|
@@ -424,13 +582,13 @@ var useMessages = (client, roomId) => {
|
|
|
424
582
|
};
|
|
425
583
|
|
|
426
584
|
// src/react/hooks/useRooms.ts
|
|
427
|
-
var
|
|
585
|
+
var import_react8 = require("react");
|
|
428
586
|
var useRooms = (client) => {
|
|
429
|
-
const [rooms, setRooms] = (0,
|
|
430
|
-
const [loading, setLoading] = (0,
|
|
431
|
-
const [error, setError] = (0,
|
|
432
|
-
const fetchedRef = (0,
|
|
433
|
-
const fetchRooms = (0,
|
|
587
|
+
const [rooms, setRooms] = (0, import_react8.useState)([]);
|
|
588
|
+
const [loading, setLoading] = (0, import_react8.useState)(true);
|
|
589
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
590
|
+
const fetchedRef = (0, import_react8.useRef)(false);
|
|
591
|
+
const fetchRooms = (0, import_react8.useCallback)(async () => {
|
|
434
592
|
setLoading(true);
|
|
435
593
|
setError(null);
|
|
436
594
|
await new Promise((resolve, reject) => {
|
|
@@ -459,7 +617,7 @@ var useRooms = (client) => {
|
|
|
459
617
|
setLoading(false);
|
|
460
618
|
}
|
|
461
619
|
}, [client]);
|
|
462
|
-
(0,
|
|
620
|
+
(0, import_react8.useEffect)(() => {
|
|
463
621
|
fetchRooms();
|
|
464
622
|
const onConnected = () => {
|
|
465
623
|
if (!fetchedRef.current) fetchRooms();
|
|
@@ -469,7 +627,7 @@ var useRooms = (client) => {
|
|
|
469
627
|
client.off("connected", onConnected);
|
|
470
628
|
};
|
|
471
629
|
}, [fetchRooms, client]);
|
|
472
|
-
(0,
|
|
630
|
+
(0, import_react8.useEffect)(() => {
|
|
473
631
|
const onCreated = (room) => {
|
|
474
632
|
setRooms((prev) => {
|
|
475
633
|
if (prev.find((r) => r._id === room._id)) return prev;
|
|
@@ -516,7 +674,7 @@ var useRooms = (client) => {
|
|
|
516
674
|
client.off("message:receive", onMessage);
|
|
517
675
|
};
|
|
518
676
|
}, [client]);
|
|
519
|
-
const createDirect = (0,
|
|
677
|
+
const createDirect = (0, import_react8.useCallback)(
|
|
520
678
|
async (input) => {
|
|
521
679
|
const room = await client.createDirectRoom(input);
|
|
522
680
|
setRooms((prev) => {
|
|
@@ -527,7 +685,7 @@ var useRooms = (client) => {
|
|
|
527
685
|
},
|
|
528
686
|
[client]
|
|
529
687
|
);
|
|
530
|
-
const createGroup = (0,
|
|
688
|
+
const createGroup = (0, import_react8.useCallback)(
|
|
531
689
|
async (input) => {
|
|
532
690
|
const room = await client.createGroupRoom(input);
|
|
533
691
|
setRooms((prev) => {
|
|
@@ -538,18 +696,18 @@ var useRooms = (client) => {
|
|
|
538
696
|
},
|
|
539
697
|
[client]
|
|
540
698
|
);
|
|
541
|
-
const deleteRoom = (0,
|
|
699
|
+
const deleteRoom = (0, import_react8.useCallback)(
|
|
542
700
|
async (roomId) => {
|
|
543
701
|
await client.deleteRoom(roomId);
|
|
544
702
|
setRooms((prev) => prev.filter((r) => r._id !== roomId));
|
|
545
703
|
},
|
|
546
704
|
[client]
|
|
547
705
|
);
|
|
548
|
-
const addMember = (0,
|
|
706
|
+
const addMember = (0, import_react8.useCallback)(
|
|
549
707
|
(roomId, userId) => client.addMember(roomId, userId),
|
|
550
708
|
[client]
|
|
551
709
|
);
|
|
552
|
-
const removeMember = (0,
|
|
710
|
+
const removeMember = (0, import_react8.useCallback)(
|
|
553
711
|
(roomId, userId) => client.removeMember(roomId, userId),
|
|
554
712
|
[client]
|
|
555
713
|
);
|
|
@@ -567,10 +725,10 @@ var useRooms = (client) => {
|
|
|
567
725
|
};
|
|
568
726
|
|
|
569
727
|
// src/react/hooks/usePresence.ts
|
|
570
|
-
var
|
|
728
|
+
var import_react9 = require("react");
|
|
571
729
|
var usePresence = (client) => {
|
|
572
|
-
const [onlineMap, setOnlineMap] = (0,
|
|
573
|
-
(0,
|
|
730
|
+
const [onlineMap, setOnlineMap] = (0, import_react9.useState)(/* @__PURE__ */ new Map());
|
|
731
|
+
(0, import_react9.useEffect)(() => {
|
|
574
732
|
const onOnline = ({ userId }) => {
|
|
575
733
|
setOnlineMap((prev) => new Map(prev).set(userId, true));
|
|
576
734
|
};
|
|
@@ -584,7 +742,7 @@ var usePresence = (client) => {
|
|
|
584
742
|
client.off("user:offline", onOffline);
|
|
585
743
|
};
|
|
586
744
|
}, [client]);
|
|
587
|
-
const isOnline = (0,
|
|
745
|
+
const isOnline = (0, import_react9.useCallback)(
|
|
588
746
|
(userId) => onlineMap.get(userId) ?? false,
|
|
589
747
|
[onlineMap]
|
|
590
748
|
);
|
|
@@ -593,17 +751,17 @@ var usePresence = (client) => {
|
|
|
593
751
|
};
|
|
594
752
|
|
|
595
753
|
// src/react/hooks/useTyping.ts
|
|
596
|
-
var
|
|
754
|
+
var import_react10 = require("react");
|
|
597
755
|
var useTyping = (client, roomId) => {
|
|
598
|
-
const [typingUsers, setTypingUsers] = (0,
|
|
756
|
+
const [typingUsers, setTypingUsers] = (0, import_react10.useState)(
|
|
599
757
|
/* @__PURE__ */ new Map()
|
|
600
758
|
);
|
|
601
|
-
const timeouts = (0,
|
|
759
|
+
const timeouts = (0, import_react10.useRef)(
|
|
602
760
|
/* @__PURE__ */ new Map()
|
|
603
761
|
);
|
|
604
|
-
const typingRef = (0,
|
|
605
|
-
const stopTimeout = (0,
|
|
606
|
-
(0,
|
|
762
|
+
const typingRef = (0, import_react10.useRef)(false);
|
|
763
|
+
const stopTimeout = (0, import_react10.useRef)(null);
|
|
764
|
+
(0, import_react10.useEffect)(() => {
|
|
607
765
|
if (!roomId) return;
|
|
608
766
|
const onStart = (event) => {
|
|
609
767
|
if (event.roomId !== roomId) return;
|
|
@@ -642,7 +800,7 @@ var useTyping = (client, roomId) => {
|
|
|
642
800
|
timeouts.current.clear();
|
|
643
801
|
};
|
|
644
802
|
}, [roomId, client]);
|
|
645
|
-
const startTyping = (0,
|
|
803
|
+
const startTyping = (0, import_react10.useCallback)(() => {
|
|
646
804
|
if (!roomId) return;
|
|
647
805
|
if (!typingRef.current) {
|
|
648
806
|
client.startTyping(roomId);
|
|
@@ -654,7 +812,7 @@ var useTyping = (client, roomId) => {
|
|
|
654
812
|
typingRef.current = false;
|
|
655
813
|
}, 3e3);
|
|
656
814
|
}, [roomId, client]);
|
|
657
|
-
const stopTyping = (0,
|
|
815
|
+
const stopTyping = (0, import_react10.useCallback)(() => {
|
|
658
816
|
if (!roomId) return;
|
|
659
817
|
if (stopTimeout.current) clearTimeout(stopTimeout.current);
|
|
660
818
|
if (typingRef.current) {
|
|
@@ -679,10 +837,10 @@ var useTyping = (client, roomId) => {
|
|
|
679
837
|
};
|
|
680
838
|
|
|
681
839
|
// src/react/hooks/useReadReceipts.ts
|
|
682
|
-
var
|
|
840
|
+
var import_react11 = require("react");
|
|
683
841
|
var useReadReceipts = (client, roomId) => {
|
|
684
|
-
const [receipts, setReceipts] = (0,
|
|
685
|
-
(0,
|
|
842
|
+
const [receipts, setReceipts] = (0, import_react11.useState)(/* @__PURE__ */ new Map());
|
|
843
|
+
(0, import_react11.useEffect)(() => {
|
|
686
844
|
if (!roomId) return;
|
|
687
845
|
const onReceipt = (event) => {
|
|
688
846
|
if (event.roomId !== roomId) return;
|
|
@@ -697,14 +855,14 @@ var useReadReceipts = (client, roomId) => {
|
|
|
697
855
|
client.on("receipt:updated", onReceipt);
|
|
698
856
|
return () => client.off("receipt:updated", onReceipt);
|
|
699
857
|
}, [roomId, client]);
|
|
700
|
-
const markSeen = (0,
|
|
858
|
+
const markSeen = (0, import_react11.useCallback)(
|
|
701
859
|
async (lastMessageId) => {
|
|
702
860
|
if (!roomId) return;
|
|
703
861
|
await client.markSeen(roomId, lastMessageId);
|
|
704
862
|
},
|
|
705
863
|
[roomId, client]
|
|
706
864
|
);
|
|
707
|
-
const seenBy = (0,
|
|
865
|
+
const seenBy = (0, import_react11.useCallback)(
|
|
708
866
|
(messageId) => {
|
|
709
867
|
return Array.from(receipts.get(messageId) ?? []);
|
|
710
868
|
},
|
|
@@ -714,16 +872,16 @@ var useReadReceipts = (client, roomId) => {
|
|
|
714
872
|
};
|
|
715
873
|
|
|
716
874
|
// src/react/hooks/useReactions.ts
|
|
717
|
-
var
|
|
875
|
+
var import_react12 = require("react");
|
|
718
876
|
var useReactions = (client, roomId) => {
|
|
719
|
-
const react = (0,
|
|
877
|
+
const react = (0, import_react12.useCallback)(
|
|
720
878
|
async (messageId, emoji) => {
|
|
721
879
|
if (!roomId) throw new Error("No room selected");
|
|
722
880
|
await client.addReaction(messageId, roomId, emoji);
|
|
723
881
|
},
|
|
724
882
|
[roomId, client]
|
|
725
883
|
);
|
|
726
|
-
const hasReacted = (0,
|
|
884
|
+
const hasReacted = (0, import_react12.useCallback)(
|
|
727
885
|
(reactions, emoji) => {
|
|
728
886
|
const userId = client.currentUser?.userId;
|
|
729
887
|
if (!userId) return false;
|
|
@@ -731,25 +889,25 @@ var useReactions = (client, roomId) => {
|
|
|
731
889
|
},
|
|
732
890
|
[client]
|
|
733
891
|
);
|
|
734
|
-
const getCount = (0,
|
|
892
|
+
const getCount = (0, import_react12.useCallback)(
|
|
735
893
|
(reactions, emoji) => {
|
|
736
894
|
return reactions.find((r) => r.emoji === emoji)?.users.length ?? 0;
|
|
737
895
|
},
|
|
738
896
|
[]
|
|
739
897
|
);
|
|
740
|
-
const getEmojis = (0,
|
|
898
|
+
const getEmojis = (0, import_react12.useCallback)((reactions) => {
|
|
741
899
|
return reactions.filter((r) => r.users.length > 0).map((r) => r.emoji);
|
|
742
900
|
}, []);
|
|
743
901
|
return { react, hasReacted, getCount, getEmojis };
|
|
744
902
|
};
|
|
745
903
|
|
|
746
904
|
// src/react/hooks/useUpload.ts
|
|
747
|
-
var
|
|
905
|
+
var import_react13 = require("react");
|
|
748
906
|
var useUpload = (client) => {
|
|
749
|
-
const [uploading, setUploading] = (0,
|
|
750
|
-
const [error, setError] = (0,
|
|
751
|
-
const [lastUpload, setLastUpload] = (0,
|
|
752
|
-
const upload = (0,
|
|
907
|
+
const [uploading, setUploading] = (0, import_react13.useState)(false);
|
|
908
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
909
|
+
const [lastUpload, setLastUpload] = (0, import_react13.useState)(null);
|
|
910
|
+
const upload = (0, import_react13.useCallback)(
|
|
753
911
|
async (file) => {
|
|
754
912
|
setUploading(true);
|
|
755
913
|
setError(null);
|
|
@@ -766,7 +924,7 @@ var useUpload = (client) => {
|
|
|
766
924
|
},
|
|
767
925
|
[client]
|
|
768
926
|
);
|
|
769
|
-
const sendFile = (0,
|
|
927
|
+
const sendFile = (0, import_react13.useCallback)(
|
|
770
928
|
async (roomId, file, replyTo) => {
|
|
771
929
|
setUploading(true);
|
|
772
930
|
setError(null);
|
|
@@ -793,7 +951,7 @@ var useUpload = (client) => {
|
|
|
793
951
|
},
|
|
794
952
|
[client]
|
|
795
953
|
);
|
|
796
|
-
const validate = (0,
|
|
954
|
+
const validate = (0, import_react13.useCallback)((file, maxMb = 50) => {
|
|
797
955
|
if (file.size > maxMb * 1024 * 1024) {
|
|
798
956
|
return `File too large. Max size is ${maxMb}MB.`;
|
|
799
957
|
}
|
|
@@ -820,151 +978,616 @@ var useUpload = (client) => {
|
|
|
820
978
|
return { upload, sendFile, validate, uploading, error, lastUpload };
|
|
821
979
|
};
|
|
822
980
|
|
|
823
|
-
// src/react/components/
|
|
824
|
-
var
|
|
825
|
-
var
|
|
826
|
-
var
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
981
|
+
// src/react/components/Chat/Chat.tsx
|
|
982
|
+
var import_react14 = require("react");
|
|
983
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
984
|
+
var Chat = ({
|
|
985
|
+
client,
|
|
986
|
+
theme = "light",
|
|
987
|
+
customClasses,
|
|
988
|
+
initialNavOpen = false,
|
|
989
|
+
children
|
|
990
|
+
}) => {
|
|
991
|
+
const [activeRoom, setActiveRoom] = (0, import_react14.useState)(void 0);
|
|
992
|
+
const [navOpen, setNavOpen] = (0, import_react14.useState)(initialNavOpen);
|
|
993
|
+
const [currentUser, setCurrentUser] = (0, import_react14.useState)(
|
|
994
|
+
client.currentUser
|
|
995
|
+
);
|
|
996
|
+
(0, import_react14.useEffect)(() => {
|
|
997
|
+
if (client.currentUser) {
|
|
998
|
+
setCurrentUser(client.currentUser);
|
|
999
|
+
}
|
|
1000
|
+
const onConnected = () => setCurrentUser(client.currentUser);
|
|
1001
|
+
client.on("connected", onConnected);
|
|
1002
|
+
return () => {
|
|
1003
|
+
client.off("connected", onConnected);
|
|
1004
|
+
};
|
|
1005
|
+
}, [client]);
|
|
1006
|
+
const openMobileNav = (0, import_react14.useCallback)(() => setNavOpen(true), []);
|
|
1007
|
+
const closeMobileNav = (0, import_react14.useCallback)(() => setNavOpen(false), []);
|
|
1008
|
+
const handleSetActiveRoom = (0, import_react14.useCallback)(
|
|
1009
|
+
(room) => {
|
|
1010
|
+
setActiveRoom(room);
|
|
1011
|
+
setNavOpen(false);
|
|
1012
|
+
},
|
|
1013
|
+
[]
|
|
1014
|
+
);
|
|
1015
|
+
const chatContextValue = (0, import_react14.useMemo)(
|
|
1016
|
+
() => ({
|
|
1017
|
+
client,
|
|
1018
|
+
currentUser,
|
|
1019
|
+
theme,
|
|
1020
|
+
activeRoom,
|
|
1021
|
+
setActiveRoom: handleSetActiveRoom,
|
|
1022
|
+
openMobileNav,
|
|
1023
|
+
closeMobileNav,
|
|
1024
|
+
navOpen,
|
|
1025
|
+
customClasses
|
|
1026
|
+
}),
|
|
1027
|
+
[
|
|
1028
|
+
client,
|
|
1029
|
+
currentUser,
|
|
1030
|
+
theme,
|
|
1031
|
+
activeRoom,
|
|
1032
|
+
handleSetActiveRoom,
|
|
1033
|
+
openMobileNav,
|
|
1034
|
+
closeMobileNav,
|
|
1035
|
+
navOpen,
|
|
1036
|
+
customClasses
|
|
1037
|
+
]
|
|
1038
|
+
);
|
|
1039
|
+
const containerClass = customClasses?.chat || `hermes-chat hermes-chat--${theme}`;
|
|
1040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatProvider, { value: chatContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: containerClass, children }) });
|
|
832
1041
|
};
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1042
|
+
|
|
1043
|
+
// src/react/components/Room/Room.tsx
|
|
1044
|
+
var import_react15 = require("react");
|
|
1045
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1046
|
+
var Room = ({
|
|
1047
|
+
roomId,
|
|
1048
|
+
children,
|
|
1049
|
+
// Component overrides forwarded to ComponentContext
|
|
1050
|
+
Avatar: Avatar2,
|
|
1051
|
+
Message: MessageOverride,
|
|
1052
|
+
MessageStatus: MessageStatus2,
|
|
1053
|
+
MessageActions: MessageActions2,
|
|
1054
|
+
DateSeparator: DateSeparator2,
|
|
1055
|
+
EmptyStateIndicator: EmptyStateIndicator2,
|
|
1056
|
+
LoadingIndicator: LoadingIndicator2,
|
|
1057
|
+
LoadingErrorIndicator: LoadingErrorIndicator2,
|
|
1058
|
+
ReactionPicker: ReactionPicker2,
|
|
1059
|
+
TypingIndicator: TypingIndicator2,
|
|
1060
|
+
MediaMessage: MediaMessage2,
|
|
1061
|
+
ThreadHeader: ThreadHeader2,
|
|
1062
|
+
Modal: Modal2,
|
|
1063
|
+
ChatInput: ChatInput2,
|
|
1064
|
+
RoomListItem,
|
|
1065
|
+
Search: Search2,
|
|
1066
|
+
OnlineBadge: OnlineBadge2
|
|
1067
|
+
}) => {
|
|
1068
|
+
const { client, customClasses } = useChatContext("Room");
|
|
1069
|
+
const [messages, setMessages] = (0, import_react15.useState)([]);
|
|
1070
|
+
const [loading, setLoading] = (0, import_react15.useState)(true);
|
|
1071
|
+
const [loadingMore, setLoadingMore] = (0, import_react15.useState)(false);
|
|
1072
|
+
const [hasMore, setHasMore] = (0, import_react15.useState)(false);
|
|
1073
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
1074
|
+
const oldestMessageId = (0, import_react15.useRef)(void 0);
|
|
1075
|
+
const [thread, setThread] = (0, import_react15.useState)(null);
|
|
1076
|
+
const [threadMessages, setThreadMessages] = (0, import_react15.useState)([]);
|
|
1077
|
+
const [threadHasMore, setThreadHasMore] = (0, import_react15.useState)(false);
|
|
1078
|
+
const [threadLoadingMore, setThreadLoadingMore] = (0, import_react15.useState)(false);
|
|
1079
|
+
const [typingUsers, setTypingUsers] = (0, import_react15.useState)(
|
|
1080
|
+
/* @__PURE__ */ new Map()
|
|
1081
|
+
);
|
|
1082
|
+
const typingTimeouts = (0, import_react15.useRef)(
|
|
1083
|
+
/* @__PURE__ */ new Map()
|
|
1084
|
+
);
|
|
1085
|
+
const isTypingRef = (0, import_react15.useRef)(false);
|
|
1086
|
+
const stopTypingTimeout = (0, import_react15.useRef)(null);
|
|
1087
|
+
(0, import_react15.useEffect)(() => {
|
|
1088
|
+
if (!roomId || !client?.isConnected) return;
|
|
1089
|
+
setMessages([]);
|
|
1090
|
+
setHasMore(false);
|
|
1091
|
+
setThread(null);
|
|
1092
|
+
setThreadMessages([]);
|
|
1093
|
+
oldestMessageId.current = void 0;
|
|
1094
|
+
setLoading(true);
|
|
1095
|
+
setError(null);
|
|
1096
|
+
client.getHistory(roomId).then(({ messages: msgs, hasMore: more }) => {
|
|
1097
|
+
setMessages(msgs);
|
|
1098
|
+
setHasMore(more);
|
|
1099
|
+
if (msgs.length > 0) oldestMessageId.current = msgs[0]._id;
|
|
1100
|
+
}).catch((err) => setError(err.message)).finally(() => setLoading(false));
|
|
1101
|
+
}, [roomId, client?.isConnected]);
|
|
1102
|
+
(0, import_react15.useEffect)(() => {
|
|
1103
|
+
if (!roomId || !client) return;
|
|
1104
|
+
const onReceive = (msg) => {
|
|
1105
|
+
if (msg.roomId !== roomId) return;
|
|
1106
|
+
if (msg.threadParentId && thread && msg.threadParentId === thread._id) {
|
|
1107
|
+
setThreadMessages(
|
|
1108
|
+
(prev) => prev.find((m) => m._id === msg._id) ? prev : [...prev, msg]
|
|
1109
|
+
);
|
|
1110
|
+
setMessages(
|
|
1111
|
+
(prev) => prev.map(
|
|
1112
|
+
(m) => m._id === msg.threadParentId ? { ...m, replyCount: (m.replyCount || 0) + 1 } : m
|
|
1113
|
+
)
|
|
1114
|
+
);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
setMessages(
|
|
1118
|
+
(prev) => prev.find((m) => m._id === msg._id) ? prev : [...prev, msg]
|
|
1119
|
+
);
|
|
860
1120
|
};
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1121
|
+
const onDeleted = ({ messageId }) => {
|
|
1122
|
+
setMessages(
|
|
1123
|
+
(prev) => prev.map(
|
|
1124
|
+
(m) => m._id === messageId ? { ...m, isDeleted: true, text: void 0 } : m
|
|
1125
|
+
)
|
|
1126
|
+
);
|
|
1127
|
+
setThreadMessages(
|
|
1128
|
+
(prev) => prev.map(
|
|
1129
|
+
(m) => m._id === messageId ? { ...m, isDeleted: true, text: void 0 } : m
|
|
1130
|
+
)
|
|
1131
|
+
);
|
|
1132
|
+
};
|
|
1133
|
+
const onEdited = (msg) => {
|
|
1134
|
+
setMessages((prev) => prev.map((m) => m._id === msg._id ? msg : m));
|
|
1135
|
+
setThreadMessages(
|
|
1136
|
+
(prev) => prev.map((m) => m._id === msg._id ? msg : m)
|
|
1137
|
+
);
|
|
1138
|
+
};
|
|
1139
|
+
const onReaction = ({ messageId, reactions }) => {
|
|
1140
|
+
setMessages(
|
|
1141
|
+
(prev) => prev.map((m) => m._id === messageId ? { ...m, reactions } : m)
|
|
1142
|
+
);
|
|
1143
|
+
setThreadMessages(
|
|
1144
|
+
(prev) => prev.map((m) => m._id === messageId ? { ...m, reactions } : m)
|
|
1145
|
+
);
|
|
1146
|
+
};
|
|
1147
|
+
client.on("message:receive", onReceive);
|
|
1148
|
+
client.on("message:deleted", onDeleted);
|
|
1149
|
+
client.on("message:edited", onEdited);
|
|
1150
|
+
client.on("reaction:updated", onReaction);
|
|
1151
|
+
return () => {
|
|
1152
|
+
client.off("message:receive", onReceive);
|
|
1153
|
+
client.off("message:deleted", onDeleted);
|
|
1154
|
+
client.off("message:edited", onEdited);
|
|
1155
|
+
client.off("reaction:updated", onReaction);
|
|
1156
|
+
};
|
|
1157
|
+
}, [roomId, client, thread]);
|
|
1158
|
+
(0, import_react15.useEffect)(() => {
|
|
1159
|
+
if (!roomId || !client) return;
|
|
1160
|
+
const onStart = (event) => {
|
|
1161
|
+
if (event.roomId !== roomId) return;
|
|
1162
|
+
if (event.userId === client.currentUser?.userId) return;
|
|
1163
|
+
setTypingUsers(
|
|
1164
|
+
(prev) => new Map(prev).set(event.userId, event.displayName)
|
|
1165
|
+
);
|
|
1166
|
+
const existing = typingTimeouts.current.get(event.userId);
|
|
1167
|
+
if (existing) clearTimeout(existing);
|
|
1168
|
+
const t = setTimeout(() => {
|
|
1169
|
+
setTypingUsers((prev) => {
|
|
1170
|
+
const next = new Map(prev);
|
|
1171
|
+
next.delete(event.userId);
|
|
1172
|
+
return next;
|
|
1173
|
+
});
|
|
1174
|
+
}, 4e3);
|
|
1175
|
+
typingTimeouts.current.set(event.userId, t);
|
|
1176
|
+
};
|
|
1177
|
+
const onStop = (event) => {
|
|
1178
|
+
if (event.roomId !== roomId) return;
|
|
1179
|
+
setTypingUsers((prev) => {
|
|
1180
|
+
const next = new Map(prev);
|
|
1181
|
+
next.delete(event.userId);
|
|
1182
|
+
return next;
|
|
1183
|
+
});
|
|
1184
|
+
const existing = typingTimeouts.current.get(event.userId);
|
|
1185
|
+
if (existing) clearTimeout(existing);
|
|
1186
|
+
};
|
|
1187
|
+
client.on("typing:started", onStart);
|
|
1188
|
+
client.on("typing:stopped", onStop);
|
|
1189
|
+
return () => {
|
|
1190
|
+
client.off("typing:started", onStart);
|
|
1191
|
+
client.off("typing:stopped", onStop);
|
|
1192
|
+
typingTimeouts.current.forEach(clearTimeout);
|
|
1193
|
+
typingTimeouts.current.clear();
|
|
1194
|
+
setTypingUsers(/* @__PURE__ */ new Map());
|
|
1195
|
+
};
|
|
1196
|
+
}, [roomId, client]);
|
|
1197
|
+
const sendMessage = (0, import_react15.useCallback)(
|
|
1198
|
+
async (input) => {
|
|
1199
|
+
if (!roomId) throw new Error("No room selected");
|
|
1200
|
+
return client.sendMessage({ ...input, roomId });
|
|
1201
|
+
},
|
|
1202
|
+
[roomId, client]
|
|
1203
|
+
);
|
|
1204
|
+
const editMessage = (0, import_react15.useCallback)(
|
|
1205
|
+
async (messageId, text) => {
|
|
1206
|
+
if (!roomId) throw new Error("No room selected");
|
|
1207
|
+
return client.editMessage(messageId, roomId, text);
|
|
1208
|
+
},
|
|
1209
|
+
[roomId, client]
|
|
1210
|
+
);
|
|
1211
|
+
const deleteMessage = (0, import_react15.useCallback)(
|
|
1212
|
+
async (messageId) => {
|
|
1213
|
+
if (!roomId) throw new Error("No room selected");
|
|
1214
|
+
return client.deleteMessage(messageId, roomId);
|
|
1215
|
+
},
|
|
1216
|
+
[roomId, client]
|
|
1217
|
+
);
|
|
1218
|
+
const addReaction = (0, import_react15.useCallback)(
|
|
1219
|
+
async (messageId, emoji) => {
|
|
1220
|
+
if (!roomId) throw new Error("No room selected");
|
|
1221
|
+
return client.addReaction(messageId, roomId, emoji);
|
|
1222
|
+
},
|
|
1223
|
+
[roomId, client]
|
|
1224
|
+
);
|
|
1225
|
+
const loadMore = (0, import_react15.useCallback)(async () => {
|
|
1226
|
+
if (!roomId || loadingMore || !hasMore) return;
|
|
1227
|
+
setLoadingMore(true);
|
|
1228
|
+
try {
|
|
1229
|
+
const { messages: older, hasMore: more } = await client.getHistory(
|
|
1230
|
+
roomId,
|
|
1231
|
+
oldestMessageId.current
|
|
1232
|
+
);
|
|
1233
|
+
setMessages((prev) => [...older, ...prev]);
|
|
1234
|
+
setHasMore(more);
|
|
1235
|
+
if (older.length > 0) oldestMessageId.current = older[0]._id;
|
|
1236
|
+
} catch (err) {
|
|
1237
|
+
setError(err.message);
|
|
1238
|
+
} finally {
|
|
1239
|
+
setLoadingMore(false);
|
|
1240
|
+
}
|
|
1241
|
+
}, [roomId, loadingMore, hasMore, client]);
|
|
1242
|
+
const markRead = (0, import_react15.useCallback)(
|
|
1243
|
+
async (lastMessageId) => {
|
|
1244
|
+
if (!roomId) return;
|
|
1245
|
+
await client.markSeen(roomId, lastMessageId);
|
|
1246
|
+
},
|
|
1247
|
+
[roomId, client]
|
|
1248
|
+
);
|
|
1249
|
+
const openThread = (0, import_react15.useCallback)((message) => {
|
|
1250
|
+
setThread(message);
|
|
1251
|
+
setThreadMessages([]);
|
|
1252
|
+
setThreadHasMore(false);
|
|
1253
|
+
}, []);
|
|
1254
|
+
const closeThread = (0, import_react15.useCallback)(() => {
|
|
1255
|
+
setThread(null);
|
|
1256
|
+
setThreadMessages([]);
|
|
1257
|
+
}, []);
|
|
1258
|
+
const loadMoreThread = (0, import_react15.useCallback)(async () => {
|
|
1259
|
+
}, []);
|
|
1260
|
+
const startTyping = (0, import_react15.useCallback)(() => {
|
|
1261
|
+
if (!roomId) return;
|
|
1262
|
+
if (!isTypingRef.current) {
|
|
1263
|
+
client.startTyping(roomId);
|
|
1264
|
+
isTypingRef.current = true;
|
|
912
1265
|
}
|
|
1266
|
+
if (stopTypingTimeout.current) clearTimeout(stopTypingTimeout.current);
|
|
1267
|
+
stopTypingTimeout.current = setTimeout(() => {
|
|
1268
|
+
client.stopTyping(roomId);
|
|
1269
|
+
isTypingRef.current = false;
|
|
1270
|
+
}, 3e3);
|
|
1271
|
+
}, [roomId, client]);
|
|
1272
|
+
const stopTyping = (0, import_react15.useCallback)(() => {
|
|
1273
|
+
if (!roomId) return;
|
|
1274
|
+
if (stopTypingTimeout.current) clearTimeout(stopTypingTimeout.current);
|
|
1275
|
+
if (isTypingRef.current) {
|
|
1276
|
+
client.stopTyping(roomId);
|
|
1277
|
+
isTypingRef.current = false;
|
|
1278
|
+
}
|
|
1279
|
+
}, [roomId, client]);
|
|
1280
|
+
const typingText = (0, import_react15.useMemo)(() => {
|
|
1281
|
+
const names = Array.from(typingUsers.values());
|
|
1282
|
+
if (names.length === 0) return null;
|
|
1283
|
+
if (names.length === 1) return `${names[0]} is typing...`;
|
|
1284
|
+
if (names.length === 2) return `${names[0]} and ${names[1]} are typing...`;
|
|
1285
|
+
return `${names[0]} and ${names.length - 1} others are typing...`;
|
|
1286
|
+
}, [typingUsers]);
|
|
1287
|
+
const roomStateValue = (0, import_react15.useMemo)(
|
|
1288
|
+
() => ({
|
|
1289
|
+
room: { _id: roomId },
|
|
1290
|
+
messages,
|
|
1291
|
+
loading,
|
|
1292
|
+
loadingMore,
|
|
1293
|
+
hasMore,
|
|
1294
|
+
error,
|
|
1295
|
+
members: [],
|
|
1296
|
+
thread,
|
|
1297
|
+
threadMessages,
|
|
1298
|
+
threadHasMore,
|
|
1299
|
+
threadLoadingMore,
|
|
1300
|
+
pinnedMessages: messages.filter((m) => m.pinnedAt)
|
|
1301
|
+
}),
|
|
1302
|
+
[messages, loading, loadingMore, hasMore, error, thread, threadMessages, threadHasMore, threadLoadingMore, roomId]
|
|
913
1303
|
);
|
|
1304
|
+
const roomActionValue = (0, import_react15.useMemo)(
|
|
1305
|
+
() => ({
|
|
1306
|
+
sendMessage,
|
|
1307
|
+
editMessage,
|
|
1308
|
+
deleteMessage,
|
|
1309
|
+
addReaction,
|
|
1310
|
+
loadMore,
|
|
1311
|
+
markRead,
|
|
1312
|
+
openThread,
|
|
1313
|
+
closeThread,
|
|
1314
|
+
loadMoreThread
|
|
1315
|
+
}),
|
|
1316
|
+
[sendMessage, editMessage, deleteMessage, addReaction, loadMore, markRead, openThread, closeThread, loadMoreThread]
|
|
1317
|
+
);
|
|
1318
|
+
const typingValue = (0, import_react15.useMemo)(
|
|
1319
|
+
() => ({
|
|
1320
|
+
typingUsers,
|
|
1321
|
+
typingText,
|
|
1322
|
+
isAnyoneTyping: typingUsers.size > 0,
|
|
1323
|
+
startTyping,
|
|
1324
|
+
stopTyping
|
|
1325
|
+
}),
|
|
1326
|
+
[typingUsers, typingText, startTyping, stopTyping]
|
|
1327
|
+
);
|
|
1328
|
+
const componentOverrides = (0, import_react15.useMemo)(
|
|
1329
|
+
() => ({
|
|
1330
|
+
Avatar: Avatar2,
|
|
1331
|
+
Message: MessageOverride,
|
|
1332
|
+
MessageStatus: MessageStatus2,
|
|
1333
|
+
MessageActions: MessageActions2,
|
|
1334
|
+
DateSeparator: DateSeparator2,
|
|
1335
|
+
EmptyStateIndicator: EmptyStateIndicator2,
|
|
1336
|
+
LoadingIndicator: LoadingIndicator2,
|
|
1337
|
+
LoadingErrorIndicator: LoadingErrorIndicator2,
|
|
1338
|
+
ReactionPicker: ReactionPicker2,
|
|
1339
|
+
TypingIndicator: TypingIndicator2,
|
|
1340
|
+
MediaMessage: MediaMessage2,
|
|
1341
|
+
ThreadHeader: ThreadHeader2,
|
|
1342
|
+
Modal: Modal2,
|
|
1343
|
+
ChatInput: ChatInput2,
|
|
1344
|
+
RoomListItem,
|
|
1345
|
+
Search: Search2,
|
|
1346
|
+
OnlineBadge: OnlineBadge2
|
|
1347
|
+
}),
|
|
1348
|
+
[Avatar2, MessageOverride, MessageStatus2, MessageActions2, DateSeparator2, EmptyStateIndicator2, LoadingIndicator2, LoadingErrorIndicator2, ReactionPicker2, TypingIndicator2, MediaMessage2, ThreadHeader2, Modal2, ChatInput2, RoomListItem, Search2, OnlineBadge2]
|
|
1349
|
+
);
|
|
1350
|
+
const containerClass = customClasses?.room || "hermes-room";
|
|
1351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RoomStateProvider, { value: roomStateValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RoomActionProvider, { value: roomActionValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TypingProvider, { value: typingValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ComponentProvider, { value: componentOverrides, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: containerClass, children }) }) }) }) });
|
|
914
1352
|
};
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1353
|
+
|
|
1354
|
+
// src/react/components/Window/Window.tsx
|
|
1355
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1356
|
+
var Window = ({
|
|
1357
|
+
className = "",
|
|
1358
|
+
children
|
|
1359
|
+
}) => {
|
|
1360
|
+
const { customClasses } = useChatContext("Window");
|
|
1361
|
+
const containerClass = customClasses?.window || `hermes-window ${className}`.trim();
|
|
1362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
919
1363
|
"div",
|
|
920
1364
|
{
|
|
1365
|
+
className: containerClass,
|
|
921
1366
|
style: {
|
|
922
1367
|
display: "flex",
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1368
|
+
flexDirection: "column",
|
|
1369
|
+
height: "100%",
|
|
1370
|
+
flex: 1,
|
|
1371
|
+
minWidth: 0,
|
|
1372
|
+
overflow: "hidden"
|
|
927
1373
|
},
|
|
928
|
-
children
|
|
929
|
-
|
|
930
|
-
|
|
1374
|
+
children
|
|
1375
|
+
}
|
|
1376
|
+
);
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1379
|
+
// src/react/components/MessageList.tsx
|
|
1380
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
1381
|
+
|
|
1382
|
+
// src/react/components/Message/Message.tsx
|
|
1383
|
+
var import_react16 = require("react");
|
|
1384
|
+
|
|
1385
|
+
// src/react/components/Avatar/Avatar.tsx
|
|
1386
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1387
|
+
var getInitials = (name) => {
|
|
1388
|
+
if (!name) return "?";
|
|
1389
|
+
const parts = name.trim().split(/\s+/);
|
|
1390
|
+
if (parts.length >= 2) return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
1391
|
+
return name.slice(0, 2).toUpperCase();
|
|
1392
|
+
};
|
|
1393
|
+
var Avatar = ({
|
|
1394
|
+
image,
|
|
1395
|
+
name,
|
|
1396
|
+
size = 36,
|
|
1397
|
+
shape = "circle",
|
|
1398
|
+
className = "",
|
|
1399
|
+
online
|
|
1400
|
+
}) => {
|
|
1401
|
+
const borderRadius = shape === "circle" ? "50%" : shape === "rounded" ? "8px" : "0";
|
|
1402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1403
|
+
"div",
|
|
1404
|
+
{
|
|
1405
|
+
className: `hermes-avatar ${className}`,
|
|
1406
|
+
style: {
|
|
1407
|
+
position: "relative",
|
|
1408
|
+
width: size,
|
|
1409
|
+
height: size,
|
|
1410
|
+
flexShrink: 0
|
|
1411
|
+
},
|
|
1412
|
+
children: [
|
|
1413
|
+
image ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1414
|
+
"img",
|
|
931
1415
|
{
|
|
1416
|
+
src: image,
|
|
1417
|
+
alt: name || "avatar",
|
|
932
1418
|
style: {
|
|
1419
|
+
width: size,
|
|
1420
|
+
height: size,
|
|
1421
|
+
borderRadius,
|
|
1422
|
+
objectFit: "cover",
|
|
1423
|
+
display: "block"
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1427
|
+
"div",
|
|
1428
|
+
{
|
|
1429
|
+
style: {
|
|
1430
|
+
width: size,
|
|
1431
|
+
height: size,
|
|
1432
|
+
borderRadius,
|
|
1433
|
+
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
|
|
933
1434
|
display: "flex",
|
|
934
1435
|
alignItems: "center",
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1436
|
+
justifyContent: "center",
|
|
1437
|
+
color: "#fff",
|
|
1438
|
+
fontWeight: 700,
|
|
1439
|
+
fontSize: size * 0.38,
|
|
1440
|
+
userSelect: "none"
|
|
939
1441
|
},
|
|
940
|
-
children:
|
|
941
|
-
"span",
|
|
942
|
-
{
|
|
943
|
-
style: {
|
|
944
|
-
width: 6,
|
|
945
|
-
height: 6,
|
|
946
|
-
borderRadius: "50%",
|
|
947
|
-
background: "#999",
|
|
948
|
-
display: "block",
|
|
949
|
-
animation: `hermes-bounce 1.2s ease-in-out ${i * 0.18}s infinite`
|
|
950
|
-
}
|
|
951
|
-
},
|
|
952
|
-
i
|
|
953
|
-
))
|
|
1442
|
+
children: getInitials(name)
|
|
954
1443
|
}
|
|
955
1444
|
),
|
|
956
|
-
/* @__PURE__ */ (0,
|
|
1445
|
+
online !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1446
|
+
"span",
|
|
1447
|
+
{
|
|
1448
|
+
style: {
|
|
1449
|
+
position: "absolute",
|
|
1450
|
+
bottom: 0,
|
|
1451
|
+
right: 0,
|
|
1452
|
+
width: size * 0.3,
|
|
1453
|
+
height: size * 0.3,
|
|
1454
|
+
borderRadius: "50%",
|
|
1455
|
+
background: online ? "#22c55e" : "#9ca3af",
|
|
1456
|
+
border: "2px solid #fff"
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
)
|
|
957
1460
|
]
|
|
958
1461
|
}
|
|
959
1462
|
);
|
|
960
1463
|
};
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1464
|
+
|
|
1465
|
+
// src/react/components/Message/MessageStatus.tsx
|
|
1466
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1467
|
+
var MessageStatus = ({
|
|
1468
|
+
status,
|
|
1469
|
+
seenCount = 0,
|
|
1470
|
+
isMyMessage = true,
|
|
1471
|
+
className = ""
|
|
1472
|
+
}) => {
|
|
1473
|
+
if (!isMyMessage) return null;
|
|
1474
|
+
const color = status === "seen" ? "#0084ff" : "rgba(128,128,128,0.6)";
|
|
1475
|
+
const checks = status === "sent" ? "\u2713" : "\u2713\u2713";
|
|
1476
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1477
|
+
"span",
|
|
1478
|
+
{
|
|
1479
|
+
className: `hermes-message-status ${className}`,
|
|
1480
|
+
title: status === "seen" ? `Seen by ${seenCount} ${seenCount === 1 ? "person" : "people"}` : status === "delivered" ? "Delivered" : "Sent",
|
|
1481
|
+
style: {
|
|
1482
|
+
fontSize: 11,
|
|
1483
|
+
color,
|
|
1484
|
+
marginLeft: 4,
|
|
1485
|
+
userSelect: "none"
|
|
1486
|
+
},
|
|
1487
|
+
children: checks
|
|
1488
|
+
}
|
|
1489
|
+
);
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
// src/react/components/Message/MessageActions.tsx
|
|
1493
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1494
|
+
var ActionBtn = ({ onClick, title, children }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1495
|
+
"button",
|
|
1496
|
+
{
|
|
1497
|
+
onClick,
|
|
1498
|
+
title,
|
|
1499
|
+
style: {
|
|
1500
|
+
background: "#fff",
|
|
1501
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
1502
|
+
borderRadius: 8,
|
|
1503
|
+
cursor: "pointer",
|
|
1504
|
+
fontSize: 14,
|
|
1505
|
+
padding: "3px 6px",
|
|
1506
|
+
lineHeight: 1,
|
|
1507
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.1)",
|
|
1508
|
+
transition: "transform 0.1s"
|
|
1509
|
+
},
|
|
1510
|
+
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.15)",
|
|
1511
|
+
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
1512
|
+
children
|
|
1513
|
+
}
|
|
1514
|
+
);
|
|
1515
|
+
var MessageActions = ({
|
|
1516
|
+
isOwn,
|
|
1517
|
+
isText,
|
|
1518
|
+
hasThread = false,
|
|
1519
|
+
replyCount = 0,
|
|
1520
|
+
onReact,
|
|
1521
|
+
onReply,
|
|
1522
|
+
onThread,
|
|
1523
|
+
onEdit,
|
|
1524
|
+
onDelete,
|
|
1525
|
+
onPin,
|
|
1526
|
+
className = ""
|
|
1527
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1528
|
+
"div",
|
|
1529
|
+
{
|
|
1530
|
+
className: `hermes-message-actions ${className}`,
|
|
1531
|
+
style: {
|
|
1532
|
+
display: "flex",
|
|
1533
|
+
flexDirection: isOwn ? "row-reverse" : "row",
|
|
1534
|
+
gap: 2
|
|
1535
|
+
},
|
|
1536
|
+
children: [
|
|
1537
|
+
onReact && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onReact, title: "React", children: "\u{1F60A}" }),
|
|
1538
|
+
onReply && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onReply, title: "Reply", children: "\u21A9" }),
|
|
1539
|
+
onThread && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onThread, title: `Thread${replyCount > 0 ? ` (${replyCount})` : ""}`, children: "\u{1F9F5}" }),
|
|
1540
|
+
isOwn && isText && onEdit && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onEdit, title: "Edit", children: "\u270F\uFE0F" }),
|
|
1541
|
+
onPin && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onPin, title: "Pin", children: "\u{1F4CC}" }),
|
|
1542
|
+
isOwn && onDelete && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionBtn, { onClick: onDelete, title: "Delete", children: "\u{1F5D1}" })
|
|
1543
|
+
]
|
|
1544
|
+
}
|
|
1545
|
+
);
|
|
1546
|
+
|
|
1547
|
+
// src/react/components/Message/Message.tsx
|
|
1548
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1549
|
+
var REACTION_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F525}", "\u{1F389}", "\u{1F44F}"];
|
|
1550
|
+
var formatTime = (iso) => new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
1551
|
+
var formatFileSize = (bytes) => {
|
|
1552
|
+
if (!bytes) return "";
|
|
1553
|
+
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
1554
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1555
|
+
return `${bytes} B`;
|
|
1556
|
+
};
|
|
1557
|
+
var Message = ({
|
|
1558
|
+
message,
|
|
1559
|
+
isOwn,
|
|
1560
|
+
onEdit,
|
|
1561
|
+
onDelete,
|
|
1562
|
+
onReact,
|
|
1563
|
+
onReply,
|
|
1564
|
+
onOpenThread,
|
|
1565
|
+
onPin,
|
|
1566
|
+
renderAvatar,
|
|
1567
|
+
senderName,
|
|
1568
|
+
senderImage,
|
|
1569
|
+
groupStyle = "single",
|
|
1570
|
+
className = "",
|
|
1571
|
+
showAvatar = true
|
|
1572
|
+
}) => {
|
|
1573
|
+
const [hovered, setHovered] = (0, import_react16.useState)(false);
|
|
1574
|
+
const [pickerOpen, setPickerOpen] = (0, import_react16.useState)(false);
|
|
1575
|
+
const pickerRef = (0, import_react16.useRef)(null);
|
|
1576
|
+
(0, import_react16.useEffect)(() => {
|
|
1577
|
+
if (!pickerOpen) return;
|
|
1578
|
+
const handler = (e) => {
|
|
1579
|
+
if (pickerRef.current && !pickerRef.current.contains(e.target)) {
|
|
1580
|
+
setPickerOpen(false);
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
document.addEventListener("mousedown", handler);
|
|
1584
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
1585
|
+
}, [pickerOpen]);
|
|
964
1586
|
if (message.isDeleted) {
|
|
965
|
-
return /* @__PURE__ */ (0,
|
|
1587
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
966
1588
|
"div",
|
|
967
1589
|
{
|
|
1590
|
+
className: `hermes-message hermes-message--deleted ${className}`,
|
|
968
1591
|
style: {
|
|
969
1592
|
opacity: 0.5,
|
|
970
1593
|
fontStyle: "italic",
|
|
@@ -975,40 +1598,24 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
975
1598
|
}
|
|
976
1599
|
);
|
|
977
1600
|
}
|
|
978
|
-
|
|
1601
|
+
const showAvatarSlot = showAvatar && !isOwn && (groupStyle === "bottom" || groupStyle === "single");
|
|
1602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
979
1603
|
"div",
|
|
980
1604
|
{
|
|
1605
|
+
className: `hermes-message ${isOwn ? "hermes-message--own" : "hermes-message--other"} ${className}`,
|
|
981
1606
|
onMouseEnter: () => setHovered(true),
|
|
982
|
-
onMouseLeave: () =>
|
|
983
|
-
setHovered(false);
|
|
984
|
-
},
|
|
1607
|
+
onMouseLeave: () => setHovered(false),
|
|
985
1608
|
style: {
|
|
986
1609
|
display: "flex",
|
|
987
1610
|
flexDirection: isOwn ? "row-reverse" : "row",
|
|
988
1611
|
alignItems: "flex-end",
|
|
989
1612
|
gap: 8,
|
|
990
|
-
marginBottom:
|
|
1613
|
+
marginBottom: groupStyle === "bottom" || groupStyle === "single" ? 8 : 2,
|
|
991
1614
|
position: "relative"
|
|
992
1615
|
},
|
|
993
1616
|
children: [
|
|
994
|
-
!isOwn && /* @__PURE__ */ (0,
|
|
995
|
-
|
|
996
|
-
{
|
|
997
|
-
style: {
|
|
998
|
-
width: 32,
|
|
999
|
-
height: 32,
|
|
1000
|
-
borderRadius: "50%",
|
|
1001
|
-
background: "#e0e0e0",
|
|
1002
|
-
display: "flex",
|
|
1003
|
-
alignItems: "center",
|
|
1004
|
-
justifyContent: "center",
|
|
1005
|
-
fontSize: 12,
|
|
1006
|
-
fontWeight: 600
|
|
1007
|
-
},
|
|
1008
|
-
children: message.senderId.slice(-2).toUpperCase()
|
|
1009
|
-
}
|
|
1010
|
-
) }),
|
|
1011
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1617
|
+
!isOwn && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flexShrink: 0, width: 32 }, children: showAvatarSlot ? renderAvatar ? renderAvatar(message.senderId) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { image: senderImage, name: senderName || message.senderId, size: 32 }) : null }),
|
|
1618
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1012
1619
|
"div",
|
|
1013
1620
|
{
|
|
1014
1621
|
style: {
|
|
@@ -1018,13 +1625,10 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1018
1625
|
alignItems: isOwn ? "flex-end" : "flex-start"
|
|
1019
1626
|
},
|
|
1020
1627
|
children: [
|
|
1021
|
-
(onEdit || onDelete || onReact || onReply) && /* @__PURE__ */ (0,
|
|
1628
|
+
(onEdit || onDelete || onReact || onReply || onOpenThread) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1022
1629
|
"div",
|
|
1023
1630
|
{
|
|
1024
1631
|
style: {
|
|
1025
|
-
display: "flex",
|
|
1026
|
-
flexDirection: isOwn ? "row-reverse" : "row",
|
|
1027
|
-
gap: 2,
|
|
1028
1632
|
marginBottom: 4,
|
|
1029
1633
|
opacity: hovered ? 1 : 0,
|
|
1030
1634
|
pointerEvents: hovered ? "auto" : "none",
|
|
@@ -1032,55 +1636,86 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1032
1636
|
position: "relative"
|
|
1033
1637
|
},
|
|
1034
1638
|
children: [
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
ActionBtn,
|
|
1038
|
-
{
|
|
1039
|
-
onClick: () => setPickerOpen((p) => !p),
|
|
1040
|
-
title: "React",
|
|
1041
|
-
children: "\u{1FAE0}"
|
|
1042
|
-
}
|
|
1043
|
-
),
|
|
1044
|
-
pickerOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1045
|
-
EmojiPicker,
|
|
1046
|
-
{
|
|
1047
|
-
isOwn,
|
|
1048
|
-
onPick: (emoji) => onReact(message._id, emoji),
|
|
1049
|
-
onClose: () => setPickerOpen(false)
|
|
1050
|
-
}
|
|
1051
|
-
)
|
|
1052
|
-
] }),
|
|
1053
|
-
onReply && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActionBtn, { onClick: () => onReply(message), title: "Reply", children: "\u21A9" }),
|
|
1054
|
-
isOwn && onEdit && message.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1055
|
-
ActionBtn,
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1640
|
+
MessageActions,
|
|
1056
1641
|
{
|
|
1057
|
-
|
|
1642
|
+
isOwn,
|
|
1643
|
+
isText: message.type === "text",
|
|
1644
|
+
hasThread: !!message.replyCount && message.replyCount > 0,
|
|
1645
|
+
replyCount: message.replyCount,
|
|
1646
|
+
onReact: onReact ? () => setPickerOpen((p) => !p) : void 0,
|
|
1647
|
+
onReply: onReply ? () => onReply(message) : void 0,
|
|
1648
|
+
onThread: onOpenThread ? () => onOpenThread(message) : void 0,
|
|
1649
|
+
onEdit: onEdit ? () => {
|
|
1058
1650
|
const text = window.prompt("Edit message:", message.text);
|
|
1059
1651
|
if (text) onEdit(message._id, text);
|
|
1060
|
-
},
|
|
1061
|
-
|
|
1062
|
-
|
|
1652
|
+
} : void 0,
|
|
1653
|
+
onDelete: onDelete ? () => onDelete(message._id) : void 0,
|
|
1654
|
+
onPin: onPin ? () => onPin(message) : void 0
|
|
1063
1655
|
}
|
|
1064
1656
|
),
|
|
1065
|
-
|
|
1657
|
+
pickerOpen && onReact && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1658
|
+
"div",
|
|
1659
|
+
{
|
|
1660
|
+
ref: pickerRef,
|
|
1661
|
+
style: {
|
|
1662
|
+
position: "absolute",
|
|
1663
|
+
bottom: "calc(100% + 4px)",
|
|
1664
|
+
[isOwn ? "right" : "left"]: 0,
|
|
1665
|
+
zIndex: 100,
|
|
1666
|
+
background: "#1a1a2e",
|
|
1667
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
1668
|
+
borderRadius: 14,
|
|
1669
|
+
padding: "8px 10px",
|
|
1670
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.4)",
|
|
1671
|
+
display: "flex",
|
|
1672
|
+
gap: 4,
|
|
1673
|
+
animation: "hermes-pop 0.15s ease"
|
|
1674
|
+
},
|
|
1675
|
+
children: REACTION_EMOJIS.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1676
|
+
"button",
|
|
1677
|
+
{
|
|
1678
|
+
onClick: () => {
|
|
1679
|
+
onReact(message._id, emoji);
|
|
1680
|
+
setPickerOpen(false);
|
|
1681
|
+
},
|
|
1682
|
+
style: {
|
|
1683
|
+
background: "none",
|
|
1684
|
+
border: "none",
|
|
1685
|
+
cursor: "pointer",
|
|
1686
|
+
fontSize: 20,
|
|
1687
|
+
padding: "4px",
|
|
1688
|
+
borderRadius: 8,
|
|
1689
|
+
lineHeight: 1,
|
|
1690
|
+
transition: "transform 0.1s"
|
|
1691
|
+
},
|
|
1692
|
+
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.3)",
|
|
1693
|
+
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
1694
|
+
children: emoji
|
|
1695
|
+
},
|
|
1696
|
+
emoji
|
|
1697
|
+
))
|
|
1698
|
+
}
|
|
1699
|
+
)
|
|
1066
1700
|
]
|
|
1067
1701
|
}
|
|
1068
1702
|
),
|
|
1069
|
-
/* @__PURE__ */ (0,
|
|
1703
|
+
!isOwn && (groupStyle === "top" || groupStyle === "single") && senderName && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 11, fontWeight: 600, opacity: 0.6, marginBottom: 2, marginLeft: 4 }, children: senderName }),
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1070
1705
|
"div",
|
|
1071
1706
|
{
|
|
1072
1707
|
style: {
|
|
1073
1708
|
padding: "8px 12px",
|
|
1074
|
-
borderRadius: isOwn ? "16px 16px 4px 16px" : "16px 16px 16px 4px",
|
|
1709
|
+
borderRadius: isOwn ? groupStyle === "top" || groupStyle === "single" ? "16px 16px 4px 16px" : "16px 4px 4px 16px" : groupStyle === "top" || groupStyle === "single" ? "16px 16px 16px 4px" : "4px 16px 16px 4px",
|
|
1075
1710
|
background: isOwn ? "#0084ff" : "#f0f0f0",
|
|
1076
1711
|
color: isOwn ? "#fff" : "#000"
|
|
1077
1712
|
},
|
|
1078
1713
|
children: [
|
|
1079
|
-
message.replyTo && /* @__PURE__ */ (0,
|
|
1714
|
+
message.replyTo && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1080
1715
|
"div",
|
|
1081
1716
|
{
|
|
1082
1717
|
style: {
|
|
1083
|
-
borderLeft:
|
|
1718
|
+
borderLeft: `3px solid ${isOwn ? "rgba(255,255,255,0.4)" : "rgba(0,132,255,0.4)"}`,
|
|
1084
1719
|
paddingLeft: 8,
|
|
1085
1720
|
marginBottom: 6,
|
|
1086
1721
|
fontSize: 12,
|
|
@@ -1089,27 +1724,24 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1089
1724
|
children: "Replying to a message"
|
|
1090
1725
|
}
|
|
1091
1726
|
),
|
|
1092
|
-
message.type === "text" && /* @__PURE__ */ (0,
|
|
1727
|
+
message.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { style: { margin: 0, wordBreak: "break-word" }, children: [
|
|
1093
1728
|
message.text,
|
|
1094
|
-
message.editedAt && /* @__PURE__ */ (0,
|
|
1729
|
+
message.editedAt && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 10, opacity: 0.6, marginLeft: 6 }, children: "(edited)" })
|
|
1095
1730
|
] }),
|
|
1096
|
-
message.type === "link" && /* @__PURE__ */ (0,
|
|
1097
|
-
message.text && /* @__PURE__ */ (0,
|
|
1098
|
-
/* @__PURE__ */ (0,
|
|
1731
|
+
message.type === "link" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
1732
|
+
message.text && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { margin: "0 0 4px" }, children: message.text }),
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1099
1734
|
"a",
|
|
1100
1735
|
{
|
|
1101
1736
|
href: message.url,
|
|
1102
1737
|
target: "_blank",
|
|
1103
1738
|
rel: "noopener noreferrer",
|
|
1104
|
-
style: {
|
|
1105
|
-
color: isOwn ? "#cce4ff" : "#0084ff",
|
|
1106
|
-
wordBreak: "break-all"
|
|
1107
|
-
},
|
|
1739
|
+
style: { color: isOwn ? "#cce4ff" : "#0084ff", wordBreak: "break-all" },
|
|
1108
1740
|
children: message.url
|
|
1109
1741
|
}
|
|
1110
1742
|
)
|
|
1111
1743
|
] }),
|
|
1112
|
-
message.type === "image" && /* @__PURE__ */ (0,
|
|
1744
|
+
message.type === "image" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1113
1745
|
"img",
|
|
1114
1746
|
{
|
|
1115
1747
|
src: message.url,
|
|
@@ -1117,16 +1749,17 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1117
1749
|
style: { maxWidth: "100%", borderRadius: 8, display: "block" }
|
|
1118
1750
|
}
|
|
1119
1751
|
),
|
|
1120
|
-
message.type === "video" && /* @__PURE__ */ (0,
|
|
1752
|
+
message.type === "video" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1121
1753
|
"video",
|
|
1122
1754
|
{
|
|
1123
1755
|
src: message.url,
|
|
1756
|
+
poster: message.thumbnail,
|
|
1124
1757
|
controls: true,
|
|
1125
1758
|
style: { maxWidth: "100%", borderRadius: 8 }
|
|
1126
1759
|
}
|
|
1127
1760
|
),
|
|
1128
|
-
message.type === "audio" && /* @__PURE__ */ (0,
|
|
1129
|
-
message.type === "document" && /* @__PURE__ */ (0,
|
|
1761
|
+
message.type === "audio" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("audio", { src: message.url, controls: true, style: { width: "100%" } }),
|
|
1762
|
+
message.type === "document" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1130
1763
|
"a",
|
|
1131
1764
|
{
|
|
1132
1765
|
href: message.url,
|
|
@@ -1140,67 +1773,90 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1140
1773
|
textDecoration: "none"
|
|
1141
1774
|
},
|
|
1142
1775
|
children: [
|
|
1143
|
-
/* @__PURE__ */ (0,
|
|
1144
|
-
/* @__PURE__ */ (0,
|
|
1145
|
-
/* @__PURE__ */ (0,
|
|
1146
|
-
/* @__PURE__ */ (0,
|
|
1776
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 24 }, children: "\u{1F4C4}" }),
|
|
1777
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
1778
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, fontSize: 13 }, children: message.fileName }),
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontSize: 11, opacity: 0.7 }, children: formatFileSize(message.fileSize) })
|
|
1147
1780
|
] })
|
|
1148
1781
|
]
|
|
1149
1782
|
}
|
|
1150
1783
|
),
|
|
1151
|
-
/* @__PURE__ */ (0,
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1152
1785
|
"div",
|
|
1153
1786
|
{
|
|
1154
1787
|
style: {
|
|
1788
|
+
display: "flex",
|
|
1789
|
+
alignItems: "center",
|
|
1790
|
+
justifyContent: "flex-end",
|
|
1791
|
+
gap: 4,
|
|
1155
1792
|
fontSize: 10,
|
|
1156
1793
|
opacity: 0.6,
|
|
1157
|
-
textAlign: "right",
|
|
1158
1794
|
marginTop: 4
|
|
1159
1795
|
},
|
|
1160
|
-
children:
|
|
1796
|
+
children: [
|
|
1797
|
+
formatTime(message.createdAt),
|
|
1798
|
+
message.pinnedAt && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { title: "Pinned", children: "\u{1F4CC}" }),
|
|
1799
|
+
isOwn && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1800
|
+
MessageStatus,
|
|
1801
|
+
{
|
|
1802
|
+
status: message.deliveryStatus,
|
|
1803
|
+
seenCount: message.seenBy?.length || 0,
|
|
1804
|
+
isMyMessage: isOwn
|
|
1805
|
+
}
|
|
1806
|
+
)
|
|
1807
|
+
]
|
|
1161
1808
|
}
|
|
1162
1809
|
)
|
|
1163
1810
|
]
|
|
1164
1811
|
}
|
|
1165
1812
|
),
|
|
1166
|
-
message.
|
|
1167
|
-
"
|
|
1813
|
+
message.replyCount && message.replyCount > 0 && onOpenThread && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1814
|
+
"button",
|
|
1168
1815
|
{
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
"
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
userSelect: "none"
|
|
1186
|
-
},
|
|
1187
|
-
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
|
|
1188
|
-
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
1189
|
-
children: [
|
|
1190
|
-
r.emoji,
|
|
1191
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1192
|
-
"span",
|
|
1193
|
-
{
|
|
1194
|
-
style: { fontSize: 11, fontWeight: 600, color: "#555" },
|
|
1195
|
-
children: r.users.length
|
|
1196
|
-
}
|
|
1197
|
-
)
|
|
1198
|
-
]
|
|
1199
|
-
},
|
|
1200
|
-
r.emoji
|
|
1201
|
-
))
|
|
1816
|
+
onClick: () => onOpenThread(message),
|
|
1817
|
+
style: {
|
|
1818
|
+
background: "none",
|
|
1819
|
+
border: "none",
|
|
1820
|
+
color: "#0084ff",
|
|
1821
|
+
cursor: "pointer",
|
|
1822
|
+
fontSize: 12,
|
|
1823
|
+
fontWeight: 600,
|
|
1824
|
+
padding: "2px 4px",
|
|
1825
|
+
marginTop: 2
|
|
1826
|
+
},
|
|
1827
|
+
children: [
|
|
1828
|
+
message.replyCount,
|
|
1829
|
+
" ",
|
|
1830
|
+
message.replyCount === 1 ? "reply" : "replies"
|
|
1831
|
+
]
|
|
1202
1832
|
}
|
|
1203
|
-
)
|
|
1833
|
+
),
|
|
1834
|
+
message.reactions?.filter((r) => r.users.length > 0).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", gap: 4, flexWrap: "wrap", marginTop: 4 }, children: message.reactions.filter((r) => r.users.length > 0).map((r) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1835
|
+
"span",
|
|
1836
|
+
{
|
|
1837
|
+
onClick: () => onReact?.(message._id, r.emoji),
|
|
1838
|
+
style: {
|
|
1839
|
+
background: "#f0f0f0",
|
|
1840
|
+
border: "1px solid rgba(0,0,0,0.08)",
|
|
1841
|
+
borderRadius: 20,
|
|
1842
|
+
padding: "2px 8px",
|
|
1843
|
+
fontSize: 13,
|
|
1844
|
+
cursor: onReact ? "pointer" : "default",
|
|
1845
|
+
display: "flex",
|
|
1846
|
+
alignItems: "center",
|
|
1847
|
+
gap: 4,
|
|
1848
|
+
transition: "transform 0.1s",
|
|
1849
|
+
userSelect: "none"
|
|
1850
|
+
},
|
|
1851
|
+
onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
|
|
1852
|
+
onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
|
|
1853
|
+
children: [
|
|
1854
|
+
r.emoji,
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 11, fontWeight: 600, color: "#555" }, children: r.users.length })
|
|
1856
|
+
]
|
|
1857
|
+
},
|
|
1858
|
+
r.emoji
|
|
1859
|
+
)) })
|
|
1204
1860
|
]
|
|
1205
1861
|
}
|
|
1206
1862
|
)
|
|
@@ -1208,52 +1864,277 @@ var DefaultMessage = ({ message, isOwn, onEdit, onDelete, onReact, onReply, rend
|
|
|
1208
1864
|
}
|
|
1209
1865
|
);
|
|
1210
1866
|
};
|
|
1211
|
-
|
|
1212
|
-
|
|
1867
|
+
|
|
1868
|
+
// src/react/components/DateSeparator/DateSeparator.tsx
|
|
1869
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1870
|
+
var defaultFormat = (date) => {
|
|
1871
|
+
const now = /* @__PURE__ */ new Date();
|
|
1872
|
+
const isToday = date.getDate() === now.getDate() && date.getMonth() === now.getMonth() && date.getFullYear() === now.getFullYear();
|
|
1873
|
+
const yesterday = new Date(now);
|
|
1874
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
1875
|
+
const isYesterday = date.getDate() === yesterday.getDate() && date.getMonth() === yesterday.getMonth() && date.getFullYear() === yesterday.getFullYear();
|
|
1876
|
+
if (isToday) return "Today";
|
|
1877
|
+
if (isYesterday) return "Yesterday";
|
|
1878
|
+
return date.toLocaleDateString(void 0, {
|
|
1879
|
+
weekday: "long",
|
|
1880
|
+
year: "numeric",
|
|
1881
|
+
month: "long",
|
|
1882
|
+
day: "numeric"
|
|
1883
|
+
});
|
|
1884
|
+
};
|
|
1885
|
+
var DateSeparator = ({
|
|
1886
|
+
date,
|
|
1887
|
+
formatDate = defaultFormat,
|
|
1888
|
+
className = ""
|
|
1889
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1890
|
+
"div",
|
|
1213
1891
|
{
|
|
1214
|
-
|
|
1215
|
-
title,
|
|
1892
|
+
className: `hermes-date-separator ${className}`,
|
|
1216
1893
|
style: {
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
fontSize: 14,
|
|
1222
|
-
padding: "3px 6px",
|
|
1223
|
-
lineHeight: 1,
|
|
1224
|
-
boxShadow: "0 1px 4px rgba(0,0,0,0.1)",
|
|
1225
|
-
transition: "transform 0.1s"
|
|
1894
|
+
display: "flex",
|
|
1895
|
+
alignItems: "center",
|
|
1896
|
+
gap: 12,
|
|
1897
|
+
padding: "16px 0"
|
|
1226
1898
|
},
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1899
|
+
children: [
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1901
|
+
"div",
|
|
1902
|
+
{
|
|
1903
|
+
style: { flex: 1, height: 1, background: "rgba(128,128,128,0.2)" }
|
|
1904
|
+
}
|
|
1905
|
+
),
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1907
|
+
"span",
|
|
1908
|
+
{
|
|
1909
|
+
style: {
|
|
1910
|
+
fontSize: 12,
|
|
1911
|
+
fontWeight: 600,
|
|
1912
|
+
color: "rgba(128,128,128,0.7)",
|
|
1913
|
+
whiteSpace: "nowrap",
|
|
1914
|
+
userSelect: "none"
|
|
1915
|
+
},
|
|
1916
|
+
children: formatDate(date)
|
|
1917
|
+
}
|
|
1918
|
+
),
|
|
1919
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1920
|
+
"div",
|
|
1921
|
+
{
|
|
1922
|
+
style: { flex: 1, height: 1, background: "rgba(128,128,128,0.2)" }
|
|
1923
|
+
}
|
|
1924
|
+
)
|
|
1925
|
+
]
|
|
1230
1926
|
}
|
|
1231
1927
|
);
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1928
|
+
|
|
1929
|
+
// src/react/components/EmptyStateIndicator/EmptyStateIndicator.tsx
|
|
1930
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1931
|
+
var DEFAULT_TEXTS = {
|
|
1932
|
+
message: "No messages yet. Say hello! \u{1F44B}",
|
|
1933
|
+
room: "No conversations yet.",
|
|
1934
|
+
thread: "No replies yet.",
|
|
1935
|
+
search: "No results found."
|
|
1936
|
+
};
|
|
1937
|
+
var EmptyStateIndicator = ({
|
|
1938
|
+
listType = "message",
|
|
1939
|
+
text,
|
|
1940
|
+
className = ""
|
|
1941
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1942
|
+
"div",
|
|
1943
|
+
{
|
|
1944
|
+
className: `hermes-empty-state ${className}`,
|
|
1945
|
+
style: {
|
|
1946
|
+
display: "flex",
|
|
1947
|
+
flexDirection: "column",
|
|
1948
|
+
alignItems: "center",
|
|
1949
|
+
justifyContent: "center",
|
|
1950
|
+
gap: 8,
|
|
1951
|
+
padding: 32,
|
|
1952
|
+
textAlign: "center",
|
|
1953
|
+
opacity: 0.5,
|
|
1954
|
+
flex: 1
|
|
1955
|
+
},
|
|
1956
|
+
children: [
|
|
1957
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontSize: 36 }, children: listType === "message" ? "\u{1F4AC}" : listType === "room" ? "\u{1F4ED}" : listType === "thread" ? "\u{1F9F5}" : "\u{1F50D}" }),
|
|
1958
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontSize: 14 }, children: text || DEFAULT_TEXTS[listType] })
|
|
1959
|
+
]
|
|
1960
|
+
}
|
|
1961
|
+
);
|
|
1962
|
+
|
|
1963
|
+
// src/react/components/Loading/LoadingIndicator.tsx
|
|
1964
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1965
|
+
var LoadingIndicator = ({
|
|
1966
|
+
size = 32,
|
|
1967
|
+
color = "#0084ff",
|
|
1968
|
+
text,
|
|
1969
|
+
className = ""
|
|
1970
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1971
|
+
"div",
|
|
1972
|
+
{
|
|
1973
|
+
className: `hermes-loading ${className}`,
|
|
1974
|
+
style: {
|
|
1975
|
+
display: "flex",
|
|
1976
|
+
flexDirection: "column",
|
|
1977
|
+
alignItems: "center",
|
|
1978
|
+
justifyContent: "center",
|
|
1979
|
+
gap: 8,
|
|
1980
|
+
padding: 16
|
|
1981
|
+
},
|
|
1982
|
+
children: [
|
|
1983
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1984
|
+
"div",
|
|
1985
|
+
{
|
|
1986
|
+
style: {
|
|
1987
|
+
width: size,
|
|
1988
|
+
height: size,
|
|
1989
|
+
border: `3px solid rgba(128,128,128,0.15)`,
|
|
1990
|
+
borderTopColor: color,
|
|
1991
|
+
borderRadius: "50%",
|
|
1992
|
+
animation: "hermes-spin 0.8s linear infinite"
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
text && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 13, opacity: 0.6 }, children: text }),
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("style", { children: `
|
|
1998
|
+
@keyframes hermes-spin {
|
|
1999
|
+
to { transform: rotate(360deg); }
|
|
2000
|
+
}
|
|
2001
|
+
` })
|
|
2002
|
+
]
|
|
2003
|
+
}
|
|
2004
|
+
);
|
|
2005
|
+
var LoadingErrorIndicator = ({
|
|
2006
|
+
error,
|
|
2007
|
+
onRetry,
|
|
2008
|
+
className = ""
|
|
1248
2009
|
}) => {
|
|
1249
|
-
|
|
1250
|
-
const
|
|
1251
|
-
(0,
|
|
2010
|
+
if (!error) return null;
|
|
2011
|
+
const message = typeof error === "string" ? error : error.message;
|
|
2012
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2013
|
+
"div",
|
|
2014
|
+
{
|
|
2015
|
+
className: `hermes-loading-error ${className}`,
|
|
2016
|
+
style: {
|
|
2017
|
+
display: "flex",
|
|
2018
|
+
flexDirection: "column",
|
|
2019
|
+
alignItems: "center",
|
|
2020
|
+
justifyContent: "center",
|
|
2021
|
+
gap: 8,
|
|
2022
|
+
padding: 24,
|
|
2023
|
+
textAlign: "center"
|
|
2024
|
+
},
|
|
2025
|
+
children: [
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 28 }, children: "\u26A0\uFE0F" }),
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 14, opacity: 0.7 }, children: message }),
|
|
2028
|
+
onRetry && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2029
|
+
"button",
|
|
2030
|
+
{
|
|
2031
|
+
onClick: onRetry,
|
|
2032
|
+
style: {
|
|
2033
|
+
marginTop: 4,
|
|
2034
|
+
padding: "6px 16px",
|
|
2035
|
+
border: "1px solid rgba(128,128,128,0.3)",
|
|
2036
|
+
borderRadius: 8,
|
|
2037
|
+
background: "none",
|
|
2038
|
+
cursor: "pointer",
|
|
2039
|
+
fontSize: 13,
|
|
2040
|
+
fontWeight: 600
|
|
2041
|
+
},
|
|
2042
|
+
children: "Retry"
|
|
2043
|
+
}
|
|
2044
|
+
)
|
|
2045
|
+
]
|
|
2046
|
+
}
|
|
2047
|
+
);
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
// src/react/components/TypingIndicator.tsx
|
|
2051
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2052
|
+
var TypingIndicator = ({
|
|
2053
|
+
typingText,
|
|
2054
|
+
className = ""
|
|
2055
|
+
}) => {
|
|
2056
|
+
if (!typingText) return null;
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
2058
|
+
"div",
|
|
2059
|
+
{
|
|
2060
|
+
className: `hermes-typing-indicator ${className}`,
|
|
2061
|
+
style: {
|
|
2062
|
+
display: "flex",
|
|
2063
|
+
alignItems: "center",
|
|
2064
|
+
gap: 6,
|
|
2065
|
+
padding: "4px 16px",
|
|
2066
|
+
minHeight: 24
|
|
2067
|
+
},
|
|
2068
|
+
children: [
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { display: "flex", gap: 3 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2070
|
+
"span",
|
|
2071
|
+
{
|
|
2072
|
+
style: {
|
|
2073
|
+
width: 6,
|
|
2074
|
+
height: 6,
|
|
2075
|
+
borderRadius: "50%",
|
|
2076
|
+
background: "#aaa",
|
|
2077
|
+
display: "block",
|
|
2078
|
+
animation: `hermes-bounce 1.2s ease-in-out ${i * 0.2}s infinite`
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2081
|
+
i
|
|
2082
|
+
)) }),
|
|
2083
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { fontSize: 12, opacity: 0.6 }, children: typingText }),
|
|
2084
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("style", { children: `
|
|
2085
|
+
@keyframes hermes-bounce {
|
|
2086
|
+
0%, 80%, 100% { transform: translateY(0); }
|
|
2087
|
+
40% { transform: translateY(-4px); }
|
|
2088
|
+
}
|
|
2089
|
+
` })
|
|
2090
|
+
]
|
|
2091
|
+
}
|
|
2092
|
+
);
|
|
2093
|
+
};
|
|
2094
|
+
|
|
2095
|
+
// src/react/components/MessageList.tsx
|
|
2096
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2097
|
+
var isSameDay = (d1, d2) => {
|
|
2098
|
+
const a = new Date(d1);
|
|
2099
|
+
const b = new Date(d2);
|
|
2100
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
2101
|
+
};
|
|
2102
|
+
var MessageList = (props) => {
|
|
2103
|
+
const chatCtx = useChatContext("MessageList");
|
|
2104
|
+
const roomStateCtx = useRoomStateContext("MessageList");
|
|
2105
|
+
const roomActionCtx = useRoomActionContext("MessageList");
|
|
2106
|
+
const typingCtx = useTypingContext("MessageList");
|
|
2107
|
+
const componentCtx = useComponentContext("MessageList");
|
|
2108
|
+
const messages = props.messages ?? roomStateCtx.messages ?? [];
|
|
2109
|
+
const currentUser = props.currentUser ?? chatCtx.currentUser;
|
|
2110
|
+
const loading = props.loading ?? roomStateCtx.loading ?? false;
|
|
2111
|
+
const loadingMore = props.loadingMore ?? roomStateCtx.loadingMore ?? false;
|
|
2112
|
+
const hasMore = props.hasMore ?? roomStateCtx.hasMore ?? false;
|
|
2113
|
+
const onLoadMore = props.onLoadMore ?? roomActionCtx.loadMore;
|
|
2114
|
+
const onEdit = props.onEdit ?? (roomActionCtx.editMessage ? (id, text) => roomActionCtx.editMessage(id, text) : void 0);
|
|
2115
|
+
const onDelete = props.onDelete ?? (roomActionCtx.deleteMessage ? (id) => roomActionCtx.deleteMessage(id) : void 0);
|
|
2116
|
+
const onReact = props.onReact ?? (roomActionCtx.addReaction ? (id, emoji) => roomActionCtx.addReaction(id, emoji) : void 0);
|
|
2117
|
+
const onReply = props.onReply;
|
|
2118
|
+
const onOpenThread = props.onOpenThread ?? (roomActionCtx.openThread ? (msg) => roomActionCtx.openThread(msg) : void 0);
|
|
2119
|
+
const autoScroll = props.autoScroll ?? true;
|
|
2120
|
+
const disableDateSeparator = props.disableDateSeparator ?? false;
|
|
2121
|
+
const className = props.className ?? "";
|
|
2122
|
+
const renderMessage = props.renderMessage;
|
|
2123
|
+
const renderAvatar = props.renderAvatar;
|
|
2124
|
+
const typingText = props.typingText ?? typingCtx.typingText ?? null;
|
|
2125
|
+
const MessageComponent = componentCtx.Message || Message;
|
|
2126
|
+
const DateSepComponent = componentCtx.DateSeparator || DateSeparator;
|
|
2127
|
+
const EmptyComponent = componentCtx.EmptyStateIndicator || EmptyStateIndicator;
|
|
2128
|
+
const LoadingComponent = componentCtx.LoadingIndicator || LoadingIndicator;
|
|
2129
|
+
const TypingComponent = componentCtx.TypingIndicator || TypingIndicator;
|
|
2130
|
+
const bottomRef = (0, import_react17.useRef)(null);
|
|
2131
|
+
const containerRef = (0, import_react17.useRef)(null);
|
|
2132
|
+
(0, import_react17.useEffect)(() => {
|
|
1252
2133
|
if (autoScroll && bottomRef.current) {
|
|
1253
2134
|
bottomRef.current.scrollIntoView({ behavior: "smooth" });
|
|
1254
2135
|
}
|
|
1255
2136
|
}, [messages, autoScroll]);
|
|
1256
|
-
(0,
|
|
2137
|
+
(0, import_react17.useEffect)(() => {
|
|
1257
2138
|
const container = containerRef.current;
|
|
1258
2139
|
if (!container || !onLoadMore) return;
|
|
1259
2140
|
const onScroll = () => {
|
|
@@ -1263,21 +2144,33 @@ var MessageList = ({
|
|
|
1263
2144
|
return () => container.removeEventListener("scroll", onScroll);
|
|
1264
2145
|
}, [hasMore, loadingMore, onLoadMore]);
|
|
1265
2146
|
if (loading) {
|
|
1266
|
-
return /* @__PURE__ */ (0,
|
|
2147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1267
2148
|
"div",
|
|
1268
2149
|
{
|
|
1269
2150
|
style: {
|
|
1270
2151
|
display: "flex",
|
|
1271
2152
|
alignItems: "center",
|
|
1272
2153
|
justifyContent: "center",
|
|
1273
|
-
height: "100%"
|
|
2154
|
+
height: "100%",
|
|
2155
|
+
flex: 1
|
|
1274
2156
|
},
|
|
1275
|
-
children: "Loading messages..."
|
|
2157
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LoadingComponent, { text: "Loading messages..." })
|
|
1276
2158
|
}
|
|
1277
2159
|
);
|
|
1278
2160
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
2161
|
+
const getGroupStyle = (index) => {
|
|
2162
|
+
const msg = messages[index];
|
|
2163
|
+
const prev = index > 0 ? messages[index - 1] : null;
|
|
2164
|
+
const next = index < messages.length - 1 ? messages[index + 1] : null;
|
|
2165
|
+
const sameSenderPrev = prev && prev.senderId === msg.senderId && !prev.isDeleted && isSameDay(prev.createdAt, msg.createdAt);
|
|
2166
|
+
const sameSenderNext = next && next.senderId === msg.senderId && !next.isDeleted && isSameDay(next.createdAt, msg.createdAt);
|
|
2167
|
+
if (sameSenderPrev && sameSenderNext) return "middle";
|
|
2168
|
+
if (sameSenderPrev) return "bottom";
|
|
2169
|
+
if (sameSenderNext) return "top";
|
|
2170
|
+
return "single";
|
|
2171
|
+
};
|
|
2172
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
2173
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("style", { children: `
|
|
1281
2174
|
@keyframes hermes-bounce {
|
|
1282
2175
|
0%, 80%, 100% { transform: translateY(0); }
|
|
1283
2176
|
40% { transform: translateY(-5px); }
|
|
@@ -1287,7 +2180,7 @@ var MessageList = ({
|
|
|
1287
2180
|
to { opacity: 1; transform: scale(1); }
|
|
1288
2181
|
}
|
|
1289
2182
|
` }),
|
|
1290
|
-
/* @__PURE__ */ (0,
|
|
2183
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1291
2184
|
"div",
|
|
1292
2185
|
{
|
|
1293
2186
|
ref: containerRef,
|
|
@@ -1296,11 +2189,11 @@ var MessageList = ({
|
|
|
1296
2189
|
overflowY: "auto",
|
|
1297
2190
|
display: "flex",
|
|
1298
2191
|
flexDirection: "column",
|
|
1299
|
-
|
|
2192
|
+
flex: 1,
|
|
1300
2193
|
padding: "16px"
|
|
1301
2194
|
},
|
|
1302
2195
|
children: [
|
|
1303
|
-
hasMore && /* @__PURE__ */ (0,
|
|
2196
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { textAlign: "center", marginBottom: 12 }, children: loadingMore ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LoadingComponent, { size: 20, text: "Loading older messages..." }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1304
2197
|
"button",
|
|
1305
2198
|
{
|
|
1306
2199
|
onClick: onLoadMore,
|
|
@@ -1315,35 +2208,32 @@ var MessageList = ({
|
|
|
1315
2208
|
children: "Load older messages"
|
|
1316
2209
|
}
|
|
1317
2210
|
) }),
|
|
1318
|
-
messages.length === 0 && /* @__PURE__ */ (0,
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
renderAvatar
|
|
1342
|
-
}
|
|
1343
|
-
) }, message._id);
|
|
2211
|
+
messages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmptyComponent, { listType: "message" }),
|
|
2212
|
+
messages.map((message, index) => {
|
|
2213
|
+
const isOwn = message.senderId === currentUser?.userId;
|
|
2214
|
+
const groupStyle = getGroupStyle(index);
|
|
2215
|
+
const showDateSep = !disableDateSeparator && (index === 0 || !isSameDay(messages[index - 1].createdAt, message.createdAt));
|
|
2216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react17.default.Fragment, { children: [
|
|
2217
|
+
showDateSep && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DateSepComponent, { date: new Date(message.createdAt) }),
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginBottom: groupStyle === "bottom" || groupStyle === "single" ? 8 : 2 }, children: renderMessage ? renderMessage(message, isOwn) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2219
|
+
MessageComponent,
|
|
2220
|
+
{
|
|
2221
|
+
message,
|
|
2222
|
+
isOwn,
|
|
2223
|
+
onEdit,
|
|
2224
|
+
onDelete,
|
|
2225
|
+
onReact,
|
|
2226
|
+
onReply,
|
|
2227
|
+
onOpenThread,
|
|
2228
|
+
renderAvatar,
|
|
2229
|
+
groupStyle,
|
|
2230
|
+
showAvatar: true
|
|
2231
|
+
}
|
|
2232
|
+
) })
|
|
2233
|
+
] }, message._id);
|
|
1344
2234
|
}),
|
|
1345
|
-
/* @__PURE__ */ (0,
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
2235
|
+
typingText && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TypingComponent, { typingText }),
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: bottomRef })
|
|
1347
2237
|
]
|
|
1348
2238
|
}
|
|
1349
2239
|
)
|
|
@@ -1351,28 +2241,34 @@ var MessageList = ({
|
|
|
1351
2241
|
};
|
|
1352
2242
|
|
|
1353
2243
|
// src/react/components/ChatInput.tsx
|
|
1354
|
-
var
|
|
1355
|
-
var
|
|
1356
|
-
var ChatInput = ({
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
2244
|
+
var import_react18 = require("react");
|
|
2245
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2246
|
+
var ChatInput = (props) => {
|
|
2247
|
+
const roomActionCtx = useRoomActionContext("ChatInput");
|
|
2248
|
+
const typingCtx = useTypingContext("ChatInput");
|
|
2249
|
+
const chatCtx = useChatContext("ChatInput");
|
|
2250
|
+
const onSendText = props.onSendText ?? (roomActionCtx.sendMessage ? async (text2) => {
|
|
2251
|
+
await roomActionCtx.sendMessage({ type: "text", text: text2 });
|
|
2252
|
+
} : void 0);
|
|
2253
|
+
const onSendFile = props.onSendFile;
|
|
2254
|
+
const onTypingStart = props.onTypingStart ?? typingCtx.startTyping;
|
|
2255
|
+
const onTypingStop = props.onTypingStop ?? typingCtx.stopTyping;
|
|
2256
|
+
const {
|
|
2257
|
+
replyingTo,
|
|
2258
|
+
onCancelReply,
|
|
2259
|
+
disabled = false,
|
|
2260
|
+
placeholder = "Type a message...",
|
|
2261
|
+
maxLength = 4e3,
|
|
2262
|
+
className = "",
|
|
2263
|
+
inputClassName = "",
|
|
2264
|
+
renderAttachIcon,
|
|
2265
|
+
renderSendIcon
|
|
2266
|
+
} = props;
|
|
2267
|
+
const [text, setText] = (0, import_react18.useState)("");
|
|
2268
|
+
const [sending, setSending] = (0, import_react18.useState)(false);
|
|
2269
|
+
const fileRef = (0, import_react18.useRef)(null);
|
|
2270
|
+
const textareaRef = (0, import_react18.useRef)(null);
|
|
2271
|
+
const resizeTextarea = (0, import_react18.useCallback)(() => {
|
|
1376
2272
|
const el = textareaRef.current;
|
|
1377
2273
|
if (!el) return;
|
|
1378
2274
|
el.style.height = "auto";
|
|
@@ -1385,7 +2281,7 @@ var ChatInput = ({
|
|
|
1385
2281
|
};
|
|
1386
2282
|
const handleSend = async () => {
|
|
1387
2283
|
const trimmed = text.trim();
|
|
1388
|
-
if (!trimmed || sending || disabled) return;
|
|
2284
|
+
if (!trimmed || sending || disabled || !onSendText) return;
|
|
1389
2285
|
setSending(true);
|
|
1390
2286
|
try {
|
|
1391
2287
|
await onSendText(trimmed);
|
|
@@ -1408,7 +2304,7 @@ var ChatInput = ({
|
|
|
1408
2304
|
await onSendFile(file);
|
|
1409
2305
|
if (fileRef.current) fileRef.current.value = "";
|
|
1410
2306
|
};
|
|
1411
|
-
return /* @__PURE__ */ (0,
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1412
2308
|
"div",
|
|
1413
2309
|
{
|
|
1414
2310
|
className: `hermes-chat-input ${className}`,
|
|
@@ -1419,7 +2315,7 @@ var ChatInput = ({
|
|
|
1419
2315
|
borderTop: "1px solid #e0e0e0"
|
|
1420
2316
|
},
|
|
1421
2317
|
children: [
|
|
1422
|
-
replyingTo && /* @__PURE__ */ (0,
|
|
2318
|
+
replyingTo && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1423
2319
|
"div",
|
|
1424
2320
|
{
|
|
1425
2321
|
className: "hermes-chat-input__reply",
|
|
@@ -1435,11 +2331,11 @@ var ChatInput = ({
|
|
|
1435
2331
|
fontSize: 12
|
|
1436
2332
|
},
|
|
1437
2333
|
children: [
|
|
1438
|
-
/* @__PURE__ */ (0,
|
|
1439
|
-
/* @__PURE__ */ (0,
|
|
1440
|
-
/* @__PURE__ */ (0,
|
|
2334
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { overflow: "hidden" }, children: [
|
|
2335
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontWeight: 600, marginRight: 4 }, children: "Replying to:" }),
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { opacity: 0.7 }, children: replyingTo.type === "text" ? replyingTo.text?.slice(0, 60) : `[${replyingTo.type}]` })
|
|
1441
2337
|
] }),
|
|
1442
|
-
/* @__PURE__ */ (0,
|
|
2338
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1443
2339
|
"button",
|
|
1444
2340
|
{
|
|
1445
2341
|
onClick: onCancelReply,
|
|
@@ -1456,14 +2352,14 @@ var ChatInput = ({
|
|
|
1456
2352
|
]
|
|
1457
2353
|
}
|
|
1458
2354
|
),
|
|
1459
|
-
/* @__PURE__ */ (0,
|
|
2355
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1460
2356
|
"div",
|
|
1461
2357
|
{
|
|
1462
2358
|
className: "hermes-chat-input__row",
|
|
1463
2359
|
style: { display: "flex", alignItems: "flex-end", gap: 8 },
|
|
1464
2360
|
children: [
|
|
1465
|
-
onSendFile && /* @__PURE__ */ (0,
|
|
1466
|
-
/* @__PURE__ */ (0,
|
|
2361
|
+
onSendFile && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1467
2363
|
"button",
|
|
1468
2364
|
{
|
|
1469
2365
|
onClick: () => fileRef.current?.click(),
|
|
@@ -1477,23 +2373,10 @@ var ChatInput = ({
|
|
|
1477
2373
|
flexShrink: 0,
|
|
1478
2374
|
opacity: disabled ? 0.4 : 1
|
|
1479
2375
|
},
|
|
1480
|
-
children: renderAttachIcon ? renderAttachIcon() : /* @__PURE__ */ (0,
|
|
1481
|
-
"svg",
|
|
1482
|
-
{
|
|
1483
|
-
width: "20",
|
|
1484
|
-
height: "20",
|
|
1485
|
-
viewBox: "0 0 24 24",
|
|
1486
|
-
fill: "none",
|
|
1487
|
-
stroke: "currentColor",
|
|
1488
|
-
strokeWidth: "2",
|
|
1489
|
-
strokeLinecap: "round",
|
|
1490
|
-
strokeLinejoin: "round",
|
|
1491
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" })
|
|
1492
|
-
}
|
|
1493
|
-
)
|
|
2376
|
+
children: renderAttachIcon ? renderAttachIcon() : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" }) })
|
|
1494
2377
|
}
|
|
1495
2378
|
),
|
|
1496
|
-
/* @__PURE__ */ (0,
|
|
2379
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1497
2380
|
"input",
|
|
1498
2381
|
{
|
|
1499
2382
|
ref: fileRef,
|
|
@@ -1504,7 +2387,7 @@ var ChatInput = ({
|
|
|
1504
2387
|
}
|
|
1505
2388
|
)
|
|
1506
2389
|
] }),
|
|
1507
|
-
/* @__PURE__ */ (0,
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1508
2391
|
"textarea",
|
|
1509
2392
|
{
|
|
1510
2393
|
ref: textareaRef,
|
|
@@ -1531,7 +2414,7 @@ var ChatInput = ({
|
|
|
1531
2414
|
}
|
|
1532
2415
|
}
|
|
1533
2416
|
),
|
|
1534
|
-
/* @__PURE__ */ (0,
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1535
2418
|
"button",
|
|
1536
2419
|
{
|
|
1537
2420
|
onClick: handleSend,
|
|
@@ -1545,35 +2428,24 @@ var ChatInput = ({
|
|
|
1545
2428
|
flexShrink: 0,
|
|
1546
2429
|
opacity: !text.trim() || sending || disabled ? 0.4 : 1
|
|
1547
2430
|
},
|
|
1548
|
-
children: renderSendIcon ? renderSendIcon() : /* @__PURE__ */ (0,
|
|
2431
|
+
children: renderSendIcon ? renderSendIcon() : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) })
|
|
1549
2432
|
}
|
|
1550
2433
|
)
|
|
1551
2434
|
]
|
|
1552
2435
|
}
|
|
1553
2436
|
),
|
|
1554
|
-
text.length > maxLength * 0.8 && /* @__PURE__ */ (0,
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
textAlign: "right",
|
|
1560
|
-
opacity: 0.5,
|
|
1561
|
-
marginTop: 2
|
|
1562
|
-
},
|
|
1563
|
-
children: [
|
|
1564
|
-
text.length,
|
|
1565
|
-
"/",
|
|
1566
|
-
maxLength
|
|
1567
|
-
]
|
|
1568
|
-
}
|
|
1569
|
-
)
|
|
2437
|
+
text.length > maxLength * 0.8 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { fontSize: 10, textAlign: "right", opacity: 0.5, marginTop: 2 }, children: [
|
|
2438
|
+
text.length,
|
|
2439
|
+
"/",
|
|
2440
|
+
maxLength
|
|
2441
|
+
] })
|
|
1570
2442
|
]
|
|
1571
2443
|
}
|
|
1572
2444
|
);
|
|
1573
2445
|
};
|
|
1574
2446
|
|
|
1575
2447
|
// src/react/components/RoomList.tsx
|
|
1576
|
-
var
|
|
2448
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1577
2449
|
var formatLastActivity = (iso) => {
|
|
1578
2450
|
const date = new Date(iso);
|
|
1579
2451
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1604,7 +2476,7 @@ var getLastMessagePreview = (room) => {
|
|
|
1604
2476
|
if (msg.type === "link") return `\u{1F517} ${msg.url}`;
|
|
1605
2477
|
return "";
|
|
1606
2478
|
};
|
|
1607
|
-
var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassName }) => /* @__PURE__ */ (0,
|
|
2479
|
+
var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassName }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1608
2480
|
"div",
|
|
1609
2481
|
{
|
|
1610
2482
|
className: `hermes-room-item ${isActive ? "hermes-room-item--active" : ""} ${itemClassName ?? ""}`,
|
|
@@ -1618,7 +2490,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1618
2490
|
borderLeft: isActive ? "3px solid #0084ff" : "3px solid transparent"
|
|
1619
2491
|
},
|
|
1620
2492
|
children: [
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { flexShrink: 0 }, children: renderAvatar ? renderAvatar(room) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1622
2494
|
"div",
|
|
1623
2495
|
{
|
|
1624
2496
|
style: {
|
|
@@ -1635,8 +2507,8 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1635
2507
|
children: room.type === "group" ? "G" : "D"
|
|
1636
2508
|
}
|
|
1637
2509
|
) }),
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1639
|
-
/* @__PURE__ */ (0,
|
|
2510
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, overflow: "hidden" }, children: [
|
|
2511
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1640
2512
|
"div",
|
|
1641
2513
|
{
|
|
1642
2514
|
style: {
|
|
@@ -1645,7 +2517,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1645
2517
|
alignItems: "baseline"
|
|
1646
2518
|
},
|
|
1647
2519
|
children: [
|
|
1648
|
-
/* @__PURE__ */ (0,
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1649
2521
|
"span",
|
|
1650
2522
|
{
|
|
1651
2523
|
style: {
|
|
@@ -1658,7 +2530,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1658
2530
|
children: getRoomName(room, currentUserId)
|
|
1659
2531
|
}
|
|
1660
2532
|
),
|
|
1661
|
-
/* @__PURE__ */ (0,
|
|
2533
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1662
2534
|
"span",
|
|
1663
2535
|
{
|
|
1664
2536
|
style: { fontSize: 11, opacity: 0.5, flexShrink: 0, marginLeft: 4 },
|
|
@@ -1668,7 +2540,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1668
2540
|
]
|
|
1669
2541
|
}
|
|
1670
2542
|
),
|
|
1671
|
-
/* @__PURE__ */ (0,
|
|
2543
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1672
2544
|
"div",
|
|
1673
2545
|
{
|
|
1674
2546
|
style: {
|
|
@@ -1678,7 +2550,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1678
2550
|
marginTop: 2
|
|
1679
2551
|
},
|
|
1680
2552
|
children: [
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1682
2554
|
"span",
|
|
1683
2555
|
{
|
|
1684
2556
|
style: {
|
|
@@ -1691,7 +2563,7 @@ var DefaultRoomItem = ({ room, isActive, currentUserId, renderAvatar, itemClassN
|
|
|
1691
2563
|
children: getLastMessagePreview(room)
|
|
1692
2564
|
}
|
|
1693
2565
|
),
|
|
1694
|
-
room.unreadCount > 0 && /* @__PURE__ */ (0,
|
|
2566
|
+
room.unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1695
2567
|
"span",
|
|
1696
2568
|
{
|
|
1697
2569
|
style: {
|
|
@@ -1728,7 +2600,7 @@ var RoomList = ({
|
|
|
1728
2600
|
className = "",
|
|
1729
2601
|
itemClassName = ""
|
|
1730
2602
|
}) => {
|
|
1731
|
-
return /* @__PURE__ */ (0,
|
|
2603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1732
2604
|
"div",
|
|
1733
2605
|
{
|
|
1734
2606
|
className: `hermes-room-list ${className}`,
|
|
@@ -1739,7 +2611,7 @@ var RoomList = ({
|
|
|
1739
2611
|
overflowY: "auto"
|
|
1740
2612
|
},
|
|
1741
2613
|
children: [
|
|
1742
|
-
(onCreateDirect || onCreateGroup) && /* @__PURE__ */ (0,
|
|
2614
|
+
(onCreateDirect || onCreateGroup) && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1743
2615
|
"div",
|
|
1744
2616
|
{
|
|
1745
2617
|
style: {
|
|
@@ -1749,7 +2621,7 @@ var RoomList = ({
|
|
|
1749
2621
|
borderBottom: "1px solid #e0e0e0"
|
|
1750
2622
|
},
|
|
1751
2623
|
children: [
|
|
1752
|
-
onCreateDirect && /* @__PURE__ */ (0,
|
|
2624
|
+
onCreateDirect && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1753
2625
|
"button",
|
|
1754
2626
|
{
|
|
1755
2627
|
onClick: onCreateDirect,
|
|
@@ -1767,7 +2639,7 @@ var RoomList = ({
|
|
|
1767
2639
|
children: "+ Direct"
|
|
1768
2640
|
}
|
|
1769
2641
|
),
|
|
1770
|
-
onCreateGroup && /* @__PURE__ */ (0,
|
|
2642
|
+
onCreateGroup && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1771
2643
|
"button",
|
|
1772
2644
|
{
|
|
1773
2645
|
onClick: onCreateGroup,
|
|
@@ -1787,8 +2659,8 @@ var RoomList = ({
|
|
|
1787
2659
|
]
|
|
1788
2660
|
}
|
|
1789
2661
|
),
|
|
1790
|
-
loading && /* @__PURE__ */ (0,
|
|
1791
|
-
!loading && rooms.length === 0 && /* @__PURE__ */ (0,
|
|
2662
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { padding: "12px 16px", opacity: 0.5, fontSize: 13 }, children: "Loading rooms..." }),
|
|
2663
|
+
!loading && rooms.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1792
2664
|
"div",
|
|
1793
2665
|
{
|
|
1794
2666
|
style: {
|
|
@@ -1802,7 +2674,7 @@ var RoomList = ({
|
|
|
1802
2674
|
),
|
|
1803
2675
|
!loading && rooms.map((room) => {
|
|
1804
2676
|
const isActive = room._id === activeRoomId;
|
|
1805
|
-
return /* @__PURE__ */ (0,
|
|
2677
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { onClick: () => onSelectRoom(room), children: renderRoomItem ? renderRoomItem(room, isActive) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1806
2678
|
DefaultRoomItem,
|
|
1807
2679
|
{
|
|
1808
2680
|
room,
|
|
@@ -1818,58 +2690,13 @@ var RoomList = ({
|
|
|
1818
2690
|
);
|
|
1819
2691
|
};
|
|
1820
2692
|
|
|
1821
|
-
// src/react/components/TypingIndicator.tsx
|
|
1822
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1823
|
-
var TypingIndicator2 = ({
|
|
1824
|
-
typingText,
|
|
1825
|
-
className = ""
|
|
1826
|
-
}) => {
|
|
1827
|
-
if (!typingText) return null;
|
|
1828
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1829
|
-
"div",
|
|
1830
|
-
{
|
|
1831
|
-
className: `hermes-typing-indicator ${className}`,
|
|
1832
|
-
style: {
|
|
1833
|
-
display: "flex",
|
|
1834
|
-
alignItems: "center",
|
|
1835
|
-
gap: 6,
|
|
1836
|
-
padding: "4px 16px",
|
|
1837
|
-
minHeight: 24
|
|
1838
|
-
},
|
|
1839
|
-
children: [
|
|
1840
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", gap: 3 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1841
|
-
"span",
|
|
1842
|
-
{
|
|
1843
|
-
style: {
|
|
1844
|
-
width: 6,
|
|
1845
|
-
height: 6,
|
|
1846
|
-
borderRadius: "50%",
|
|
1847
|
-
background: "#aaa",
|
|
1848
|
-
display: "block",
|
|
1849
|
-
animation: `hermes-bounce 1.2s ease-in-out ${i * 0.2}s infinite`
|
|
1850
|
-
}
|
|
1851
|
-
},
|
|
1852
|
-
i
|
|
1853
|
-
)) }),
|
|
1854
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: 12, opacity: 0.6 }, children: typingText }),
|
|
1855
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
1856
|
-
@keyframes hermes-bounce {
|
|
1857
|
-
0%, 80%, 100% { transform: translateY(0); }
|
|
1858
|
-
40% { transform: translateY(-4px); }
|
|
1859
|
-
}
|
|
1860
|
-
` })
|
|
1861
|
-
]
|
|
1862
|
-
}
|
|
1863
|
-
);
|
|
1864
|
-
};
|
|
1865
|
-
|
|
1866
2693
|
// src/react/components/OnlineBadge.tsx
|
|
1867
|
-
var
|
|
2694
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1868
2695
|
var OnlineBadge = ({
|
|
1869
2696
|
isOnline,
|
|
1870
2697
|
size = 10,
|
|
1871
2698
|
className = ""
|
|
1872
|
-
}) => /* @__PURE__ */ (0,
|
|
2699
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1873
2700
|
"span",
|
|
1874
2701
|
{
|
|
1875
2702
|
className: `hermes-online-badge ${isOnline ? "hermes-online-badge--online" : "hermes-online-badge--offline"} ${className}`,
|
|
@@ -1887,9 +2714,9 @@ var OnlineBadge = ({
|
|
|
1887
2714
|
);
|
|
1888
2715
|
|
|
1889
2716
|
// src/react/components/ReactionPicker.tsx
|
|
1890
|
-
var
|
|
2717
|
+
var import_react19 = require("react");
|
|
1891
2718
|
var import_emoji_picker_react = __toESM(require("emoji-picker-react"), 1);
|
|
1892
|
-
var
|
|
2719
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1893
2720
|
var DEFAULT_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F525}", "\u{1F389}", "\u{1F44F}"];
|
|
1894
2721
|
var ReactionPicker = ({
|
|
1895
2722
|
onSelect,
|
|
@@ -1899,8 +2726,8 @@ var ReactionPicker = ({
|
|
|
1899
2726
|
className = "",
|
|
1900
2727
|
align = "left"
|
|
1901
2728
|
}) => {
|
|
1902
|
-
const [showPicker, setShowPicker] = (0,
|
|
1903
|
-
const containerRef = (0,
|
|
2729
|
+
const [showPicker, setShowPicker] = (0, import_react19.useState)(false);
|
|
2730
|
+
const containerRef = (0, import_react19.useRef)(null);
|
|
1904
2731
|
const hasReacted = (emoji) => {
|
|
1905
2732
|
if (!currentUserId) return false;
|
|
1906
2733
|
return currentReactions.find((r) => r.emoji === emoji)?.users.includes(currentUserId) ?? false;
|
|
@@ -1909,7 +2736,7 @@ var ReactionPicker = ({
|
|
|
1909
2736
|
onSelect(emojiData.emoji);
|
|
1910
2737
|
setShowPicker(false);
|
|
1911
2738
|
};
|
|
1912
|
-
(0,
|
|
2739
|
+
(0, import_react19.useEffect)(() => {
|
|
1913
2740
|
const handleOutsideClick = (e) => {
|
|
1914
2741
|
if (!containerRef.current) return;
|
|
1915
2742
|
const target = e.target;
|
|
@@ -1922,14 +2749,14 @@ var ReactionPicker = ({
|
|
|
1922
2749
|
}
|
|
1923
2750
|
return () => window.removeEventListener("click", handleOutsideClick);
|
|
1924
2751
|
}, [showPicker]);
|
|
1925
|
-
return /* @__PURE__ */ (0,
|
|
2752
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1926
2753
|
"div",
|
|
1927
2754
|
{
|
|
1928
2755
|
ref: containerRef,
|
|
1929
2756
|
style: { position: "relative", display: "inline-block" },
|
|
1930
2757
|
className,
|
|
1931
2758
|
children: [
|
|
1932
|
-
/* @__PURE__ */ (0,
|
|
2759
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1933
2760
|
"div",
|
|
1934
2761
|
{
|
|
1935
2762
|
style: {
|
|
@@ -1942,7 +2769,7 @@ var ReactionPicker = ({
|
|
|
1942
2769
|
border: "1px solid rgba(255,255,255,0.08)"
|
|
1943
2770
|
},
|
|
1944
2771
|
children: [
|
|
1945
|
-
emojis.map((emoji) => /* @__PURE__ */ (0,
|
|
2772
|
+
emojis.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1946
2773
|
"button",
|
|
1947
2774
|
{
|
|
1948
2775
|
onClick: () => onSelect(emoji),
|
|
@@ -1962,7 +2789,7 @@ var ReactionPicker = ({
|
|
|
1962
2789
|
},
|
|
1963
2790
|
emoji
|
|
1964
2791
|
)),
|
|
1965
|
-
/* @__PURE__ */ (0,
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1966
2793
|
"button",
|
|
1967
2794
|
{
|
|
1968
2795
|
onClick: (e) => {
|
|
@@ -1983,7 +2810,7 @@ var ReactionPicker = ({
|
|
|
1983
2810
|
]
|
|
1984
2811
|
}
|
|
1985
2812
|
),
|
|
1986
|
-
showPicker && /* @__PURE__ */ (0,
|
|
2813
|
+
showPicker && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1987
2814
|
"div",
|
|
1988
2815
|
{
|
|
1989
2816
|
onMouseDown: (e) => e.stopPropagation(),
|
|
@@ -1995,7 +2822,7 @@ var ReactionPicker = ({
|
|
|
1995
2822
|
zIndex: 50,
|
|
1996
2823
|
animation: "hermes-pop 0.15s ease"
|
|
1997
2824
|
},
|
|
1998
|
-
children: /* @__PURE__ */ (0,
|
|
2825
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1999
2826
|
import_emoji_picker_react.default,
|
|
2000
2827
|
{
|
|
2001
2828
|
theme: import_emoji_picker_react.Theme.DARK,
|
|
@@ -2008,7 +2835,7 @@ var ReactionPicker = ({
|
|
|
2008
2835
|
)
|
|
2009
2836
|
}
|
|
2010
2837
|
),
|
|
2011
|
-
/* @__PURE__ */ (0,
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("style", { children: `
|
|
2012
2839
|
@keyframes hermes-pop {
|
|
2013
2840
|
from {
|
|
2014
2841
|
opacity: 0;
|
|
@@ -2026,7 +2853,7 @@ var ReactionPicker = ({
|
|
|
2026
2853
|
};
|
|
2027
2854
|
|
|
2028
2855
|
// src/react/components/MediaMessage.tsx
|
|
2029
|
-
var
|
|
2856
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2030
2857
|
var formatFileSize2 = (bytes) => {
|
|
2031
2858
|
if (!bytes) return "";
|
|
2032
2859
|
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -2039,13 +2866,13 @@ var MediaMessage = ({
|
|
|
2039
2866
|
maxWidth = 300
|
|
2040
2867
|
}) => {
|
|
2041
2868
|
if (!message.url) return null;
|
|
2042
|
-
return /* @__PURE__ */ (0,
|
|
2869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2043
2870
|
"div",
|
|
2044
2871
|
{
|
|
2045
2872
|
className: `hermes-media-message hermes-media-message--${message.type} ${className}`,
|
|
2046
2873
|
style: { maxWidth },
|
|
2047
2874
|
children: [
|
|
2048
|
-
message.type === "image" && /* @__PURE__ */ (0,
|
|
2875
|
+
message.type === "image" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2049
2876
|
"img",
|
|
2050
2877
|
{
|
|
2051
2878
|
src: message.url,
|
|
@@ -2059,7 +2886,7 @@ var MediaMessage = ({
|
|
|
2059
2886
|
onClick: () => window.open(message.url, "_blank")
|
|
2060
2887
|
}
|
|
2061
2888
|
),
|
|
2062
|
-
message.type === "video" && /* @__PURE__ */ (0,
|
|
2889
|
+
message.type === "video" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2063
2890
|
"video",
|
|
2064
2891
|
{
|
|
2065
2892
|
src: message.url,
|
|
@@ -2068,17 +2895,17 @@ var MediaMessage = ({
|
|
|
2068
2895
|
style: { width: "100%", borderRadius: 10 }
|
|
2069
2896
|
}
|
|
2070
2897
|
),
|
|
2071
|
-
message.type === "audio" && /* @__PURE__ */ (0,
|
|
2898
|
+
message.type === "audio" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2072
2899
|
"div",
|
|
2073
2900
|
{
|
|
2074
2901
|
style: { display: "flex", alignItems: "center", gap: 8, padding: 8 },
|
|
2075
2902
|
children: [
|
|
2076
|
-
/* @__PURE__ */ (0,
|
|
2077
|
-
/* @__PURE__ */ (0,
|
|
2903
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: 20 }, children: "\u{1F3B5}" }),
|
|
2904
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("audio", { src: message.url, controls: true, style: { flex: 1, height: 36 } })
|
|
2078
2905
|
]
|
|
2079
2906
|
}
|
|
2080
2907
|
),
|
|
2081
|
-
message.type === "document" && /* @__PURE__ */ (0,
|
|
2908
|
+
message.type === "document" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2082
2909
|
"a",
|
|
2083
2910
|
{
|
|
2084
2911
|
href: message.url,
|
|
@@ -2095,9 +2922,9 @@ var MediaMessage = ({
|
|
|
2095
2922
|
color: "inherit"
|
|
2096
2923
|
},
|
|
2097
2924
|
children: [
|
|
2098
|
-
/* @__PURE__ */ (0,
|
|
2099
|
-
/* @__PURE__ */ (0,
|
|
2100
|
-
/* @__PURE__ */ (0,
|
|
2925
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: 28, flexShrink: 0 }, children: "\u{1F4C4}" }),
|
|
2926
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { overflow: "hidden" }, children: [
|
|
2927
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2101
2928
|
"div",
|
|
2102
2929
|
{
|
|
2103
2930
|
style: {
|
|
@@ -2110,7 +2937,7 @@ var MediaMessage = ({
|
|
|
2110
2937
|
children: message.fileName ?? "Document"
|
|
2111
2938
|
}
|
|
2112
2939
|
),
|
|
2113
|
-
/* @__PURE__ */ (0,
|
|
2940
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { fontSize: 11, opacity: 0.6 }, children: [
|
|
2114
2941
|
formatFileSize2(message.fileSize),
|
|
2115
2942
|
" \xB7 Click to download"
|
|
2116
2943
|
] })
|
|
@@ -2118,7 +2945,7 @@ var MediaMessage = ({
|
|
|
2118
2945
|
]
|
|
2119
2946
|
}
|
|
2120
2947
|
),
|
|
2121
|
-
message.type === "link" && /* @__PURE__ */ (0,
|
|
2948
|
+
message.type === "link" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2122
2949
|
"a",
|
|
2123
2950
|
{
|
|
2124
2951
|
href: message.url,
|
|
@@ -2146,22 +2973,436 @@ var MediaMessage = ({
|
|
|
2146
2973
|
}
|
|
2147
2974
|
);
|
|
2148
2975
|
};
|
|
2976
|
+
|
|
2977
|
+
// src/react/components/Thread/ThreadHeader.tsx
|
|
2978
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2979
|
+
var ThreadHeader = ({
|
|
2980
|
+
thread,
|
|
2981
|
+
onClose,
|
|
2982
|
+
className = ""
|
|
2983
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2984
|
+
"div",
|
|
2985
|
+
{
|
|
2986
|
+
className: `hermes-thread-header ${className}`,
|
|
2987
|
+
style: {
|
|
2988
|
+
display: "flex",
|
|
2989
|
+
alignItems: "center",
|
|
2990
|
+
justifyContent: "space-between",
|
|
2991
|
+
padding: "12px 16px",
|
|
2992
|
+
borderBottom: "1px solid rgba(128,128,128,0.15)"
|
|
2993
|
+
},
|
|
2994
|
+
children: [
|
|
2995
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, overflow: "hidden" }, children: [
|
|
2996
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontWeight: 700, fontSize: 15, marginBottom: 2 }, children: "Thread" }),
|
|
2997
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2998
|
+
"div",
|
|
2999
|
+
{
|
|
3000
|
+
style: {
|
|
3001
|
+
fontSize: 12,
|
|
3002
|
+
opacity: 0.6,
|
|
3003
|
+
overflow: "hidden",
|
|
3004
|
+
textOverflow: "ellipsis",
|
|
3005
|
+
whiteSpace: "nowrap"
|
|
3006
|
+
},
|
|
3007
|
+
children: thread.type === "text" ? thread.text?.slice(0, 80) : `[${thread.type}]`
|
|
3008
|
+
}
|
|
3009
|
+
)
|
|
3010
|
+
] }),
|
|
3011
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3012
|
+
"button",
|
|
3013
|
+
{
|
|
3014
|
+
onClick: onClose,
|
|
3015
|
+
style: {
|
|
3016
|
+
background: "none",
|
|
3017
|
+
border: "none",
|
|
3018
|
+
cursor: "pointer",
|
|
3019
|
+
fontSize: 18,
|
|
3020
|
+
padding: 4,
|
|
3021
|
+
opacity: 0.6,
|
|
3022
|
+
lineHeight: 1
|
|
3023
|
+
},
|
|
3024
|
+
children: "\u2715"
|
|
3025
|
+
}
|
|
3026
|
+
)
|
|
3027
|
+
]
|
|
3028
|
+
}
|
|
3029
|
+
);
|
|
3030
|
+
|
|
3031
|
+
// src/react/components/Thread/Thread.tsx
|
|
3032
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
3033
|
+
var Thread = ({
|
|
3034
|
+
className = "",
|
|
3035
|
+
autoFocus = true
|
|
3036
|
+
}) => {
|
|
3037
|
+
const { currentUser, customClasses } = useChatContext("Thread");
|
|
3038
|
+
const { thread, threadMessages, threadHasMore, threadLoadingMore } = useRoomStateContext("Thread");
|
|
3039
|
+
const { closeThread, addReaction, deleteMessage, editMessage } = useRoomActionContext("Thread");
|
|
3040
|
+
const {
|
|
3041
|
+
ThreadHeader: CustomThreadHeader,
|
|
3042
|
+
Message: CustomMessage
|
|
3043
|
+
} = useComponentContext("Thread");
|
|
3044
|
+
if (!thread) return null;
|
|
3045
|
+
const ThreadHeaderComponent = CustomThreadHeader || ThreadHeader;
|
|
3046
|
+
const MessageComponent = CustomMessage || Message;
|
|
3047
|
+
const threadClass = customClasses?.thread || `hermes-thread ${className}`.trim();
|
|
3048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3049
|
+
"div",
|
|
3050
|
+
{
|
|
3051
|
+
className: threadClass,
|
|
3052
|
+
style: {
|
|
3053
|
+
display: "flex",
|
|
3054
|
+
flexDirection: "column",
|
|
3055
|
+
height: "100%",
|
|
3056
|
+
borderLeft: "1px solid rgba(128,128,128,0.15)",
|
|
3057
|
+
minWidth: 320,
|
|
3058
|
+
maxWidth: 420
|
|
3059
|
+
},
|
|
3060
|
+
children: [
|
|
3061
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ThreadHeaderComponent, { thread, onClose: closeThread }),
|
|
3062
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3063
|
+
"div",
|
|
3064
|
+
{
|
|
3065
|
+
style: {
|
|
3066
|
+
padding: "12px 16px",
|
|
3067
|
+
borderBottom: "1px solid rgba(128,128,128,0.1)",
|
|
3068
|
+
background: "rgba(128,128,128,0.03)"
|
|
3069
|
+
},
|
|
3070
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3071
|
+
MessageComponent,
|
|
3072
|
+
{
|
|
3073
|
+
message: thread,
|
|
3074
|
+
isOwn: thread.senderId === currentUser?.userId,
|
|
3075
|
+
onReact: (id, emoji) => addReaction(id, emoji),
|
|
3076
|
+
showAvatar: true
|
|
3077
|
+
}
|
|
3078
|
+
)
|
|
3079
|
+
}
|
|
3080
|
+
),
|
|
3081
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3082
|
+
"div",
|
|
3083
|
+
{
|
|
3084
|
+
style: {
|
|
3085
|
+
flex: 1,
|
|
3086
|
+
overflowY: "auto",
|
|
3087
|
+
padding: 16,
|
|
3088
|
+
display: "flex",
|
|
3089
|
+
flexDirection: "column"
|
|
3090
|
+
},
|
|
3091
|
+
children: threadMessages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(EmptyStateIndicator, { listType: "thread" }) : threadMessages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginBottom: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3092
|
+
MessageComponent,
|
|
3093
|
+
{
|
|
3094
|
+
message: msg,
|
|
3095
|
+
isOwn: msg.senderId === currentUser?.userId,
|
|
3096
|
+
onEdit: (id, text) => editMessage(id, text),
|
|
3097
|
+
onDelete: (id) => deleteMessage(id),
|
|
3098
|
+
onReact: (id, emoji) => addReaction(id, emoji),
|
|
3099
|
+
showAvatar: true
|
|
3100
|
+
}
|
|
3101
|
+
) }, msg._id))
|
|
3102
|
+
}
|
|
3103
|
+
)
|
|
3104
|
+
]
|
|
3105
|
+
}
|
|
3106
|
+
);
|
|
3107
|
+
};
|
|
3108
|
+
|
|
3109
|
+
// src/react/components/Modal/Modal.tsx
|
|
3110
|
+
var import_react20 = require("react");
|
|
3111
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
3112
|
+
var Modal = ({
|
|
3113
|
+
open,
|
|
3114
|
+
onClose,
|
|
3115
|
+
className = "",
|
|
3116
|
+
children
|
|
3117
|
+
}) => {
|
|
3118
|
+
const handleKeyDown = (0, import_react20.useCallback)(
|
|
3119
|
+
(e) => {
|
|
3120
|
+
if (e.key === "Escape") onClose();
|
|
3121
|
+
},
|
|
3122
|
+
[onClose]
|
|
3123
|
+
);
|
|
3124
|
+
(0, import_react20.useEffect)(() => {
|
|
3125
|
+
if (open) {
|
|
3126
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
3127
|
+
document.body.style.overflow = "hidden";
|
|
3128
|
+
}
|
|
3129
|
+
return () => {
|
|
3130
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
3131
|
+
document.body.style.overflow = "";
|
|
3132
|
+
};
|
|
3133
|
+
}, [open, handleKeyDown]);
|
|
3134
|
+
if (!open) return null;
|
|
3135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3136
|
+
"div",
|
|
3137
|
+
{
|
|
3138
|
+
className: `hermes-modal-overlay ${className}`,
|
|
3139
|
+
onClick: onClose,
|
|
3140
|
+
style: {
|
|
3141
|
+
position: "fixed",
|
|
3142
|
+
inset: 0,
|
|
3143
|
+
zIndex: 9999,
|
|
3144
|
+
display: "flex",
|
|
3145
|
+
alignItems: "center",
|
|
3146
|
+
justifyContent: "center",
|
|
3147
|
+
background: "rgba(0,0,0,0.6)",
|
|
3148
|
+
backdropFilter: "blur(4px)",
|
|
3149
|
+
animation: "hermes-fade-in 0.15s ease"
|
|
3150
|
+
},
|
|
3151
|
+
children: [
|
|
3152
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3153
|
+
"div",
|
|
3154
|
+
{
|
|
3155
|
+
className: "hermes-modal-content",
|
|
3156
|
+
onClick: (e) => e.stopPropagation(),
|
|
3157
|
+
style: {
|
|
3158
|
+
maxWidth: "90vw",
|
|
3159
|
+
maxHeight: "90vh",
|
|
3160
|
+
overflow: "auto",
|
|
3161
|
+
borderRadius: 12,
|
|
3162
|
+
background: "#fff",
|
|
3163
|
+
boxShadow: "0 16px 64px rgba(0,0,0,0.3)",
|
|
3164
|
+
animation: "hermes-pop 0.2s ease"
|
|
3165
|
+
},
|
|
3166
|
+
children: [
|
|
3167
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3168
|
+
"button",
|
|
3169
|
+
{
|
|
3170
|
+
onClick: onClose,
|
|
3171
|
+
style: {
|
|
3172
|
+
position: "absolute",
|
|
3173
|
+
top: 16,
|
|
3174
|
+
right: 16,
|
|
3175
|
+
background: "rgba(0,0,0,0.5)",
|
|
3176
|
+
color: "#fff",
|
|
3177
|
+
border: "none",
|
|
3178
|
+
borderRadius: "50%",
|
|
3179
|
+
width: 32,
|
|
3180
|
+
height: 32,
|
|
3181
|
+
cursor: "pointer",
|
|
3182
|
+
fontSize: 16,
|
|
3183
|
+
display: "flex",
|
|
3184
|
+
alignItems: "center",
|
|
3185
|
+
justifyContent: "center",
|
|
3186
|
+
zIndex: 1
|
|
3187
|
+
},
|
|
3188
|
+
children: "\u2715"
|
|
3189
|
+
}
|
|
3190
|
+
),
|
|
3191
|
+
children
|
|
3192
|
+
]
|
|
3193
|
+
}
|
|
3194
|
+
),
|
|
3195
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("style", { children: `
|
|
3196
|
+
@keyframes hermes-fade-in {
|
|
3197
|
+
from { opacity: 0; }
|
|
3198
|
+
to { opacity: 1; }
|
|
3199
|
+
}
|
|
3200
|
+
@keyframes hermes-pop {
|
|
3201
|
+
from { opacity: 0; transform: scale(0.9); }
|
|
3202
|
+
to { opacity: 1; transform: scale(1); }
|
|
3203
|
+
}
|
|
3204
|
+
` })
|
|
3205
|
+
]
|
|
3206
|
+
}
|
|
3207
|
+
);
|
|
3208
|
+
};
|
|
3209
|
+
|
|
3210
|
+
// src/react/components/Search/Search.tsx
|
|
3211
|
+
var import_react21 = require("react");
|
|
3212
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3213
|
+
var Search = ({
|
|
3214
|
+
messages = [],
|
|
3215
|
+
onSelectResult,
|
|
3216
|
+
placeholder = "Search messages...",
|
|
3217
|
+
className = ""
|
|
3218
|
+
}) => {
|
|
3219
|
+
const [query, setQuery] = (0, import_react21.useState)("");
|
|
3220
|
+
const [focused, setFocused] = (0, import_react21.useState)(false);
|
|
3221
|
+
const results = (0, import_react21.useMemo)(() => {
|
|
3222
|
+
if (!query.trim()) return [];
|
|
3223
|
+
const lower = query.toLowerCase();
|
|
3224
|
+
return messages.filter(
|
|
3225
|
+
(m) => !m.isDeleted && m.type === "text" && m.text?.toLowerCase().includes(lower)
|
|
3226
|
+
).slice(0, 20);
|
|
3227
|
+
}, [query, messages]);
|
|
3228
|
+
const handleSelect = (0, import_react21.useCallback)(
|
|
3229
|
+
(msg) => {
|
|
3230
|
+
onSelectResult?.(msg);
|
|
3231
|
+
setQuery("");
|
|
3232
|
+
setFocused(false);
|
|
3233
|
+
},
|
|
3234
|
+
[onSelectResult]
|
|
3235
|
+
);
|
|
3236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3237
|
+
"div",
|
|
3238
|
+
{
|
|
3239
|
+
className: `hermes-search ${className}`,
|
|
3240
|
+
style: { position: "relative" },
|
|
3241
|
+
children: [
|
|
3242
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3243
|
+
"div",
|
|
3244
|
+
{
|
|
3245
|
+
style: {
|
|
3246
|
+
display: "flex",
|
|
3247
|
+
alignItems: "center",
|
|
3248
|
+
gap: 8,
|
|
3249
|
+
padding: "6px 12px",
|
|
3250
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3251
|
+
borderRadius: 10,
|
|
3252
|
+
background: focused ? "#fff" : "rgba(128,128,128,0.05)",
|
|
3253
|
+
transition: "background 0.15s, border-color 0.15s",
|
|
3254
|
+
borderColor: focused ? "#0084ff" : "rgba(128,128,128,0.2)"
|
|
3255
|
+
},
|
|
3256
|
+
children: [
|
|
3257
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontSize: 14, opacity: 0.5 }, children: "\u{1F50D}" }),
|
|
3258
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3259
|
+
"input",
|
|
3260
|
+
{
|
|
3261
|
+
type: "text",
|
|
3262
|
+
value: query,
|
|
3263
|
+
onChange: (e) => setQuery(e.target.value),
|
|
3264
|
+
onFocus: () => setFocused(true),
|
|
3265
|
+
onBlur: () => setTimeout(() => setFocused(false), 200),
|
|
3266
|
+
placeholder,
|
|
3267
|
+
style: {
|
|
3268
|
+
flex: 1,
|
|
3269
|
+
border: "none",
|
|
3270
|
+
outline: "none",
|
|
3271
|
+
fontSize: 13,
|
|
3272
|
+
background: "transparent"
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
),
|
|
3276
|
+
query && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3277
|
+
"button",
|
|
3278
|
+
{
|
|
3279
|
+
onClick: () => setQuery(""),
|
|
3280
|
+
style: {
|
|
3281
|
+
background: "none",
|
|
3282
|
+
border: "none",
|
|
3283
|
+
cursor: "pointer",
|
|
3284
|
+
fontSize: 14,
|
|
3285
|
+
opacity: 0.5,
|
|
3286
|
+
lineHeight: 1
|
|
3287
|
+
},
|
|
3288
|
+
children: "\u2715"
|
|
3289
|
+
}
|
|
3290
|
+
)
|
|
3291
|
+
]
|
|
3292
|
+
}
|
|
3293
|
+
),
|
|
3294
|
+
focused && query.trim() && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3295
|
+
"div",
|
|
3296
|
+
{
|
|
3297
|
+
style: {
|
|
3298
|
+
position: "absolute",
|
|
3299
|
+
top: "calc(100% + 4px)",
|
|
3300
|
+
left: 0,
|
|
3301
|
+
right: 0,
|
|
3302
|
+
zIndex: 50,
|
|
3303
|
+
background: "#fff",
|
|
3304
|
+
border: "1px solid rgba(128,128,128,0.15)",
|
|
3305
|
+
borderRadius: 10,
|
|
3306
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.12)",
|
|
3307
|
+
maxHeight: 300,
|
|
3308
|
+
overflowY: "auto"
|
|
3309
|
+
},
|
|
3310
|
+
children: results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3311
|
+
"div",
|
|
3312
|
+
{
|
|
3313
|
+
style: {
|
|
3314
|
+
padding: 16,
|
|
3315
|
+
textAlign: "center",
|
|
3316
|
+
fontSize: 13,
|
|
3317
|
+
opacity: 0.5
|
|
3318
|
+
},
|
|
3319
|
+
children: "No results found"
|
|
3320
|
+
}
|
|
3321
|
+
) : results.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3322
|
+
"div",
|
|
3323
|
+
{
|
|
3324
|
+
onClick: () => handleSelect(msg),
|
|
3325
|
+
style: {
|
|
3326
|
+
padding: "8px 12px",
|
|
3327
|
+
cursor: "pointer",
|
|
3328
|
+
borderBottom: "1px solid rgba(128,128,128,0.08)",
|
|
3329
|
+
transition: "background 0.1s"
|
|
3330
|
+
},
|
|
3331
|
+
onMouseEnter: (e) => e.currentTarget.style.background = "rgba(0,132,255,0.05)",
|
|
3332
|
+
onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
|
|
3333
|
+
children: [
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3335
|
+
"div",
|
|
3336
|
+
{
|
|
3337
|
+
style: {
|
|
3338
|
+
fontSize: 13,
|
|
3339
|
+
overflow: "hidden",
|
|
3340
|
+
textOverflow: "ellipsis",
|
|
3341
|
+
whiteSpace: "nowrap"
|
|
3342
|
+
},
|
|
3343
|
+
children: msg.text
|
|
3344
|
+
}
|
|
3345
|
+
),
|
|
3346
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 11, opacity: 0.5, marginTop: 2 }, children: new Date(msg.createdAt).toLocaleString() })
|
|
3347
|
+
]
|
|
3348
|
+
},
|
|
3349
|
+
msg._id
|
|
3350
|
+
))
|
|
3351
|
+
}
|
|
3352
|
+
)
|
|
3353
|
+
]
|
|
3354
|
+
}
|
|
3355
|
+
);
|
|
3356
|
+
};
|
|
2149
3357
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2150
3358
|
0 && (module.exports = {
|
|
3359
|
+
Avatar,
|
|
3360
|
+
Chat,
|
|
3361
|
+
ChatContext,
|
|
2151
3362
|
ChatInput,
|
|
3363
|
+
ChatProvider,
|
|
3364
|
+
ComponentContext,
|
|
3365
|
+
ComponentProvider,
|
|
3366
|
+
DateSeparator,
|
|
3367
|
+
EmptyStateIndicator,
|
|
2152
3368
|
HermesClient,
|
|
3369
|
+
LoadingErrorIndicator,
|
|
3370
|
+
LoadingIndicator,
|
|
2153
3371
|
MediaMessage,
|
|
3372
|
+
Message,
|
|
3373
|
+
MessageActions,
|
|
3374
|
+
MessageContext,
|
|
2154
3375
|
MessageList,
|
|
3376
|
+
MessageProvider,
|
|
3377
|
+
MessageStatus,
|
|
3378
|
+
Modal,
|
|
2155
3379
|
OnlineBadge,
|
|
2156
3380
|
ReactionPicker,
|
|
3381
|
+
Room,
|
|
3382
|
+
RoomActionContext,
|
|
3383
|
+
RoomActionProvider,
|
|
2157
3384
|
RoomList,
|
|
3385
|
+
RoomStateContext,
|
|
3386
|
+
RoomStateProvider,
|
|
3387
|
+
Search,
|
|
3388
|
+
Thread,
|
|
3389
|
+
ThreadHeader,
|
|
3390
|
+
TypingContext,
|
|
2158
3391
|
TypingIndicator,
|
|
3392
|
+
TypingProvider,
|
|
3393
|
+
Window,
|
|
3394
|
+
useChatContext,
|
|
3395
|
+
useComponentContext,
|
|
3396
|
+
useMessageContext,
|
|
2159
3397
|
useMessages,
|
|
2160
3398
|
usePresence,
|
|
2161
3399
|
useReactions,
|
|
2162
3400
|
useReadReceipts,
|
|
3401
|
+
useRoomActionContext,
|
|
3402
|
+
useRoomStateContext,
|
|
2163
3403
|
useRooms,
|
|
2164
3404
|
useTyping,
|
|
3405
|
+
useTypingContext,
|
|
2165
3406
|
useUpload
|
|
2166
3407
|
});
|
|
2167
3408
|
//# sourceMappingURL=react.cjs.map
|