@mieweb/ui 0.9.0 → 0.10.0-dev.0
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/{Animated-Cs-naa2g.d.cts → Animated-XmH6k8pZ.d.cts} +16 -3
- package/dist/{Animated-Cs-naa2g.d.ts → Animated-XmH6k8pZ.d.ts} +16 -3
- package/dist/{chunk-XUVEF2RQ.js → chunk-24SEAAOH.js} +2 -2
- package/dist/{chunk-XUVEF2RQ.js.map → chunk-24SEAAOH.js.map} +1 -1
- package/dist/{chunk-FUFBRKOG.cjs → chunk-2WBPNXO2.cjs} +21 -21
- package/dist/{chunk-FUFBRKOG.cjs.map → chunk-2WBPNXO2.cjs.map} +1 -1
- package/dist/{chunk-IUDY6S7I.cjs → chunk-37UZHCLM.cjs} +35 -14
- package/dist/chunk-37UZHCLM.cjs.map +1 -0
- package/dist/{chunk-L52N6BEN.cjs → chunk-AUOTJQGO.cjs} +7 -7
- package/dist/{chunk-L52N6BEN.cjs.map → chunk-AUOTJQGO.cjs.map} +1 -1
- package/dist/{chunk-6XDPJWSC.cjs → chunk-E7G22IQM.cjs} +32 -28
- package/dist/chunk-E7G22IQM.cjs.map +1 -0
- package/dist/chunk-IIFQ6BSJ.js +1888 -0
- package/dist/chunk-IIFQ6BSJ.js.map +1 -0
- package/dist/{chunk-ONNY7UO4.js → chunk-JDJQTKTX.js} +3 -3
- package/dist/{chunk-ONNY7UO4.js.map → chunk-JDJQTKTX.js.map} +1 -1
- package/dist/{chunk-BJKAVWED.js → chunk-MBWF36DJ.js} +35 -14
- package/dist/chunk-MBWF36DJ.js.map +1 -0
- package/dist/chunk-NV2CWBI2.cjs +290 -0
- package/dist/chunk-NV2CWBI2.cjs.map +1 -0
- package/dist/{chunk-FQBTGS3E.cjs → chunk-OFUKTVBN.cjs} +363 -285
- package/dist/chunk-OFUKTVBN.cjs.map +1 -0
- package/dist/{chunk-7KN6J7XV.cjs → chunk-OMAACCFW.cjs} +7 -7
- package/dist/{chunk-7KN6J7XV.cjs.map → chunk-OMAACCFW.cjs.map} +1 -1
- package/dist/chunk-OYQ7GYAA.cjs +1921 -0
- package/dist/chunk-OYQ7GYAA.cjs.map +1 -0
- package/dist/{chunk-YJP6DUFO.cjs → chunk-PKD3JLS2.cjs} +6 -6
- package/dist/{chunk-YJP6DUFO.cjs.map → chunk-PKD3JLS2.cjs.map} +1 -1
- package/dist/{chunk-CXDMZT45.cjs → chunk-PY7XAG4D.cjs} +27 -4
- package/dist/chunk-PY7XAG4D.cjs.map +1 -0
- package/dist/{chunk-5H7SAEQO.js → chunk-QKFJDQEK.js} +3 -3
- package/dist/{chunk-5H7SAEQO.js.map → chunk-QKFJDQEK.js.map} +1 -1
- package/dist/{chunk-XJTFZLWH.cjs → chunk-QO6PRHDX.cjs} +2 -2
- package/dist/{chunk-XJTFZLWH.cjs.map → chunk-QO6PRHDX.cjs.map} +1 -1
- package/dist/{chunk-OHDIJOGG.js → chunk-RD3JDFYJ.js} +3 -3
- package/dist/{chunk-OHDIJOGG.js.map → chunk-RD3JDFYJ.js.map} +1 -1
- package/dist/{chunk-4SM3I7WE.cjs → chunk-RXPEZXAB.cjs} +67 -38
- package/dist/chunk-RXPEZXAB.cjs.map +1 -0
- package/dist/{chunk-VTR2KGLY.cjs → chunk-S3BCHPXT.cjs} +9 -9
- package/dist/{chunk-VTR2KGLY.cjs.map → chunk-S3BCHPXT.cjs.map} +1 -1
- package/dist/{chunk-KU3XRHWA.js → chunk-TZX76ZNZ.js} +67 -38
- package/dist/chunk-TZX76ZNZ.js.map +1 -0
- package/dist/{chunk-MXQ7J4BB.js → chunk-VSVGMMNO.js} +361 -284
- package/dist/chunk-VSVGMMNO.js.map +1 -0
- package/dist/{chunk-Q7G56ZIO.js → chunk-WUBMDOTG.js} +3 -3
- package/dist/{chunk-Q7G56ZIO.js.map → chunk-WUBMDOTG.js.map} +1 -1
- package/dist/{chunk-DGRXAIWK.js → chunk-X5YM3KXY.js} +27 -4
- package/dist/chunk-X5YM3KXY.js.map +1 -0
- package/dist/chunk-XCP454Q6.js +263 -0
- package/dist/chunk-XCP454Q6.js.map +1 -0
- package/dist/{chunk-I3DQXUSC.js → chunk-Y6DFMDMH.js} +3 -3
- package/dist/{chunk-I3DQXUSC.js.map → chunk-Y6DFMDMH.js.map} +1 -1
- package/dist/{chunk-ODYQYLO2.js → chunk-YSEMAI4I.js} +8 -4
- package/dist/chunk-YSEMAI4I.js.map +1 -0
- package/dist/components/AlertDialog/index.cjs +4 -4
- package/dist/components/AlertDialog/index.js +3 -3
- package/dist/components/Collapsible/index.cjs +6 -4
- package/dist/components/Collapsible/index.js +3 -1
- package/dist/components/Dropdown/index.cjs +9 -8
- package/dist/components/Dropdown/index.js +2 -1
- package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
- package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
- package/dist/components/MediaEditor/index.cjs +8 -8
- package/dist/components/MediaEditor/index.js +3 -3
- package/dist/components/Modal/index.cjs +10 -10
- package/dist/components/Modal/index.js +2 -2
- package/dist/components/RichTextEditor/index.cjs +6 -5
- package/dist/components/RichTextEditor/index.js +3 -2
- package/dist/components/SuperChat/index.cjs +40 -17
- package/dist/components/SuperChat/index.cjs.map +1 -1
- package/dist/components/SuperChat/index.d.cts +20 -7
- package/dist/components/SuperChat/index.d.ts +20 -7
- package/dist/components/SuperChat/index.js +35 -12
- 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.d.cts +3 -3
- package/dist/components/SuperChat/plugins/index.d.ts +3 -3
- package/dist/components/SuperChat/plugins/index.js +9 -2
- package/dist/components/SuperChat/plugins/index.js.map +1 -1
- package/dist/esheet.cjs +6 -6
- package/dist/esheet.js +3 -3
- package/dist/hooks/index.cjs +13 -13
- package/dist/hooks/index.js +1 -1
- package/dist/index.cjs +720 -1671
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +347 -347
- package/dist/index.d.ts +347 -347
- package/dist/index.js +459 -1405
- package/dist/index.js.map +1 -1
- package/dist/motion.cjs +7 -7
- package/dist/motion.d.cts +1 -1
- package/dist/motion.d.ts +1 -1
- package/dist/motion.js +2 -2
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/dist/{types-DZDroUW8.d.cts → types-B97JNRNQ.d.cts} +1 -1
- package/dist/{types-B2RLmdVd.d.ts → types-CnPEwzlp.d.cts} +6 -2
- package/dist/{types-B2RLmdVd.d.cts → types-CnPEwzlp.d.ts} +6 -2
- package/dist/{types-9vK_YdEb.d.ts → types-gZXrfLj6.d.ts} +1 -1
- package/package.json +2 -1
- package/dist/chunk-4SM3I7WE.cjs.map +0 -1
- package/dist/chunk-5BVFVXHN.cjs +0 -1244
- package/dist/chunk-5BVFVXHN.cjs.map +0 -1
- package/dist/chunk-6XDPJWSC.cjs.map +0 -1
- package/dist/chunk-BJKAVWED.js.map +0 -1
- package/dist/chunk-BN75TLUN.cjs +0 -163
- package/dist/chunk-BN75TLUN.cjs.map +0 -1
- package/dist/chunk-CXDMZT45.cjs.map +0 -1
- package/dist/chunk-DGRXAIWK.js.map +0 -1
- package/dist/chunk-FQBTGS3E.cjs.map +0 -1
- package/dist/chunk-IUDY6S7I.cjs.map +0 -1
- package/dist/chunk-KU3XRHWA.js.map +0 -1
- package/dist/chunk-MXQ7J4BB.js.map +0 -1
- package/dist/chunk-O6GJ4IYS.js +0 -1210
- package/dist/chunk-O6GJ4IYS.js.map +0 -1
- package/dist/chunk-ODYQYLO2.js.map +0 -1
- package/dist/chunk-WYMO3IIK.js +0 -136
- package/dist/chunk-WYMO3IIK.js.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 = React5__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 = React5__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 = React5__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];
|
|
@@ -1120,7 +1399,7 @@ function formatLastSeen(date) {
|
|
|
1120
1399
|
if (diffDays < 7) return `${diffDays}d ago`;
|
|
1121
1400
|
return date.toLocaleDateString();
|
|
1122
1401
|
}
|
|
1123
|
-
var ConversationHeader =
|
|
1402
|
+
var ConversationHeader = React__namespace.forwardRef(
|
|
1124
1403
|
({
|
|
1125
1404
|
className,
|
|
1126
1405
|
size,
|
|
@@ -1242,7 +1521,7 @@ var ConversationHeader = React5__namespace.forwardRef(
|
|
|
1242
1521
|
}
|
|
1243
1522
|
);
|
|
1244
1523
|
ConversationHeader.displayName = "ConversationHeader";
|
|
1245
|
-
var ConversationListItem =
|
|
1524
|
+
var ConversationListItem = React__namespace.forwardRef(({ className, conversation, isSelected, onSelect, ...props }, ref) => {
|
|
1246
1525
|
const participant = conversation.participants.find((p) => !p.isCurrentUser);
|
|
1247
1526
|
const title = getConversationTitle(conversation, participant);
|
|
1248
1527
|
const avatarUrl = conversation.avatarUrl || participant?.avatarUrl;
|
|
@@ -1450,7 +1729,7 @@ function ConversationListSkeleton({
|
|
|
1450
1729
|
}
|
|
1451
1730
|
ConversationListSkeleton.displayName = "ConversationListSkeleton";
|
|
1452
1731
|
function LightboxModal({ attachment, onClose }) {
|
|
1453
|
-
|
|
1732
|
+
React__namespace.useEffect(() => {
|
|
1454
1733
|
const handleKeyDown = (event) => {
|
|
1455
1734
|
if (event.key === "Escape") {
|
|
1456
1735
|
onClose();
|
|
@@ -1547,7 +1826,7 @@ function LightboxModal({ attachment, onClose }) {
|
|
|
1547
1826
|
);
|
|
1548
1827
|
}
|
|
1549
1828
|
LightboxModal.displayName = "LightboxModal";
|
|
1550
|
-
var MessageThread =
|
|
1829
|
+
var MessageThread = React__namespace.forwardRef(
|
|
1551
1830
|
({
|
|
1552
1831
|
conversation,
|
|
1553
1832
|
messages,
|
|
@@ -1578,8 +1857,23 @@ var MessageThread = React5__namespace.forwardRef(
|
|
|
1578
1857
|
onError,
|
|
1579
1858
|
className
|
|
1580
1859
|
}, ref) => {
|
|
1581
|
-
const [lightboxAttachment, setLightboxAttachment] =
|
|
1582
|
-
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
|
+
});
|
|
1583
1877
|
const participant = conversation?.type === "direct" ? conversation.participants.find((p) => p.id !== currentUser.id) : void 0;
|
|
1584
1878
|
const handleAttachmentClick = (attachment, message) => {
|
|
1585
1879
|
if (attachment.type === "image" || attachment.type === "video") {
|
|
@@ -1588,12 +1882,21 @@ var MessageThread = React5__namespace.forwardRef(
|
|
|
1588
1882
|
eventHandlers.onAttachmentClick?.(attachment, message);
|
|
1589
1883
|
};
|
|
1590
1884
|
const handleSendMessage = async (newMessage) => {
|
|
1885
|
+
stopTyping();
|
|
1591
1886
|
const messageWithReply = {
|
|
1592
1887
|
...newMessage,
|
|
1593
1888
|
replyToId: replyTo?.id || newMessage.replyToId
|
|
1594
1889
|
};
|
|
1595
1890
|
setReplyTo(null);
|
|
1596
|
-
|
|
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
|
+
}
|
|
1597
1900
|
};
|
|
1598
1901
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1599
1902
|
"div",
|
|
@@ -1617,11 +1920,13 @@ var MessageThread = React5__namespace.forwardRef(
|
|
|
1617
1920
|
}
|
|
1618
1921
|
),
|
|
1619
1922
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1620
|
-
|
|
1923
|
+
chunkOYQ7GYAA_cjs.DragDropZone,
|
|
1621
1924
|
{
|
|
1622
|
-
onFilesDropped: () => {
|
|
1623
|
-
|
|
1925
|
+
onFilesDropped: (files) => {
|
|
1926
|
+
composerRef.current?.addFiles(files);
|
|
1624
1927
|
},
|
|
1928
|
+
maxFiles: maxAttachments,
|
|
1929
|
+
onError,
|
|
1625
1930
|
disabled: !showAttachmentPicker,
|
|
1626
1931
|
className: "flex-1 overflow-hidden",
|
|
1627
1932
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1647,23 +1952,38 @@ var MessageThread = React5__namespace.forwardRef(
|
|
|
1647
1952
|
}
|
|
1648
1953
|
),
|
|
1649
1954
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1650
|
-
|
|
1955
|
+
"div",
|
|
1651
1956
|
{
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
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
|
+
)
|
|
1667
1987
|
}
|
|
1668
1988
|
),
|
|
1669
1989
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1743,249 +2063,6 @@ function MessagingSplitView({
|
|
|
1743
2063
|
);
|
|
1744
2064
|
}
|
|
1745
2065
|
MessagingSplitView.displayName = "MessagingSplitView";
|
|
1746
|
-
function useMessages(options) {
|
|
1747
|
-
const {
|
|
1748
|
-
initialMessages = [],
|
|
1749
|
-
currentUser,
|
|
1750
|
-
onSend,
|
|
1751
|
-
onRetry,
|
|
1752
|
-
onLoadMore
|
|
1753
|
-
} = options;
|
|
1754
|
-
const [messages, setMessages] = React5__namespace.useState(initialMessages);
|
|
1755
|
-
const [isSending, setIsSending] = React5__namespace.useState(false);
|
|
1756
|
-
const [isLoadingMore, setIsLoadingMore] = React5__namespace.useState(false);
|
|
1757
|
-
React5__namespace.useEffect(() => {
|
|
1758
|
-
setMessages(initialMessages);
|
|
1759
|
-
}, [initialMessages]);
|
|
1760
|
-
const addMessage = React5__namespace.useCallback((message) => {
|
|
1761
|
-
setMessages((prev) => {
|
|
1762
|
-
if (prev.some((m) => m.id === message.id)) {
|
|
1763
|
-
return prev;
|
|
1764
|
-
}
|
|
1765
|
-
return [...prev, message];
|
|
1766
|
-
});
|
|
1767
|
-
}, []);
|
|
1768
|
-
const updateMessage = React5__namespace.useCallback(
|
|
1769
|
-
(messageId, updates) => {
|
|
1770
|
-
setMessages(
|
|
1771
|
-
(prev) => prev.map((m) => m.id === messageId ? { ...m, ...updates } : m)
|
|
1772
|
-
);
|
|
1773
|
-
},
|
|
1774
|
-
[]
|
|
1775
|
-
);
|
|
1776
|
-
const removeMessage = React5__namespace.useCallback((messageId) => {
|
|
1777
|
-
setMessages((prev) => prev.filter((m) => m.id !== messageId));
|
|
1778
|
-
}, []);
|
|
1779
|
-
const updateStatus = React5__namespace.useCallback(
|
|
1780
|
-
(messageId, status) => {
|
|
1781
|
-
updateMessage(messageId, { status });
|
|
1782
|
-
},
|
|
1783
|
-
[updateMessage]
|
|
1784
|
-
);
|
|
1785
|
-
const markAsRead = React5__namespace.useCallback(
|
|
1786
|
-
(messageId) => {
|
|
1787
|
-
updateStatus(messageId, "read");
|
|
1788
|
-
},
|
|
1789
|
-
[updateStatus]
|
|
1790
|
-
);
|
|
1791
|
-
const sendMessage = React5__namespace.useCallback(
|
|
1792
|
-
async (newMessage) => {
|
|
1793
|
-
const optimisticId = `optimistic-${Date.now()}`;
|
|
1794
|
-
const optimisticMessage = {
|
|
1795
|
-
id: optimisticId,
|
|
1796
|
-
type: "text",
|
|
1797
|
-
content: newMessage.content,
|
|
1798
|
-
sender: currentUser,
|
|
1799
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
1800
|
-
status: "sending",
|
|
1801
|
-
attachments: []
|
|
1802
|
-
// Would handle attachment uploads here
|
|
1803
|
-
};
|
|
1804
|
-
addMessage(optimisticMessage);
|
|
1805
|
-
setIsSending(true);
|
|
1806
|
-
try {
|
|
1807
|
-
if (onSend) {
|
|
1808
|
-
const sentMessage = await onSend(newMessage);
|
|
1809
|
-
setMessages(
|
|
1810
|
-
(prev) => prev.map((m) => m.id === optimisticId ? sentMessage : m)
|
|
1811
|
-
);
|
|
1812
|
-
} else {
|
|
1813
|
-
updateStatus(optimisticId, "sent");
|
|
1814
|
-
}
|
|
1815
|
-
} catch {
|
|
1816
|
-
updateStatus(optimisticId, "failed");
|
|
1817
|
-
} finally {
|
|
1818
|
-
setIsSending(false);
|
|
1819
|
-
}
|
|
1820
|
-
},
|
|
1821
|
-
[currentUser, onSend, addMessage, updateStatus]
|
|
1822
|
-
);
|
|
1823
|
-
const retryMessage = React5__namespace.useCallback(
|
|
1824
|
-
async (messageId) => {
|
|
1825
|
-
updateStatus(messageId, "sending");
|
|
1826
|
-
try {
|
|
1827
|
-
if (onRetry) {
|
|
1828
|
-
await onRetry(messageId);
|
|
1829
|
-
updateStatus(messageId, "sent");
|
|
1830
|
-
}
|
|
1831
|
-
} catch {
|
|
1832
|
-
updateStatus(messageId, "failed");
|
|
1833
|
-
}
|
|
1834
|
-
},
|
|
1835
|
-
[onRetry, updateStatus]
|
|
1836
|
-
);
|
|
1837
|
-
const loadMore = React5__namespace.useCallback(async () => {
|
|
1838
|
-
if (isLoadingMore || !onLoadMore) return;
|
|
1839
|
-
setIsLoadingMore(true);
|
|
1840
|
-
try {
|
|
1841
|
-
const olderMessages = await onLoadMore();
|
|
1842
|
-
setMessages((prev) => [...olderMessages, ...prev]);
|
|
1843
|
-
} finally {
|
|
1844
|
-
setIsLoadingMore(false);
|
|
1845
|
-
}
|
|
1846
|
-
}, [isLoadingMore, onLoadMore]);
|
|
1847
|
-
return {
|
|
1848
|
-
messages,
|
|
1849
|
-
addMessage,
|
|
1850
|
-
updateMessage,
|
|
1851
|
-
removeMessage,
|
|
1852
|
-
sendMessage,
|
|
1853
|
-
retryMessage,
|
|
1854
|
-
loadMore,
|
|
1855
|
-
isSending,
|
|
1856
|
-
isLoadingMore,
|
|
1857
|
-
markAsRead,
|
|
1858
|
-
updateStatus
|
|
1859
|
-
};
|
|
1860
|
-
}
|
|
1861
|
-
function useTypingIndicator(options = {}) {
|
|
1862
|
-
const {
|
|
1863
|
-
typingParticipants: initialParticipants = [],
|
|
1864
|
-
debounceTime = 2e3,
|
|
1865
|
-
onTypingStart,
|
|
1866
|
-
onTypingStop
|
|
1867
|
-
} = options;
|
|
1868
|
-
const [participants, setParticipants] = React5__namespace.useState(initialParticipants);
|
|
1869
|
-
const [isLocalTyping, setIsLocalTyping] = React5__namespace.useState(false);
|
|
1870
|
-
const typingTimeoutRef = React5__namespace.useRef(null);
|
|
1871
|
-
React5__namespace.useEffect(() => {
|
|
1872
|
-
setParticipants(initialParticipants);
|
|
1873
|
-
}, [initialParticipants]);
|
|
1874
|
-
const startTyping = React5__namespace.useCallback(() => {
|
|
1875
|
-
if (!isLocalTyping) {
|
|
1876
|
-
setIsLocalTyping(true);
|
|
1877
|
-
onTypingStart?.();
|
|
1878
|
-
}
|
|
1879
|
-
if (typingTimeoutRef.current) {
|
|
1880
|
-
clearTimeout(typingTimeoutRef.current);
|
|
1881
|
-
}
|
|
1882
|
-
typingTimeoutRef.current = setTimeout(() => {
|
|
1883
|
-
setIsLocalTyping(false);
|
|
1884
|
-
onTypingStop?.();
|
|
1885
|
-
}, debounceTime);
|
|
1886
|
-
}, [isLocalTyping, debounceTime, onTypingStart, onTypingStop]);
|
|
1887
|
-
const stopTyping = React5__namespace.useCallback(() => {
|
|
1888
|
-
if (typingTimeoutRef.current) {
|
|
1889
|
-
clearTimeout(typingTimeoutRef.current);
|
|
1890
|
-
}
|
|
1891
|
-
setIsLocalTyping(false);
|
|
1892
|
-
onTypingStop?.();
|
|
1893
|
-
}, [onTypingStop]);
|
|
1894
|
-
React5__namespace.useEffect(() => {
|
|
1895
|
-
return () => {
|
|
1896
|
-
if (typingTimeoutRef.current) {
|
|
1897
|
-
clearTimeout(typingTimeoutRef.current);
|
|
1898
|
-
}
|
|
1899
|
-
};
|
|
1900
|
-
}, []);
|
|
1901
|
-
const typingState = React5__namespace.useMemo(
|
|
1902
|
-
() => ({
|
|
1903
|
-
participants,
|
|
1904
|
-
lastUpdated: /* @__PURE__ */ new Date()
|
|
1905
|
-
}),
|
|
1906
|
-
[participants]
|
|
1907
|
-
);
|
|
1908
|
-
return {
|
|
1909
|
-
typingState,
|
|
1910
|
-
startTyping,
|
|
1911
|
-
stopTyping,
|
|
1912
|
-
setTypingParticipants: setParticipants
|
|
1913
|
-
};
|
|
1914
|
-
}
|
|
1915
|
-
function useMessageScroll(options) {
|
|
1916
|
-
const { messages, currentUserId, threshold = 100 } = options;
|
|
1917
|
-
const scrollContainerRef = React5__namespace.useRef(null);
|
|
1918
|
-
const bottomRef = React5__namespace.useRef(null);
|
|
1919
|
-
const [isScrolledUp, setIsScrolledUp] = React5__namespace.useState(false);
|
|
1920
|
-
const prevMessageCountRef = React5__namespace.useRef(messages.length);
|
|
1921
|
-
React5__namespace.useEffect(() => {
|
|
1922
|
-
const container = scrollContainerRef.current;
|
|
1923
|
-
if (!container) return;
|
|
1924
|
-
const handleScroll = () => {
|
|
1925
|
-
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1926
|
-
const isAtBottom = scrollHeight - scrollTop - clientHeight < threshold;
|
|
1927
|
-
setIsScrolledUp(!isAtBottom);
|
|
1928
|
-
};
|
|
1929
|
-
container.addEventListener("scroll", handleScroll);
|
|
1930
|
-
return () => container.removeEventListener("scroll", handleScroll);
|
|
1931
|
-
}, [threshold]);
|
|
1932
|
-
const scrollToBottom = React5__namespace.useCallback((smooth = true) => {
|
|
1933
|
-
bottomRef.current?.scrollIntoView({
|
|
1934
|
-
behavior: smooth ? "smooth" : "auto"
|
|
1935
|
-
});
|
|
1936
|
-
}, []);
|
|
1937
|
-
React5__namespace.useEffect(() => {
|
|
1938
|
-
const messageCountChanged = messages.length !== prevMessageCountRef.current;
|
|
1939
|
-
prevMessageCountRef.current = messages.length;
|
|
1940
|
-
if (!messageCountChanged) return;
|
|
1941
|
-
const lastMessage = messages[messages.length - 1];
|
|
1942
|
-
const isOutgoing = lastMessage?.sender.id === currentUserId;
|
|
1943
|
-
if (isOutgoing || !isScrolledUp) {
|
|
1944
|
-
scrollToBottom(true);
|
|
1945
|
-
}
|
|
1946
|
-
}, [messages, currentUserId, isScrolledUp, scrollToBottom]);
|
|
1947
|
-
return {
|
|
1948
|
-
scrollContainerRef,
|
|
1949
|
-
bottomRef,
|
|
1950
|
-
isScrolledUp,
|
|
1951
|
-
scrollToBottom
|
|
1952
|
-
};
|
|
1953
|
-
}
|
|
1954
|
-
function useReadReceipts(options) {
|
|
1955
|
-
const { currentUserId, onMarkRead, threshold = 0.5 } = options;
|
|
1956
|
-
const observerRef = React5__namespace.useRef(null);
|
|
1957
|
-
const observedMessagesRef = React5__namespace.useRef(/* @__PURE__ */ new Set());
|
|
1958
|
-
React5__namespace.useEffect(() => {
|
|
1959
|
-
observerRef.current = new IntersectionObserver(
|
|
1960
|
-
(entries) => {
|
|
1961
|
-
entries.forEach((entry) => {
|
|
1962
|
-
if (entry.isIntersecting) {
|
|
1963
|
-
const messageId = entry.target.getAttribute("data-message-id");
|
|
1964
|
-
if (messageId && !observedMessagesRef.current.has(messageId)) {
|
|
1965
|
-
observedMessagesRef.current.add(messageId);
|
|
1966
|
-
onMarkRead?.(messageId);
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
});
|
|
1970
|
-
},
|
|
1971
|
-
{ threshold }
|
|
1972
|
-
);
|
|
1973
|
-
return () => {
|
|
1974
|
-
observerRef.current?.disconnect();
|
|
1975
|
-
};
|
|
1976
|
-
}, [onMarkRead, threshold]);
|
|
1977
|
-
const observeMessage = React5__namespace.useCallback(
|
|
1978
|
-
(element, message) => {
|
|
1979
|
-
if (!element || !observerRef.current) return;
|
|
1980
|
-
if (message.sender.id !== currentUserId && message.status !== "read" && !observedMessagesRef.current.has(message.id)) {
|
|
1981
|
-
element.setAttribute("data-message-id", message.id);
|
|
1982
|
-
observerRef.current.observe(element);
|
|
1983
|
-
}
|
|
1984
|
-
},
|
|
1985
|
-
[currentUserId]
|
|
1986
|
-
);
|
|
1987
|
-
return { observeMessage };
|
|
1988
|
-
}
|
|
1989
2066
|
|
|
1990
2067
|
exports.AttachmentPreview = AttachmentPreview;
|
|
1991
2068
|
exports.ConversationHeader = ConversationHeader;
|
|
@@ -2015,6 +2092,7 @@ exports.isSameSenderGroup = isSameSenderGroup;
|
|
|
2015
2092
|
exports.useMessageScroll = useMessageScroll;
|
|
2016
2093
|
exports.useMessages = useMessages;
|
|
2017
2094
|
exports.useReadReceipts = useReadReceipts;
|
|
2095
|
+
exports.useTypingEmulation = useTypingEmulation;
|
|
2018
2096
|
exports.useTypingIndicator = useTypingIndicator;
|
|
2019
|
-
//# sourceMappingURL=chunk-
|
|
2020
|
-
//# sourceMappingURL=chunk-
|
|
2097
|
+
//# sourceMappingURL=chunk-OFUKTVBN.cjs.map
|
|
2098
|
+
//# sourceMappingURL=chunk-OFUKTVBN.cjs.map
|