@mieweb/ui 0.9.0-dev.5 → 0.9.0-dev.7
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/MIGRATION.md +112 -0
- package/dist/{chunk-QWJGEDHV.js → chunk-22CYDCXA.js} +13 -1183
- package/dist/chunk-22CYDCXA.js.map +1 -0
- package/dist/chunk-IIFQ6BSJ.js +1888 -0
- package/dist/chunk-IIFQ6BSJ.js.map +1 -0
- package/dist/{chunk-ZXRVVNT5.cjs → chunk-OFUKTVBN.cjs} +367 -798
- package/dist/chunk-OFUKTVBN.cjs.map +1 -0
- package/dist/chunk-OYQ7GYAA.cjs +1921 -0
- package/dist/chunk-OYQ7GYAA.cjs.map +1 -0
- package/dist/{chunk-PL6TFCYR.js → chunk-VSVGMMNO.js} +365 -793
- package/dist/chunk-VSVGMMNO.js.map +1 -0
- package/dist/{chunk-XJUIZA4G.cjs → chunk-WIAQQNFU.cjs} +12 -1184
- package/dist/chunk-WIAQQNFU.cjs.map +1 -0
- package/dist/components/SuperChat/index.cjs +11 -8
- package/dist/components/SuperChat/index.cjs.map +1 -1
- package/dist/components/SuperChat/index.js +5 -2
- package/dist/components/SuperChat/index.js.map +1 -1
- package/dist/components/SuperChat/plugins/index.cjs +10 -3
- package/dist/components/SuperChat/plugins/index.cjs.map +1 -1
- package/dist/components/SuperChat/plugins/index.js +9 -2
- package/dist/components/SuperChat/plugins/index.js.map +1 -1
- package/dist/index.cjs +91 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -98
- package/dist/index.d.ts +38 -98
- package/dist/index.js +20 -48
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -1
- package/dist/chunk-H3GRO43Z.cjs +0 -735
- package/dist/chunk-H3GRO43Z.cjs.map +0 -1
- package/dist/chunk-MD3ZY4UO.js +0 -705
- package/dist/chunk-MD3ZY4UO.js.map +0 -1
- package/dist/chunk-PL6TFCYR.js.map +0 -1
- package/dist/chunk-QWJGEDHV.js.map +0 -1
- package/dist/chunk-XJUIZA4G.cjs.map +0 -1
- package/dist/chunk-ZXRVVNT5.cjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkOYQ7GYAA_cjs = require('./chunk-OYQ7GYAA.cjs');
|
|
4
4
|
var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
|
|
5
|
-
var
|
|
5
|
+
var React = require('react');
|
|
6
6
|
var classVarianceAuthority = require('class-variance-authority');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
|
|
@@ -24,8 +24,287 @@ function _interopNamespace(e) {
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
28
|
|
|
29
|
+
function useMessages(options) {
|
|
30
|
+
const {
|
|
31
|
+
initialMessages = [],
|
|
32
|
+
currentUser,
|
|
33
|
+
onSend,
|
|
34
|
+
onRetry,
|
|
35
|
+
onLoadMore
|
|
36
|
+
} = options;
|
|
37
|
+
const [messages, setMessages] = React__namespace.useState(initialMessages);
|
|
38
|
+
const [isSending, setIsSending] = React__namespace.useState(false);
|
|
39
|
+
const [isLoadingMore, setIsLoadingMore] = React__namespace.useState(false);
|
|
40
|
+
React__namespace.useEffect(() => {
|
|
41
|
+
setMessages(initialMessages);
|
|
42
|
+
}, [initialMessages]);
|
|
43
|
+
const addMessage = React__namespace.useCallback((message) => {
|
|
44
|
+
setMessages((prev) => {
|
|
45
|
+
if (prev.some((m) => m.id === message.id)) {
|
|
46
|
+
return prev;
|
|
47
|
+
}
|
|
48
|
+
return [...prev, message];
|
|
49
|
+
});
|
|
50
|
+
}, []);
|
|
51
|
+
const updateMessage = React__namespace.useCallback(
|
|
52
|
+
(messageId, updates) => {
|
|
53
|
+
setMessages(
|
|
54
|
+
(prev) => prev.map((m) => m.id === messageId ? { ...m, ...updates } : m)
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
[]
|
|
58
|
+
);
|
|
59
|
+
const removeMessage = React__namespace.useCallback((messageId) => {
|
|
60
|
+
setMessages((prev) => prev.filter((m) => m.id !== messageId));
|
|
61
|
+
}, []);
|
|
62
|
+
const updateStatus = React__namespace.useCallback(
|
|
63
|
+
(messageId, status) => {
|
|
64
|
+
updateMessage(messageId, { status });
|
|
65
|
+
},
|
|
66
|
+
[updateMessage]
|
|
67
|
+
);
|
|
68
|
+
const markAsRead = React__namespace.useCallback(
|
|
69
|
+
(messageId) => {
|
|
70
|
+
updateStatus(messageId, "read");
|
|
71
|
+
},
|
|
72
|
+
[updateStatus]
|
|
73
|
+
);
|
|
74
|
+
const sendMessage = React__namespace.useCallback(
|
|
75
|
+
async (newMessage) => {
|
|
76
|
+
const optimisticId = `optimistic-${Date.now()}`;
|
|
77
|
+
const optimisticMessage = {
|
|
78
|
+
id: optimisticId,
|
|
79
|
+
type: "text",
|
|
80
|
+
content: newMessage.content,
|
|
81
|
+
sender: currentUser,
|
|
82
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
83
|
+
status: "sending",
|
|
84
|
+
attachments: []
|
|
85
|
+
// Would handle attachment uploads here
|
|
86
|
+
};
|
|
87
|
+
addMessage(optimisticMessage);
|
|
88
|
+
setIsSending(true);
|
|
89
|
+
try {
|
|
90
|
+
if (onSend) {
|
|
91
|
+
const sentMessage = await onSend(newMessage);
|
|
92
|
+
setMessages(
|
|
93
|
+
(prev) => prev.map((m) => m.id === optimisticId ? sentMessage : m)
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
updateStatus(optimisticId, "sent");
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
updateStatus(optimisticId, "failed");
|
|
100
|
+
} finally {
|
|
101
|
+
setIsSending(false);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
[currentUser, onSend, addMessage, updateStatus]
|
|
105
|
+
);
|
|
106
|
+
const retryMessage = React__namespace.useCallback(
|
|
107
|
+
async (messageId) => {
|
|
108
|
+
updateStatus(messageId, "sending");
|
|
109
|
+
try {
|
|
110
|
+
if (onRetry) {
|
|
111
|
+
await onRetry(messageId);
|
|
112
|
+
updateStatus(messageId, "sent");
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
updateStatus(messageId, "failed");
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
[onRetry, updateStatus]
|
|
119
|
+
);
|
|
120
|
+
const loadMore = React__namespace.useCallback(async () => {
|
|
121
|
+
if (isLoadingMore || !onLoadMore) return;
|
|
122
|
+
setIsLoadingMore(true);
|
|
123
|
+
try {
|
|
124
|
+
const olderMessages = await onLoadMore();
|
|
125
|
+
setMessages((prev) => [...olderMessages, ...prev]);
|
|
126
|
+
} finally {
|
|
127
|
+
setIsLoadingMore(false);
|
|
128
|
+
}
|
|
129
|
+
}, [isLoadingMore, onLoadMore]);
|
|
130
|
+
return {
|
|
131
|
+
messages,
|
|
132
|
+
addMessage,
|
|
133
|
+
updateMessage,
|
|
134
|
+
removeMessage,
|
|
135
|
+
sendMessage,
|
|
136
|
+
retryMessage,
|
|
137
|
+
loadMore,
|
|
138
|
+
isSending,
|
|
139
|
+
isLoadingMore,
|
|
140
|
+
markAsRead,
|
|
141
|
+
updateStatus
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function useTypingIndicator(options = {}) {
|
|
145
|
+
const {
|
|
146
|
+
typingParticipants: initialParticipants = [],
|
|
147
|
+
debounceTime = 2e3,
|
|
148
|
+
onTypingStart,
|
|
149
|
+
onTypingStop
|
|
150
|
+
} = options;
|
|
151
|
+
const [participants, setParticipants] = React__namespace.useState(initialParticipants);
|
|
152
|
+
const [isLocalTyping, setIsLocalTyping] = React__namespace.useState(false);
|
|
153
|
+
const typingTimeoutRef = React__namespace.useRef(null);
|
|
154
|
+
React__namespace.useEffect(() => {
|
|
155
|
+
setParticipants(initialParticipants);
|
|
156
|
+
}, [initialParticipants]);
|
|
157
|
+
const startTyping = React__namespace.useCallback(() => {
|
|
158
|
+
if (!isLocalTyping) {
|
|
159
|
+
setIsLocalTyping(true);
|
|
160
|
+
onTypingStart?.();
|
|
161
|
+
}
|
|
162
|
+
if (typingTimeoutRef.current) {
|
|
163
|
+
clearTimeout(typingTimeoutRef.current);
|
|
164
|
+
}
|
|
165
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
166
|
+
setIsLocalTyping(false);
|
|
167
|
+
onTypingStop?.();
|
|
168
|
+
}, debounceTime);
|
|
169
|
+
}, [isLocalTyping, debounceTime, onTypingStart, onTypingStop]);
|
|
170
|
+
const stopTyping = React__namespace.useCallback(() => {
|
|
171
|
+
if (typingTimeoutRef.current) {
|
|
172
|
+
clearTimeout(typingTimeoutRef.current);
|
|
173
|
+
}
|
|
174
|
+
setIsLocalTyping(false);
|
|
175
|
+
onTypingStop?.();
|
|
176
|
+
}, [onTypingStop]);
|
|
177
|
+
React__namespace.useEffect(() => {
|
|
178
|
+
return () => {
|
|
179
|
+
if (typingTimeoutRef.current) {
|
|
180
|
+
clearTimeout(typingTimeoutRef.current);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}, []);
|
|
184
|
+
const typingState = React__namespace.useMemo(
|
|
185
|
+
() => ({
|
|
186
|
+
participants,
|
|
187
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
188
|
+
}),
|
|
189
|
+
[participants]
|
|
190
|
+
);
|
|
191
|
+
return {
|
|
192
|
+
typingState,
|
|
193
|
+
startTyping,
|
|
194
|
+
stopTyping,
|
|
195
|
+
setTypingParticipants: setParticipants
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function useMessageScroll(options) {
|
|
199
|
+
const { messages, currentUserId, threshold = 100 } = options;
|
|
200
|
+
const scrollContainerRef = React__namespace.useRef(null);
|
|
201
|
+
const bottomRef = React__namespace.useRef(null);
|
|
202
|
+
const [isScrolledUp, setIsScrolledUp] = React__namespace.useState(false);
|
|
203
|
+
const prevMessageCountRef = React__namespace.useRef(messages.length);
|
|
204
|
+
React__namespace.useEffect(() => {
|
|
205
|
+
const container = scrollContainerRef.current;
|
|
206
|
+
if (!container) return;
|
|
207
|
+
const handleScroll = () => {
|
|
208
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
209
|
+
const isAtBottom = scrollHeight - scrollTop - clientHeight < threshold;
|
|
210
|
+
setIsScrolledUp(!isAtBottom);
|
|
211
|
+
};
|
|
212
|
+
container.addEventListener("scroll", handleScroll);
|
|
213
|
+
return () => container.removeEventListener("scroll", handleScroll);
|
|
214
|
+
}, [threshold]);
|
|
215
|
+
const scrollToBottom = React__namespace.useCallback((smooth = true) => {
|
|
216
|
+
bottomRef.current?.scrollIntoView({
|
|
217
|
+
behavior: smooth ? "smooth" : "auto"
|
|
218
|
+
});
|
|
219
|
+
}, []);
|
|
220
|
+
React__namespace.useEffect(() => {
|
|
221
|
+
const messageCountChanged = messages.length !== prevMessageCountRef.current;
|
|
222
|
+
prevMessageCountRef.current = messages.length;
|
|
223
|
+
if (!messageCountChanged) return;
|
|
224
|
+
const lastMessage = messages[messages.length - 1];
|
|
225
|
+
const isOutgoing = lastMessage?.sender.id === currentUserId;
|
|
226
|
+
if (isOutgoing || !isScrolledUp) {
|
|
227
|
+
scrollToBottom(true);
|
|
228
|
+
}
|
|
229
|
+
}, [messages, currentUserId, isScrolledUp, scrollToBottom]);
|
|
230
|
+
return {
|
|
231
|
+
scrollContainerRef,
|
|
232
|
+
bottomRef,
|
|
233
|
+
isScrolledUp,
|
|
234
|
+
scrollToBottom
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function useReadReceipts(options) {
|
|
238
|
+
const { currentUserId, onMarkRead, threshold = 0.5 } = options;
|
|
239
|
+
const observerRef = React__namespace.useRef(null);
|
|
240
|
+
const observedMessagesRef = React__namespace.useRef(/* @__PURE__ */ new Set());
|
|
241
|
+
React__namespace.useEffect(() => {
|
|
242
|
+
observerRef.current = new IntersectionObserver(
|
|
243
|
+
(entries) => {
|
|
244
|
+
entries.forEach((entry) => {
|
|
245
|
+
if (entry.isIntersecting) {
|
|
246
|
+
const messageId = entry.target.getAttribute("data-message-id");
|
|
247
|
+
if (messageId && !observedMessagesRef.current.has(messageId)) {
|
|
248
|
+
observedMessagesRef.current.add(messageId);
|
|
249
|
+
onMarkRead?.(messageId);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
},
|
|
254
|
+
{ threshold }
|
|
255
|
+
);
|
|
256
|
+
return () => {
|
|
257
|
+
observerRef.current?.disconnect();
|
|
258
|
+
};
|
|
259
|
+
}, [onMarkRead, threshold]);
|
|
260
|
+
const observeMessage = React__namespace.useCallback(
|
|
261
|
+
(element, message) => {
|
|
262
|
+
if (!element || !observerRef.current) return;
|
|
263
|
+
if (message.sender.id !== currentUserId && message.status !== "read" && !observedMessagesRef.current.has(message.id)) {
|
|
264
|
+
element.setAttribute("data-message-id", message.id);
|
|
265
|
+
observerRef.current.observe(element);
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
[currentUserId]
|
|
269
|
+
);
|
|
270
|
+
return { observeMessage };
|
|
271
|
+
}
|
|
272
|
+
function useTypingEmulation({
|
|
273
|
+
value,
|
|
274
|
+
onTypingStart,
|
|
275
|
+
onTypingStop
|
|
276
|
+
}) {
|
|
277
|
+
const [isTyping, setIsTyping] = React__namespace.useState(false);
|
|
278
|
+
const typingTimeoutRef = React__namespace.useRef(
|
|
279
|
+
null
|
|
280
|
+
);
|
|
281
|
+
React__namespace.useEffect(() => {
|
|
282
|
+
if (!onTypingStart && !onTypingStop) return;
|
|
283
|
+
if (value.length > 0 && !isTyping) {
|
|
284
|
+
setIsTyping(true);
|
|
285
|
+
onTypingStart?.();
|
|
286
|
+
}
|
|
287
|
+
if (typingTimeoutRef.current) {
|
|
288
|
+
clearTimeout(typingTimeoutRef.current);
|
|
289
|
+
}
|
|
290
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
291
|
+
if (isTyping) {
|
|
292
|
+
setIsTyping(false);
|
|
293
|
+
onTypingStop?.();
|
|
294
|
+
}
|
|
295
|
+
}, 2e3);
|
|
296
|
+
return () => {
|
|
297
|
+
if (typingTimeoutRef.current) {
|
|
298
|
+
clearTimeout(typingTimeoutRef.current);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
}, [value, isTyping, onTypingStart, onTypingStop]);
|
|
302
|
+
const stopTyping = React__namespace.useCallback(() => {
|
|
303
|
+
setIsTyping(false);
|
|
304
|
+
onTypingStop?.();
|
|
305
|
+
}, [onTypingStop]);
|
|
306
|
+
return { stopTyping };
|
|
307
|
+
}
|
|
29
308
|
var statusIconVariants = classVarianceAuthority.cva(
|
|
30
309
|
"inline-flex items-center gap-0.5 text-current",
|
|
31
310
|
{
|
|
@@ -406,7 +685,7 @@ function defaultFormatTimestamp(timestamp) {
|
|
|
406
685
|
minute: "2-digit"
|
|
407
686
|
});
|
|
408
687
|
}
|
|
409
|
-
var MessageBubble =
|
|
688
|
+
var MessageBubble = React__namespace.forwardRef(
|
|
410
689
|
({
|
|
411
690
|
className,
|
|
412
691
|
message,
|
|
@@ -881,7 +1160,7 @@ function LoadMoreButton({
|
|
|
881
1160
|
);
|
|
882
1161
|
}
|
|
883
1162
|
LoadMoreButton.displayName = "LoadMoreButton";
|
|
884
|
-
var MessageList =
|
|
1163
|
+
var MessageList = React__namespace.forwardRef(
|
|
885
1164
|
({
|
|
886
1165
|
messages,
|
|
887
1166
|
currentUser,
|
|
@@ -900,19 +1179,19 @@ var MessageList = React6__namespace.forwardRef(
|
|
|
900
1179
|
className,
|
|
901
1180
|
autoScroll = "onNewMessage"
|
|
902
1181
|
}, ref) => {
|
|
903
|
-
const scrollContainerRef =
|
|
904
|
-
const bottomRef =
|
|
905
|
-
const [isUserScrolled, setIsUserScrolled] =
|
|
906
|
-
const prevMessageCountRef =
|
|
907
|
-
|
|
908
|
-
const handleScroll =
|
|
1182
|
+
const scrollContainerRef = React__namespace.useRef(null);
|
|
1183
|
+
const bottomRef = React__namespace.useRef(null);
|
|
1184
|
+
const [isUserScrolled, setIsUserScrolled] = React__namespace.useState(false);
|
|
1185
|
+
const prevMessageCountRef = React__namespace.useRef(messages.length);
|
|
1186
|
+
React__namespace.useImperativeHandle(ref, () => scrollContainerRef.current);
|
|
1187
|
+
const handleScroll = React__namespace.useCallback(() => {
|
|
909
1188
|
const container = scrollContainerRef.current;
|
|
910
1189
|
if (!container) return;
|
|
911
1190
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
912
1191
|
const isAtBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
913
1192
|
setIsUserScrolled(!isAtBottom);
|
|
914
1193
|
}, []);
|
|
915
|
-
|
|
1194
|
+
React__namespace.useEffect(() => {
|
|
916
1195
|
const container = scrollContainerRef.current;
|
|
917
1196
|
const bottom = bottomRef.current;
|
|
918
1197
|
if (!container || !bottom) return;
|
|
@@ -928,7 +1207,7 @@ var MessageList = React6__namespace.forwardRef(
|
|
|
928
1207
|
}
|
|
929
1208
|
}
|
|
930
1209
|
}, [messages, currentUser.id, autoScroll, isUserScrolled]);
|
|
931
|
-
|
|
1210
|
+
React__namespace.useEffect(() => {
|
|
932
1211
|
const bottom = bottomRef.current;
|
|
933
1212
|
if (bottom && !isLoading) {
|
|
934
1213
|
bottom.scrollIntoView();
|
|
@@ -981,7 +1260,7 @@ var MessageList = React6__namespace.forwardRef(
|
|
|
981
1260
|
{
|
|
982
1261
|
"data-slot": "message-list-content",
|
|
983
1262
|
className: "flex flex-col gap-1 p-4",
|
|
984
|
-
children: messageGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1263
|
+
children: messageGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
|
985
1264
|
groupByDate && group.label && /* @__PURE__ */ jsxRuntime.jsx(DateSeparator, { label: group.label }),
|
|
986
1265
|
group.messages.map((message, index) => {
|
|
987
1266
|
const prevMessage = group.messages[index - 1];
|
|
@@ -1061,516 +1340,11 @@ var MessageList = React6__namespace.forwardRef(
|
|
|
1061
1340
|
}
|
|
1062
1341
|
);
|
|
1063
1342
|
MessageList.displayName = "MessageList";
|
|
1064
|
-
|
|
1065
|
-
if (!accepted || accepted.length === 0) return true;
|
|
1066
|
-
const mime = file.type;
|
|
1067
|
-
const name = file.name.toLowerCase();
|
|
1068
|
-
return accepted.some((token) => {
|
|
1069
|
-
if (token.startsWith(".")) return name.endsWith(token.toLowerCase());
|
|
1070
|
-
if (token.endsWith("/*")) return mime.startsWith(token.slice(0, -1));
|
|
1071
|
-
if (token.includes("/")) return mime === token;
|
|
1072
|
-
return false;
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
function CharacterCounter({
|
|
1076
|
-
current,
|
|
1077
|
-
max,
|
|
1078
|
-
showWarningAt = 0.9,
|
|
1079
|
-
className
|
|
1080
|
-
}) {
|
|
1081
|
-
const percentage = current / max;
|
|
1082
|
-
const isWarning = percentage >= showWarningAt && percentage < 1;
|
|
1083
|
-
const isOver = current > max;
|
|
1084
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1085
|
-
"span",
|
|
1086
|
-
{
|
|
1087
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1088
|
-
"text-xs tabular-nums",
|
|
1089
|
-
isOver ? "font-medium text-red-700 dark:text-red-400" : isWarning ? "text-amber-700 dark:text-amber-400" : "text-neutral-600 dark:text-neutral-400",
|
|
1090
|
-
className
|
|
1091
|
-
),
|
|
1092
|
-
"aria-live": "polite",
|
|
1093
|
-
"aria-label": `${current} of ${max} characters`,
|
|
1094
|
-
children: [
|
|
1095
|
-
current,
|
|
1096
|
-
"/",
|
|
1097
|
-
max
|
|
1098
|
-
]
|
|
1099
|
-
}
|
|
1100
|
-
);
|
|
1101
|
-
}
|
|
1102
|
-
CharacterCounter.displayName = "CharacterCounter";
|
|
1103
|
-
var sendButtonVariants = classVarianceAuthority.cva(
|
|
1343
|
+
var headerVariants = classVarianceAuthority.cva(
|
|
1104
1344
|
[
|
|
1105
|
-
"
|
|
1106
|
-
"
|
|
1107
|
-
"
|
|
1108
|
-
"focus:outline-none focus:ring-2 focus:ring-primary-500",
|
|
1109
|
-
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
1110
|
-
],
|
|
1111
|
-
{
|
|
1112
|
-
variants: {
|
|
1113
|
-
variant: {
|
|
1114
|
-
primary: [
|
|
1115
|
-
"bg-primary-800 text-white",
|
|
1116
|
-
"hover:bg-primary-900",
|
|
1117
|
-
"active:scale-95"
|
|
1118
|
-
],
|
|
1119
|
-
subtle: [
|
|
1120
|
-
"bg-transparent text-primary-800",
|
|
1121
|
-
"hover:bg-primary-50 dark:hover:bg-primary-900/20"
|
|
1122
|
-
]
|
|
1123
|
-
},
|
|
1124
|
-
canSend: {
|
|
1125
|
-
true: "",
|
|
1126
|
-
false: "opacity-50 cursor-not-allowed"
|
|
1127
|
-
}
|
|
1128
|
-
},
|
|
1129
|
-
defaultVariants: {
|
|
1130
|
-
variant: "primary",
|
|
1131
|
-
canSend: false
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
);
|
|
1135
|
-
var SendButton = React6__namespace.forwardRef(
|
|
1136
|
-
({ className, variant, canSend, isLoading, disabled, ...props }, ref) => {
|
|
1137
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1138
|
-
"button",
|
|
1139
|
-
{
|
|
1140
|
-
ref,
|
|
1141
|
-
type: "submit",
|
|
1142
|
-
disabled: disabled || !canSend || isLoading,
|
|
1143
|
-
"data-slot": "composer-send-button",
|
|
1144
|
-
className: chunkS5RVSXDV_cjs.cn(sendButtonVariants({ variant, canSend }), className),
|
|
1145
|
-
"aria-label": isLoading ? "Sending message" : "Send message",
|
|
1146
|
-
...props,
|
|
1147
|
-
children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1148
|
-
"svg",
|
|
1149
|
-
{
|
|
1150
|
-
"aria-hidden": "true",
|
|
1151
|
-
className: "h-5 w-5 animate-spin",
|
|
1152
|
-
fill: "none",
|
|
1153
|
-
viewBox: "0 0 24 24",
|
|
1154
|
-
children: [
|
|
1155
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1156
|
-
"circle",
|
|
1157
|
-
{
|
|
1158
|
-
className: "opacity-25",
|
|
1159
|
-
cx: "12",
|
|
1160
|
-
cy: "12",
|
|
1161
|
-
r: "10",
|
|
1162
|
-
stroke: "currentColor",
|
|
1163
|
-
strokeWidth: "4"
|
|
1164
|
-
}
|
|
1165
|
-
),
|
|
1166
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1167
|
-
"path",
|
|
1168
|
-
{
|
|
1169
|
-
className: "opacity-75",
|
|
1170
|
-
fill: "currentColor",
|
|
1171
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
1172
|
-
}
|
|
1173
|
-
)
|
|
1174
|
-
]
|
|
1175
|
-
}
|
|
1176
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1177
|
-
"svg",
|
|
1178
|
-
{
|
|
1179
|
-
"aria-hidden": "true",
|
|
1180
|
-
className: "h-5 w-5",
|
|
1181
|
-
fill: "none",
|
|
1182
|
-
viewBox: "0 0 24 24",
|
|
1183
|
-
stroke: "currentColor",
|
|
1184
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1185
|
-
"path",
|
|
1186
|
-
{
|
|
1187
|
-
strokeLinecap: "round",
|
|
1188
|
-
strokeLinejoin: "round",
|
|
1189
|
-
strokeWidth: 2,
|
|
1190
|
-
d: "M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
|
|
1191
|
-
}
|
|
1192
|
-
)
|
|
1193
|
-
}
|
|
1194
|
-
)
|
|
1195
|
-
}
|
|
1196
|
-
);
|
|
1197
|
-
}
|
|
1198
|
-
);
|
|
1199
|
-
SendButton.displayName = "SendButton";
|
|
1200
|
-
var MessageComposer = React6__namespace.forwardRef(
|
|
1201
|
-
({
|
|
1202
|
-
onSend,
|
|
1203
|
-
onTypingStart,
|
|
1204
|
-
onTypingStop,
|
|
1205
|
-
value: controlledValue,
|
|
1206
|
-
onValueChange,
|
|
1207
|
-
placeholder = "Type a message...",
|
|
1208
|
-
maxLength = 1600,
|
|
1209
|
-
showCharacterCount = false,
|
|
1210
|
-
disabled = false,
|
|
1211
|
-
isSending = false,
|
|
1212
|
-
showAttachmentPicker = true,
|
|
1213
|
-
showCameraButton = false,
|
|
1214
|
-
acceptedFileTypes = ["image/*", "video/*", ".pdf", ".doc", ".docx"],
|
|
1215
|
-
maxFileSize = 25 * 1024 * 1024,
|
|
1216
|
-
maxAttachments = 10,
|
|
1217
|
-
onError,
|
|
1218
|
-
autoFocus = false,
|
|
1219
|
-
replyTo = null,
|
|
1220
|
-
onCancelReply,
|
|
1221
|
-
variant = "default",
|
|
1222
|
-
inputTrailing,
|
|
1223
|
-
mentionOptions,
|
|
1224
|
-
className
|
|
1225
|
-
}, ref) => {
|
|
1226
|
-
const textareaRef = React6__namespace.useRef(null);
|
|
1227
|
-
const [internalContent, setInternalContent] = React6__namespace.useState("");
|
|
1228
|
-
const isControlled = controlledValue !== void 0;
|
|
1229
|
-
const content = isControlled ? controlledValue : internalContent;
|
|
1230
|
-
const setContent = React6__namespace.useCallback(
|
|
1231
|
-
(val) => {
|
|
1232
|
-
if (isControlled) {
|
|
1233
|
-
const newVal = typeof val === "function" ? val(controlledValue) : val;
|
|
1234
|
-
onValueChange?.(newVal);
|
|
1235
|
-
} else {
|
|
1236
|
-
setInternalContent(val);
|
|
1237
|
-
}
|
|
1238
|
-
},
|
|
1239
|
-
[isControlled, controlledValue, onValueChange]
|
|
1240
|
-
);
|
|
1241
|
-
const [attachments, setAttachments] = React6__namespace.useState(
|
|
1242
|
-
[]
|
|
1243
|
-
);
|
|
1244
|
-
const [isTyping, setIsTyping] = React6__namespace.useState(false);
|
|
1245
|
-
const typingTimeoutRef = React6__namespace.useRef(null);
|
|
1246
|
-
React6__namespace.useImperativeHandle(ref, () => textareaRef.current);
|
|
1247
|
-
React6__namespace.useEffect(() => {
|
|
1248
|
-
const textarea = textareaRef.current;
|
|
1249
|
-
if (textarea) {
|
|
1250
|
-
textarea.style.height = "auto";
|
|
1251
|
-
textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`;
|
|
1252
|
-
}
|
|
1253
|
-
}, [content]);
|
|
1254
|
-
React6__namespace.useEffect(() => {
|
|
1255
|
-
if (content.length > 0 && !isTyping) {
|
|
1256
|
-
setIsTyping(true);
|
|
1257
|
-
onTypingStart?.();
|
|
1258
|
-
}
|
|
1259
|
-
if (typingTimeoutRef.current) {
|
|
1260
|
-
clearTimeout(typingTimeoutRef.current);
|
|
1261
|
-
}
|
|
1262
|
-
typingTimeoutRef.current = setTimeout(() => {
|
|
1263
|
-
if (isTyping) {
|
|
1264
|
-
setIsTyping(false);
|
|
1265
|
-
onTypingStop?.();
|
|
1266
|
-
}
|
|
1267
|
-
}, 2e3);
|
|
1268
|
-
return () => {
|
|
1269
|
-
if (typingTimeoutRef.current) {
|
|
1270
|
-
clearTimeout(typingTimeoutRef.current);
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
}, [content, isTyping, onTypingStart, onTypingStop]);
|
|
1274
|
-
React6__namespace.useEffect(() => {
|
|
1275
|
-
if (autoFocus) {
|
|
1276
|
-
textareaRef.current?.focus();
|
|
1277
|
-
}
|
|
1278
|
-
}, [autoFocus]);
|
|
1279
|
-
const replyToId = replyTo?.id;
|
|
1280
|
-
React6__namespace.useEffect(() => {
|
|
1281
|
-
if (replyToId !== void 0) {
|
|
1282
|
-
textareaRef.current?.focus();
|
|
1283
|
-
}
|
|
1284
|
-
}, [replyToId]);
|
|
1285
|
-
const mention = chunkH3GRO43Z_cjs.useMentionAutocomplete({
|
|
1286
|
-
options: mentionOptions,
|
|
1287
|
-
value: content,
|
|
1288
|
-
setValue: setContent,
|
|
1289
|
-
textareaRef
|
|
1290
|
-
});
|
|
1291
|
-
const canSend = (content.trim().length > 0 || attachments.length > 0) && content.length <= maxLength && !disabled && !isSending;
|
|
1292
|
-
const handleSubmit = async (event) => {
|
|
1293
|
-
event.preventDefault();
|
|
1294
|
-
if (!canSend) return;
|
|
1295
|
-
const message = {
|
|
1296
|
-
content: content.trim(),
|
|
1297
|
-
attachments: attachments.map((a) => a.file),
|
|
1298
|
-
replyToId: replyTo?.id
|
|
1299
|
-
};
|
|
1300
|
-
setContent("");
|
|
1301
|
-
setAttachments([]);
|
|
1302
|
-
setIsTyping(false);
|
|
1303
|
-
onTypingStop?.();
|
|
1304
|
-
try {
|
|
1305
|
-
await onSend(message);
|
|
1306
|
-
} catch {
|
|
1307
|
-
setContent(message.content);
|
|
1308
|
-
onError?.("Failed to send message");
|
|
1309
|
-
}
|
|
1310
|
-
};
|
|
1311
|
-
const handleKeyDown = (event) => {
|
|
1312
|
-
if (mention.handleKeyDown(event)) return;
|
|
1313
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
1314
|
-
event.preventDefault();
|
|
1315
|
-
if (canSend) {
|
|
1316
|
-
handleSubmit(event);
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
};
|
|
1320
|
-
const handleFilesSelected = (files) => {
|
|
1321
|
-
const remainingSlots = maxAttachments - attachments.length;
|
|
1322
|
-
const filesToAdd = files.slice(0, remainingSlots);
|
|
1323
|
-
if (files.length > remainingSlots) {
|
|
1324
|
-
onError?.(`Maximum ${maxAttachments} attachments allowed`);
|
|
1325
|
-
}
|
|
1326
|
-
const newAttachments = filesToAdd.map((file) => {
|
|
1327
|
-
const type = chunkH3GRO43Z_cjs.getFileType(file.type);
|
|
1328
|
-
let previewUrl;
|
|
1329
|
-
if (type === "image" || type === "video") {
|
|
1330
|
-
previewUrl = URL.createObjectURL(file);
|
|
1331
|
-
}
|
|
1332
|
-
return {
|
|
1333
|
-
id: chunkH3GRO43Z_cjs.generateAttachmentId(),
|
|
1334
|
-
file,
|
|
1335
|
-
previewUrl,
|
|
1336
|
-
type,
|
|
1337
|
-
state: "pending"
|
|
1338
|
-
};
|
|
1339
|
-
});
|
|
1340
|
-
setAttachments((prev) => [...prev, ...newAttachments]);
|
|
1341
|
-
};
|
|
1342
|
-
const handlePaste = (event) => {
|
|
1343
|
-
if (!showAttachmentPicker || disabled) return;
|
|
1344
|
-
const pasted = Array.from(event.clipboardData.items).filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((f) => f !== null).filter((f) => isFileAccepted(f, acceptedFileTypes));
|
|
1345
|
-
if (pasted.length === 0) return;
|
|
1346
|
-
event.preventDefault();
|
|
1347
|
-
handleFilesSelected(pasted);
|
|
1348
|
-
};
|
|
1349
|
-
const handleRemoveAttachment = (attachmentId) => {
|
|
1350
|
-
setAttachments((prev) => {
|
|
1351
|
-
const attachment = prev.find((a) => a.id === attachmentId);
|
|
1352
|
-
if (attachment?.previewUrl) {
|
|
1353
|
-
URL.revokeObjectURL(attachment.previewUrl);
|
|
1354
|
-
}
|
|
1355
|
-
return prev.filter((a) => a.id !== attachmentId);
|
|
1356
|
-
});
|
|
1357
|
-
};
|
|
1358
|
-
React6__namespace.useEffect(() => {
|
|
1359
|
-
const currentAttachments = attachments;
|
|
1360
|
-
return () => {
|
|
1361
|
-
currentAttachments.forEach((a) => {
|
|
1362
|
-
if (a.previewUrl) {
|
|
1363
|
-
URL.revokeObjectURL(a.previewUrl);
|
|
1364
|
-
}
|
|
1365
|
-
});
|
|
1366
|
-
};
|
|
1367
|
-
}, [attachments]);
|
|
1368
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1369
|
-
chunkH3GRO43Z_cjs.DragDropZone,
|
|
1370
|
-
{
|
|
1371
|
-
onFilesDropped: handleFilesSelected,
|
|
1372
|
-
acceptedTypes: acceptedFileTypes,
|
|
1373
|
-
maxFileSize,
|
|
1374
|
-
maxFiles: maxAttachments - attachments.length,
|
|
1375
|
-
disabled: disabled || attachments.length >= maxAttachments,
|
|
1376
|
-
onError,
|
|
1377
|
-
className: chunkS5RVSXDV_cjs.cn("w-full", className),
|
|
1378
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1379
|
-
"form",
|
|
1380
|
-
{
|
|
1381
|
-
onSubmit: handleSubmit,
|
|
1382
|
-
"data-slot": "message-composer",
|
|
1383
|
-
className: "w-full",
|
|
1384
|
-
children: [
|
|
1385
|
-
replyTo && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1386
|
-
"div",
|
|
1387
|
-
{
|
|
1388
|
-
"data-slot": "composer-reply-preview",
|
|
1389
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1390
|
-
"flex items-center gap-2 px-4 py-2",
|
|
1391
|
-
"bg-neutral-50 dark:bg-neutral-800/50",
|
|
1392
|
-
"border-primary-500 border-s-4"
|
|
1393
|
-
),
|
|
1394
|
-
children: [
|
|
1395
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1396
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-primary-800 dark:text-primary-400 text-xs font-medium", children: [
|
|
1397
|
-
"Replying to ",
|
|
1398
|
-
replyTo.senderName
|
|
1399
|
-
] }),
|
|
1400
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm text-neutral-600 dark:text-neutral-300", children: replyTo.content })
|
|
1401
|
-
] }),
|
|
1402
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1403
|
-
"button",
|
|
1404
|
-
{
|
|
1405
|
-
type: "button",
|
|
1406
|
-
onClick: onCancelReply,
|
|
1407
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1408
|
-
"shrink-0 rounded p-1",
|
|
1409
|
-
"text-neutral-500 hover:text-neutral-700",
|
|
1410
|
-
"dark:text-neutral-400 dark:hover:text-neutral-200",
|
|
1411
|
-
"focus:ring-primary-500 focus:ring-2 focus:outline-none"
|
|
1412
|
-
),
|
|
1413
|
-
"aria-label": "Cancel reply",
|
|
1414
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1415
|
-
"svg",
|
|
1416
|
-
{
|
|
1417
|
-
"aria-hidden": "true",
|
|
1418
|
-
className: "h-4 w-4",
|
|
1419
|
-
fill: "none",
|
|
1420
|
-
viewBox: "0 0 24 24",
|
|
1421
|
-
stroke: "currentColor",
|
|
1422
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1423
|
-
"path",
|
|
1424
|
-
{
|
|
1425
|
-
strokeLinecap: "round",
|
|
1426
|
-
strokeLinejoin: "round",
|
|
1427
|
-
strokeWidth: 2,
|
|
1428
|
-
d: "M6 18L18 6M6 6l12 12"
|
|
1429
|
-
}
|
|
1430
|
-
)
|
|
1431
|
-
}
|
|
1432
|
-
)
|
|
1433
|
-
}
|
|
1434
|
-
)
|
|
1435
|
-
]
|
|
1436
|
-
}
|
|
1437
|
-
),
|
|
1438
|
-
attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1439
|
-
"div",
|
|
1440
|
-
{
|
|
1441
|
-
"data-slot": "composer-attachments",
|
|
1442
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1443
|
-
"flex flex-wrap gap-2 p-3",
|
|
1444
|
-
"border-t border-neutral-200 dark:border-neutral-700"
|
|
1445
|
-
),
|
|
1446
|
-
children: attachments.map((attachment) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1447
|
-
chunkH3GRO43Z_cjs.AttachmentPreviewItem,
|
|
1448
|
-
{
|
|
1449
|
-
attachment,
|
|
1450
|
-
onRemove: () => handleRemoveAttachment(attachment.id)
|
|
1451
|
-
},
|
|
1452
|
-
attachment.id
|
|
1453
|
-
))
|
|
1454
|
-
}
|
|
1455
|
-
),
|
|
1456
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1457
|
-
"div",
|
|
1458
|
-
{
|
|
1459
|
-
"data-slot": "composer-input-area",
|
|
1460
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1461
|
-
"flex items-center gap-2 p-3",
|
|
1462
|
-
"bg-white dark:bg-neutral-900",
|
|
1463
|
-
variant === "default" && "border-t border-neutral-200 dark:border-neutral-700"
|
|
1464
|
-
),
|
|
1465
|
-
children: [
|
|
1466
|
-
showAttachmentPicker && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1467
|
-
chunkH3GRO43Z_cjs.AttachmentPicker,
|
|
1468
|
-
{
|
|
1469
|
-
onFilesSelected: handleFilesSelected,
|
|
1470
|
-
acceptedTypes: acceptedFileTypes,
|
|
1471
|
-
maxFileSize,
|
|
1472
|
-
maxFiles: maxAttachments - attachments.length,
|
|
1473
|
-
disabled: disabled || attachments.length >= maxAttachments,
|
|
1474
|
-
onError
|
|
1475
|
-
}
|
|
1476
|
-
),
|
|
1477
|
-
showCameraButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1478
|
-
chunkH3GRO43Z_cjs.CameraButton,
|
|
1479
|
-
{
|
|
1480
|
-
onCapture: (file) => handleFilesSelected([file]),
|
|
1481
|
-
disabled: disabled || attachments.length >= maxAttachments
|
|
1482
|
-
}
|
|
1483
|
-
),
|
|
1484
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1485
|
-
"div",
|
|
1486
|
-
{
|
|
1487
|
-
"data-slot": "composer-input-wrapper",
|
|
1488
|
-
className: "relative flex-1",
|
|
1489
|
-
ref: mention.anchorRef,
|
|
1490
|
-
children: [
|
|
1491
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkH3GRO43Z_cjs.MentionMenu, { mention }),
|
|
1492
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1493
|
-
"textarea",
|
|
1494
|
-
{
|
|
1495
|
-
ref: textareaRef,
|
|
1496
|
-
"data-slot": "composer-input",
|
|
1497
|
-
value: content,
|
|
1498
|
-
onChange: (e) => {
|
|
1499
|
-
setContent(e.target.value);
|
|
1500
|
-
mention.sync(
|
|
1501
|
-
e.target.value,
|
|
1502
|
-
e.target.selectionStart ?? e.target.value.length
|
|
1503
|
-
);
|
|
1504
|
-
},
|
|
1505
|
-
onClick: (e) => {
|
|
1506
|
-
const el = e.currentTarget;
|
|
1507
|
-
mention.sync(el.value, el.selectionStart ?? el.value.length);
|
|
1508
|
-
},
|
|
1509
|
-
onKeyDown: handleKeyDown,
|
|
1510
|
-
onPaste: handlePaste,
|
|
1511
|
-
placeholder,
|
|
1512
|
-
disabled: disabled || isSending,
|
|
1513
|
-
rows: 1,
|
|
1514
|
-
className: chunkS5RVSXDV_cjs.cn(
|
|
1515
|
-
"w-full resize-none rounded-2xl py-2.5",
|
|
1516
|
-
inputTrailing ? "ps-4 pe-10" : "px-4",
|
|
1517
|
-
"bg-neutral-100 dark:bg-neutral-800",
|
|
1518
|
-
"text-neutral-900 dark:text-neutral-100",
|
|
1519
|
-
"placeholder:text-neutral-400 dark:placeholder:text-neutral-500",
|
|
1520
|
-
"focus:ring-primary-500 focus:ring-2 focus:outline-none",
|
|
1521
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1522
|
-
"transition-colors",
|
|
1523
|
-
"max-h-[150px]"
|
|
1524
|
-
),
|
|
1525
|
-
"aria-label": "Message",
|
|
1526
|
-
"aria-describedby": showCharacterCount ? "char-count" : void 0,
|
|
1527
|
-
...mention.inputProps
|
|
1528
|
-
}
|
|
1529
|
-
),
|
|
1530
|
-
inputTrailing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1531
|
-
"div",
|
|
1532
|
-
{
|
|
1533
|
-
"data-slot": "composer-input-trailing",
|
|
1534
|
-
className: "pointer-events-none absolute end-1 top-0 flex h-[44px] items-center [&>*]:pointer-events-auto",
|
|
1535
|
-
children: inputTrailing
|
|
1536
|
-
}
|
|
1537
|
-
),
|
|
1538
|
-
showCharacterCount && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1539
|
-
"div",
|
|
1540
|
-
{
|
|
1541
|
-
"data-slot": "composer-char-count",
|
|
1542
|
-
id: "char-count",
|
|
1543
|
-
className: "absolute end-3 bottom-1.5",
|
|
1544
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(CharacterCounter, { current: content.length, max: maxLength })
|
|
1545
|
-
}
|
|
1546
|
-
)
|
|
1547
|
-
]
|
|
1548
|
-
}
|
|
1549
|
-
),
|
|
1550
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1551
|
-
SendButton,
|
|
1552
|
-
{
|
|
1553
|
-
canSend,
|
|
1554
|
-
isLoading: isSending,
|
|
1555
|
-
disabled
|
|
1556
|
-
}
|
|
1557
|
-
)
|
|
1558
|
-
]
|
|
1559
|
-
}
|
|
1560
|
-
)
|
|
1561
|
-
]
|
|
1562
|
-
}
|
|
1563
|
-
)
|
|
1564
|
-
}
|
|
1565
|
-
);
|
|
1566
|
-
}
|
|
1567
|
-
);
|
|
1568
|
-
MessageComposer.displayName = "MessageComposer";
|
|
1569
|
-
var headerVariants = classVarianceAuthority.cva(
|
|
1570
|
-
[
|
|
1571
|
-
"flex items-center gap-3 px-4 py-3",
|
|
1572
|
-
"bg-white dark:bg-neutral-900",
|
|
1573
|
-
"border-b border-neutral-200 dark:border-neutral-700"
|
|
1345
|
+
"flex items-center gap-3 px-4 py-3",
|
|
1346
|
+
"bg-white dark:bg-neutral-900",
|
|
1347
|
+
"border-b border-neutral-200 dark:border-neutral-700"
|
|
1574
1348
|
],
|
|
1575
1349
|
{
|
|
1576
1350
|
variants: {
|
|
@@ -1625,7 +1399,7 @@ function formatLastSeen(date) {
|
|
|
1625
1399
|
if (diffDays < 7) return `${diffDays}d ago`;
|
|
1626
1400
|
return date.toLocaleDateString();
|
|
1627
1401
|
}
|
|
1628
|
-
var ConversationHeader =
|
|
1402
|
+
var ConversationHeader = React__namespace.forwardRef(
|
|
1629
1403
|
({
|
|
1630
1404
|
className,
|
|
1631
1405
|
size,
|
|
@@ -1747,7 +1521,7 @@ var ConversationHeader = React6__namespace.forwardRef(
|
|
|
1747
1521
|
}
|
|
1748
1522
|
);
|
|
1749
1523
|
ConversationHeader.displayName = "ConversationHeader";
|
|
1750
|
-
var ConversationListItem =
|
|
1524
|
+
var ConversationListItem = React__namespace.forwardRef(({ className, conversation, isSelected, onSelect, ...props }, ref) => {
|
|
1751
1525
|
const participant = conversation.participants.find((p) => !p.isCurrentUser);
|
|
1752
1526
|
const title = getConversationTitle(conversation, participant);
|
|
1753
1527
|
const avatarUrl = conversation.avatarUrl || participant?.avatarUrl;
|
|
@@ -1955,7 +1729,7 @@ function ConversationListSkeleton({
|
|
|
1955
1729
|
}
|
|
1956
1730
|
ConversationListSkeleton.displayName = "ConversationListSkeleton";
|
|
1957
1731
|
function LightboxModal({ attachment, onClose }) {
|
|
1958
|
-
|
|
1732
|
+
React__namespace.useEffect(() => {
|
|
1959
1733
|
const handleKeyDown = (event) => {
|
|
1960
1734
|
if (event.key === "Escape") {
|
|
1961
1735
|
onClose();
|
|
@@ -2052,7 +1826,7 @@ function LightboxModal({ attachment, onClose }) {
|
|
|
2052
1826
|
);
|
|
2053
1827
|
}
|
|
2054
1828
|
LightboxModal.displayName = "LightboxModal";
|
|
2055
|
-
var MessageThread =
|
|
1829
|
+
var MessageThread = React__namespace.forwardRef(
|
|
2056
1830
|
({
|
|
2057
1831
|
conversation,
|
|
2058
1832
|
messages,
|
|
@@ -2083,8 +1857,23 @@ var MessageThread = React6__namespace.forwardRef(
|
|
|
2083
1857
|
onError,
|
|
2084
1858
|
className
|
|
2085
1859
|
}, ref) => {
|
|
2086
|
-
const [lightboxAttachment, setLightboxAttachment] =
|
|
2087
|
-
const [replyTo, setReplyTo] =
|
|
1860
|
+
const [lightboxAttachment, setLightboxAttachment] = React__namespace.useState(null);
|
|
1861
|
+
const [replyTo, setReplyTo] = React__namespace.useState(null);
|
|
1862
|
+
const composerRef = React__namespace.useRef(null);
|
|
1863
|
+
React__namespace.useEffect(() => {
|
|
1864
|
+
chunkOYQ7GYAA_cjs.notifyComposerMigrationOnce("MessageThread");
|
|
1865
|
+
}, []);
|
|
1866
|
+
const [draft, setDraft] = React__namespace.useState("");
|
|
1867
|
+
const draftEpochRef = React__namespace.useRef(0);
|
|
1868
|
+
const handleDraftChange = React__namespace.useCallback((value) => {
|
|
1869
|
+
draftEpochRef.current += 1;
|
|
1870
|
+
setDraft(value);
|
|
1871
|
+
}, []);
|
|
1872
|
+
const { stopTyping } = useTypingEmulation({
|
|
1873
|
+
value: draft,
|
|
1874
|
+
onTypingStart: eventHandlers.onTypingStart,
|
|
1875
|
+
onTypingStop: eventHandlers.onTypingStop
|
|
1876
|
+
});
|
|
2088
1877
|
const participant = conversation?.type === "direct" ? conversation.participants.find((p) => p.id !== currentUser.id) : void 0;
|
|
2089
1878
|
const handleAttachmentClick = (attachment, message) => {
|
|
2090
1879
|
if (attachment.type === "image" || attachment.type === "video") {
|
|
@@ -2093,12 +1882,21 @@ var MessageThread = React6__namespace.forwardRef(
|
|
|
2093
1882
|
eventHandlers.onAttachmentClick?.(attachment, message);
|
|
2094
1883
|
};
|
|
2095
1884
|
const handleSendMessage = async (newMessage) => {
|
|
1885
|
+
stopTyping();
|
|
2096
1886
|
const messageWithReply = {
|
|
2097
1887
|
...newMessage,
|
|
2098
1888
|
replyToId: replyTo?.id || newMessage.replyToId
|
|
2099
1889
|
};
|
|
2100
1890
|
setReplyTo(null);
|
|
2101
|
-
|
|
1891
|
+
const epoch = draftEpochRef.current;
|
|
1892
|
+
try {
|
|
1893
|
+
await Promise.resolve(eventHandlers.onSendMessage?.(messageWithReply));
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
if (draftEpochRef.current === epoch) {
|
|
1896
|
+
setDraft(newMessage.content);
|
|
1897
|
+
}
|
|
1898
|
+
throw error;
|
|
1899
|
+
}
|
|
2102
1900
|
};
|
|
2103
1901
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2104
1902
|
"div",
|
|
@@ -2122,11 +1920,13 @@ var MessageThread = React6__namespace.forwardRef(
|
|
|
2122
1920
|
}
|
|
2123
1921
|
),
|
|
2124
1922
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2125
|
-
|
|
1923
|
+
chunkOYQ7GYAA_cjs.DragDropZone,
|
|
2126
1924
|
{
|
|
2127
|
-
onFilesDropped: () => {
|
|
2128
|
-
|
|
1925
|
+
onFilesDropped: (files) => {
|
|
1926
|
+
composerRef.current?.addFiles(files);
|
|
2129
1927
|
},
|
|
1928
|
+
maxFiles: maxAttachments,
|
|
1929
|
+
onError,
|
|
2130
1930
|
disabled: !showAttachmentPicker,
|
|
2131
1931
|
className: "flex-1 overflow-hidden",
|
|
2132
1932
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2152,23 +1952,38 @@ var MessageThread = React6__namespace.forwardRef(
|
|
|
2152
1952
|
}
|
|
2153
1953
|
),
|
|
2154
1954
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2155
|
-
|
|
1955
|
+
"div",
|
|
2156
1956
|
{
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
1957
|
+
"data-slot": "message-thread-composer",
|
|
1958
|
+
className: "shrink-0 border-t border-neutral-200 p-3 dark:border-neutral-700",
|
|
1959
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1960
|
+
chunkOYQ7GYAA_cjs.ChatComposer,
|
|
1961
|
+
{
|
|
1962
|
+
ref: composerRef,
|
|
1963
|
+
value: draft,
|
|
1964
|
+
onValueChange: handleDraftChange,
|
|
1965
|
+
onSend: handleSendMessage,
|
|
1966
|
+
placeholder,
|
|
1967
|
+
maxLength: maxMessageLength,
|
|
1968
|
+
showCharacterCount,
|
|
1969
|
+
isSending,
|
|
1970
|
+
allowAttachments: showAttachmentPicker,
|
|
1971
|
+
acceptedFileTypes: acceptedFileTypes ?? chunkOYQ7GYAA_cjs.DEFAULT_ACCEPTED_FILE_TYPES,
|
|
1972
|
+
maxFileSize: maxFileSize ?? chunkOYQ7GYAA_cjs.DEFAULT_MAX_FILE_SIZE,
|
|
1973
|
+
maxAttachments,
|
|
1974
|
+
onError,
|
|
1975
|
+
replyTo,
|
|
1976
|
+
onCancelReply: () => setReplyTo(null),
|
|
1977
|
+
inputLabel: "Message",
|
|
1978
|
+
micSlot: showCameraButton ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1979
|
+
chunkOYQ7GYAA_cjs.CameraButton,
|
|
1980
|
+
{
|
|
1981
|
+
onCapture: (file) => composerRef.current?.addFiles([file]),
|
|
1982
|
+
disabled: isSending
|
|
1983
|
+
}
|
|
1984
|
+
) : void 0
|
|
1985
|
+
}
|
|
1986
|
+
)
|
|
2172
1987
|
}
|
|
2173
1988
|
),
|
|
2174
1989
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2248,252 +2063,8 @@ function MessagingSplitView({
|
|
|
2248
2063
|
);
|
|
2249
2064
|
}
|
|
2250
2065
|
MessagingSplitView.displayName = "MessagingSplitView";
|
|
2251
|
-
function useMessages(options) {
|
|
2252
|
-
const {
|
|
2253
|
-
initialMessages = [],
|
|
2254
|
-
currentUser,
|
|
2255
|
-
onSend,
|
|
2256
|
-
onRetry,
|
|
2257
|
-
onLoadMore
|
|
2258
|
-
} = options;
|
|
2259
|
-
const [messages, setMessages] = React6__namespace.useState(initialMessages);
|
|
2260
|
-
const [isSending, setIsSending] = React6__namespace.useState(false);
|
|
2261
|
-
const [isLoadingMore, setIsLoadingMore] = React6__namespace.useState(false);
|
|
2262
|
-
React6__namespace.useEffect(() => {
|
|
2263
|
-
setMessages(initialMessages);
|
|
2264
|
-
}, [initialMessages]);
|
|
2265
|
-
const addMessage = React6__namespace.useCallback((message) => {
|
|
2266
|
-
setMessages((prev) => {
|
|
2267
|
-
if (prev.some((m) => m.id === message.id)) {
|
|
2268
|
-
return prev;
|
|
2269
|
-
}
|
|
2270
|
-
return [...prev, message];
|
|
2271
|
-
});
|
|
2272
|
-
}, []);
|
|
2273
|
-
const updateMessage = React6__namespace.useCallback(
|
|
2274
|
-
(messageId, updates) => {
|
|
2275
|
-
setMessages(
|
|
2276
|
-
(prev) => prev.map((m) => m.id === messageId ? { ...m, ...updates } : m)
|
|
2277
|
-
);
|
|
2278
|
-
},
|
|
2279
|
-
[]
|
|
2280
|
-
);
|
|
2281
|
-
const removeMessage = React6__namespace.useCallback((messageId) => {
|
|
2282
|
-
setMessages((prev) => prev.filter((m) => m.id !== messageId));
|
|
2283
|
-
}, []);
|
|
2284
|
-
const updateStatus = React6__namespace.useCallback(
|
|
2285
|
-
(messageId, status) => {
|
|
2286
|
-
updateMessage(messageId, { status });
|
|
2287
|
-
},
|
|
2288
|
-
[updateMessage]
|
|
2289
|
-
);
|
|
2290
|
-
const markAsRead = React6__namespace.useCallback(
|
|
2291
|
-
(messageId) => {
|
|
2292
|
-
updateStatus(messageId, "read");
|
|
2293
|
-
},
|
|
2294
|
-
[updateStatus]
|
|
2295
|
-
);
|
|
2296
|
-
const sendMessage = React6__namespace.useCallback(
|
|
2297
|
-
async (newMessage) => {
|
|
2298
|
-
const optimisticId = `optimistic-${Date.now()}`;
|
|
2299
|
-
const optimisticMessage = {
|
|
2300
|
-
id: optimisticId,
|
|
2301
|
-
type: "text",
|
|
2302
|
-
content: newMessage.content,
|
|
2303
|
-
sender: currentUser,
|
|
2304
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2305
|
-
status: "sending",
|
|
2306
|
-
attachments: []
|
|
2307
|
-
// Would handle attachment uploads here
|
|
2308
|
-
};
|
|
2309
|
-
addMessage(optimisticMessage);
|
|
2310
|
-
setIsSending(true);
|
|
2311
|
-
try {
|
|
2312
|
-
if (onSend) {
|
|
2313
|
-
const sentMessage = await onSend(newMessage);
|
|
2314
|
-
setMessages(
|
|
2315
|
-
(prev) => prev.map((m) => m.id === optimisticId ? sentMessage : m)
|
|
2316
|
-
);
|
|
2317
|
-
} else {
|
|
2318
|
-
updateStatus(optimisticId, "sent");
|
|
2319
|
-
}
|
|
2320
|
-
} catch {
|
|
2321
|
-
updateStatus(optimisticId, "failed");
|
|
2322
|
-
} finally {
|
|
2323
|
-
setIsSending(false);
|
|
2324
|
-
}
|
|
2325
|
-
},
|
|
2326
|
-
[currentUser, onSend, addMessage, updateStatus]
|
|
2327
|
-
);
|
|
2328
|
-
const retryMessage = React6__namespace.useCallback(
|
|
2329
|
-
async (messageId) => {
|
|
2330
|
-
updateStatus(messageId, "sending");
|
|
2331
|
-
try {
|
|
2332
|
-
if (onRetry) {
|
|
2333
|
-
await onRetry(messageId);
|
|
2334
|
-
updateStatus(messageId, "sent");
|
|
2335
|
-
}
|
|
2336
|
-
} catch {
|
|
2337
|
-
updateStatus(messageId, "failed");
|
|
2338
|
-
}
|
|
2339
|
-
},
|
|
2340
|
-
[onRetry, updateStatus]
|
|
2341
|
-
);
|
|
2342
|
-
const loadMore = React6__namespace.useCallback(async () => {
|
|
2343
|
-
if (isLoadingMore || !onLoadMore) return;
|
|
2344
|
-
setIsLoadingMore(true);
|
|
2345
|
-
try {
|
|
2346
|
-
const olderMessages = await onLoadMore();
|
|
2347
|
-
setMessages((prev) => [...olderMessages, ...prev]);
|
|
2348
|
-
} finally {
|
|
2349
|
-
setIsLoadingMore(false);
|
|
2350
|
-
}
|
|
2351
|
-
}, [isLoadingMore, onLoadMore]);
|
|
2352
|
-
return {
|
|
2353
|
-
messages,
|
|
2354
|
-
addMessage,
|
|
2355
|
-
updateMessage,
|
|
2356
|
-
removeMessage,
|
|
2357
|
-
sendMessage,
|
|
2358
|
-
retryMessage,
|
|
2359
|
-
loadMore,
|
|
2360
|
-
isSending,
|
|
2361
|
-
isLoadingMore,
|
|
2362
|
-
markAsRead,
|
|
2363
|
-
updateStatus
|
|
2364
|
-
};
|
|
2365
|
-
}
|
|
2366
|
-
function useTypingIndicator(options = {}) {
|
|
2367
|
-
const {
|
|
2368
|
-
typingParticipants: initialParticipants = [],
|
|
2369
|
-
debounceTime = 2e3,
|
|
2370
|
-
onTypingStart,
|
|
2371
|
-
onTypingStop
|
|
2372
|
-
} = options;
|
|
2373
|
-
const [participants, setParticipants] = React6__namespace.useState(initialParticipants);
|
|
2374
|
-
const [isLocalTyping, setIsLocalTyping] = React6__namespace.useState(false);
|
|
2375
|
-
const typingTimeoutRef = React6__namespace.useRef(null);
|
|
2376
|
-
React6__namespace.useEffect(() => {
|
|
2377
|
-
setParticipants(initialParticipants);
|
|
2378
|
-
}, [initialParticipants]);
|
|
2379
|
-
const startTyping = React6__namespace.useCallback(() => {
|
|
2380
|
-
if (!isLocalTyping) {
|
|
2381
|
-
setIsLocalTyping(true);
|
|
2382
|
-
onTypingStart?.();
|
|
2383
|
-
}
|
|
2384
|
-
if (typingTimeoutRef.current) {
|
|
2385
|
-
clearTimeout(typingTimeoutRef.current);
|
|
2386
|
-
}
|
|
2387
|
-
typingTimeoutRef.current = setTimeout(() => {
|
|
2388
|
-
setIsLocalTyping(false);
|
|
2389
|
-
onTypingStop?.();
|
|
2390
|
-
}, debounceTime);
|
|
2391
|
-
}, [isLocalTyping, debounceTime, onTypingStart, onTypingStop]);
|
|
2392
|
-
const stopTyping = React6__namespace.useCallback(() => {
|
|
2393
|
-
if (typingTimeoutRef.current) {
|
|
2394
|
-
clearTimeout(typingTimeoutRef.current);
|
|
2395
|
-
}
|
|
2396
|
-
setIsLocalTyping(false);
|
|
2397
|
-
onTypingStop?.();
|
|
2398
|
-
}, [onTypingStop]);
|
|
2399
|
-
React6__namespace.useEffect(() => {
|
|
2400
|
-
return () => {
|
|
2401
|
-
if (typingTimeoutRef.current) {
|
|
2402
|
-
clearTimeout(typingTimeoutRef.current);
|
|
2403
|
-
}
|
|
2404
|
-
};
|
|
2405
|
-
}, []);
|
|
2406
|
-
const typingState = React6__namespace.useMemo(
|
|
2407
|
-
() => ({
|
|
2408
|
-
participants,
|
|
2409
|
-
lastUpdated: /* @__PURE__ */ new Date()
|
|
2410
|
-
}),
|
|
2411
|
-
[participants]
|
|
2412
|
-
);
|
|
2413
|
-
return {
|
|
2414
|
-
typingState,
|
|
2415
|
-
startTyping,
|
|
2416
|
-
stopTyping,
|
|
2417
|
-
setTypingParticipants: setParticipants
|
|
2418
|
-
};
|
|
2419
|
-
}
|
|
2420
|
-
function useMessageScroll(options) {
|
|
2421
|
-
const { messages, currentUserId, threshold = 100 } = options;
|
|
2422
|
-
const scrollContainerRef = React6__namespace.useRef(null);
|
|
2423
|
-
const bottomRef = React6__namespace.useRef(null);
|
|
2424
|
-
const [isScrolledUp, setIsScrolledUp] = React6__namespace.useState(false);
|
|
2425
|
-
const prevMessageCountRef = React6__namespace.useRef(messages.length);
|
|
2426
|
-
React6__namespace.useEffect(() => {
|
|
2427
|
-
const container = scrollContainerRef.current;
|
|
2428
|
-
if (!container) return;
|
|
2429
|
-
const handleScroll = () => {
|
|
2430
|
-
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
2431
|
-
const isAtBottom = scrollHeight - scrollTop - clientHeight < threshold;
|
|
2432
|
-
setIsScrolledUp(!isAtBottom);
|
|
2433
|
-
};
|
|
2434
|
-
container.addEventListener("scroll", handleScroll);
|
|
2435
|
-
return () => container.removeEventListener("scroll", handleScroll);
|
|
2436
|
-
}, [threshold]);
|
|
2437
|
-
const scrollToBottom = React6__namespace.useCallback((smooth = true) => {
|
|
2438
|
-
bottomRef.current?.scrollIntoView({
|
|
2439
|
-
behavior: smooth ? "smooth" : "auto"
|
|
2440
|
-
});
|
|
2441
|
-
}, []);
|
|
2442
|
-
React6__namespace.useEffect(() => {
|
|
2443
|
-
const messageCountChanged = messages.length !== prevMessageCountRef.current;
|
|
2444
|
-
prevMessageCountRef.current = messages.length;
|
|
2445
|
-
if (!messageCountChanged) return;
|
|
2446
|
-
const lastMessage = messages[messages.length - 1];
|
|
2447
|
-
const isOutgoing = lastMessage?.sender.id === currentUserId;
|
|
2448
|
-
if (isOutgoing || !isScrolledUp) {
|
|
2449
|
-
scrollToBottom(true);
|
|
2450
|
-
}
|
|
2451
|
-
}, [messages, currentUserId, isScrolledUp, scrollToBottom]);
|
|
2452
|
-
return {
|
|
2453
|
-
scrollContainerRef,
|
|
2454
|
-
bottomRef,
|
|
2455
|
-
isScrolledUp,
|
|
2456
|
-
scrollToBottom
|
|
2457
|
-
};
|
|
2458
|
-
}
|
|
2459
|
-
function useReadReceipts(options) {
|
|
2460
|
-
const { currentUserId, onMarkRead, threshold = 0.5 } = options;
|
|
2461
|
-
const observerRef = React6__namespace.useRef(null);
|
|
2462
|
-
const observedMessagesRef = React6__namespace.useRef(/* @__PURE__ */ new Set());
|
|
2463
|
-
React6__namespace.useEffect(() => {
|
|
2464
|
-
observerRef.current = new IntersectionObserver(
|
|
2465
|
-
(entries) => {
|
|
2466
|
-
entries.forEach((entry) => {
|
|
2467
|
-
if (entry.isIntersecting) {
|
|
2468
|
-
const messageId = entry.target.getAttribute("data-message-id");
|
|
2469
|
-
if (messageId && !observedMessagesRef.current.has(messageId)) {
|
|
2470
|
-
observedMessagesRef.current.add(messageId);
|
|
2471
|
-
onMarkRead?.(messageId);
|
|
2472
|
-
}
|
|
2473
|
-
}
|
|
2474
|
-
});
|
|
2475
|
-
},
|
|
2476
|
-
{ threshold }
|
|
2477
|
-
);
|
|
2478
|
-
return () => {
|
|
2479
|
-
observerRef.current?.disconnect();
|
|
2480
|
-
};
|
|
2481
|
-
}, [onMarkRead, threshold]);
|
|
2482
|
-
const observeMessage = React6__namespace.useCallback(
|
|
2483
|
-
(element, message) => {
|
|
2484
|
-
if (!element || !observerRef.current) return;
|
|
2485
|
-
if (message.sender.id !== currentUserId && message.status !== "read" && !observedMessagesRef.current.has(message.id)) {
|
|
2486
|
-
element.setAttribute("data-message-id", message.id);
|
|
2487
|
-
observerRef.current.observe(element);
|
|
2488
|
-
}
|
|
2489
|
-
},
|
|
2490
|
-
[currentUserId]
|
|
2491
|
-
);
|
|
2492
|
-
return { observeMessage };
|
|
2493
|
-
}
|
|
2494
2066
|
|
|
2495
2067
|
exports.AttachmentPreview = AttachmentPreview;
|
|
2496
|
-
exports.CharacterCounter = CharacterCounter;
|
|
2497
2068
|
exports.ConversationHeader = ConversationHeader;
|
|
2498
2069
|
exports.ConversationListItem = ConversationListItem;
|
|
2499
2070
|
exports.ConversationListSkeleton = ConversationListSkeleton;
|
|
@@ -2502,13 +2073,11 @@ exports.EmptyState = EmptyState;
|
|
|
2502
2073
|
exports.LightboxModal = LightboxModal;
|
|
2503
2074
|
exports.LoadMoreButton = LoadMoreButton;
|
|
2504
2075
|
exports.MessageBubble = MessageBubble;
|
|
2505
|
-
exports.MessageComposer = MessageComposer;
|
|
2506
2076
|
exports.MessageList = MessageList;
|
|
2507
2077
|
exports.MessageStatusIcon = MessageStatusIcon;
|
|
2508
2078
|
exports.MessageThread = MessageThread;
|
|
2509
2079
|
exports.MessagingSplitView = MessagingSplitView;
|
|
2510
2080
|
exports.ReadReceiptIndicator = ReadReceiptIndicator;
|
|
2511
|
-
exports.SendButton = SendButton;
|
|
2512
2081
|
exports.SkeletonMessage = SkeletonMessage;
|
|
2513
2082
|
exports.TypingIndicator = TypingIndicator;
|
|
2514
2083
|
exports.bubbleVariants = bubbleVariants;
|
|
@@ -2520,10 +2089,10 @@ exports.getConversationTitle = getConversationTitle;
|
|
|
2520
2089
|
exports.groupMessagesByDate = groupMessagesByDate;
|
|
2521
2090
|
exports.headerVariants = headerVariants;
|
|
2522
2091
|
exports.isSameSenderGroup = isSameSenderGroup;
|
|
2523
|
-
exports.sendButtonVariants = sendButtonVariants;
|
|
2524
2092
|
exports.useMessageScroll = useMessageScroll;
|
|
2525
2093
|
exports.useMessages = useMessages;
|
|
2526
2094
|
exports.useReadReceipts = useReadReceipts;
|
|
2095
|
+
exports.useTypingEmulation = useTypingEmulation;
|
|
2527
2096
|
exports.useTypingIndicator = useTypingIndicator;
|
|
2528
|
-
//# sourceMappingURL=chunk-
|
|
2529
|
-
//# sourceMappingURL=chunk-
|
|
2097
|
+
//# sourceMappingURL=chunk-OFUKTVBN.cjs.map
|
|
2098
|
+
//# sourceMappingURL=chunk-OFUKTVBN.cjs.map
|