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