@mieweb/ui 0.9.0 → 0.10.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.
Files changed (121) hide show
  1. package/MIGRATION.md +112 -0
  2. package/dist/{Animated-Cs-naa2g.d.cts → Animated-XmH6k8pZ.d.cts} +16 -3
  3. package/dist/{Animated-Cs-naa2g.d.ts → Animated-XmH6k8pZ.d.ts} +16 -3
  4. package/dist/{chunk-XUVEF2RQ.js → chunk-24SEAAOH.js} +2 -2
  5. package/dist/{chunk-XUVEF2RQ.js.map → chunk-24SEAAOH.js.map} +1 -1
  6. package/dist/{chunk-FUFBRKOG.cjs → chunk-2WBPNXO2.cjs} +21 -21
  7. package/dist/{chunk-FUFBRKOG.cjs.map → chunk-2WBPNXO2.cjs.map} +1 -1
  8. package/dist/{chunk-IUDY6S7I.cjs → chunk-37UZHCLM.cjs} +35 -14
  9. package/dist/chunk-37UZHCLM.cjs.map +1 -0
  10. package/dist/{chunk-L52N6BEN.cjs → chunk-AUOTJQGO.cjs} +7 -7
  11. package/dist/{chunk-L52N6BEN.cjs.map → chunk-AUOTJQGO.cjs.map} +1 -1
  12. package/dist/{chunk-6XDPJWSC.cjs → chunk-E7G22IQM.cjs} +32 -28
  13. package/dist/chunk-E7G22IQM.cjs.map +1 -0
  14. package/dist/chunk-IIFQ6BSJ.js +1888 -0
  15. package/dist/chunk-IIFQ6BSJ.js.map +1 -0
  16. package/dist/{chunk-ONNY7UO4.js → chunk-JDJQTKTX.js} +3 -3
  17. package/dist/{chunk-ONNY7UO4.js.map → chunk-JDJQTKTX.js.map} +1 -1
  18. package/dist/{chunk-BJKAVWED.js → chunk-MBWF36DJ.js} +35 -14
  19. package/dist/chunk-MBWF36DJ.js.map +1 -0
  20. package/dist/chunk-NV2CWBI2.cjs +290 -0
  21. package/dist/chunk-NV2CWBI2.cjs.map +1 -0
  22. package/dist/{chunk-FQBTGS3E.cjs → chunk-OFUKTVBN.cjs} +363 -285
  23. package/dist/chunk-OFUKTVBN.cjs.map +1 -0
  24. package/dist/{chunk-7KN6J7XV.cjs → chunk-OMAACCFW.cjs} +7 -7
  25. package/dist/{chunk-7KN6J7XV.cjs.map → chunk-OMAACCFW.cjs.map} +1 -1
  26. package/dist/chunk-OYQ7GYAA.cjs +1921 -0
  27. package/dist/chunk-OYQ7GYAA.cjs.map +1 -0
  28. package/dist/{chunk-YJP6DUFO.cjs → chunk-PKD3JLS2.cjs} +6 -6
  29. package/dist/{chunk-YJP6DUFO.cjs.map → chunk-PKD3JLS2.cjs.map} +1 -1
  30. package/dist/{chunk-CXDMZT45.cjs → chunk-PY7XAG4D.cjs} +27 -4
  31. package/dist/chunk-PY7XAG4D.cjs.map +1 -0
  32. package/dist/{chunk-5H7SAEQO.js → chunk-QKFJDQEK.js} +3 -3
  33. package/dist/{chunk-5H7SAEQO.js.map → chunk-QKFJDQEK.js.map} +1 -1
  34. package/dist/{chunk-XJTFZLWH.cjs → chunk-QO6PRHDX.cjs} +2 -2
  35. package/dist/{chunk-XJTFZLWH.cjs.map → chunk-QO6PRHDX.cjs.map} +1 -1
  36. package/dist/{chunk-OHDIJOGG.js → chunk-RD3JDFYJ.js} +3 -3
  37. package/dist/{chunk-OHDIJOGG.js.map → chunk-RD3JDFYJ.js.map} +1 -1
  38. package/dist/{chunk-4SM3I7WE.cjs → chunk-RXPEZXAB.cjs} +67 -38
  39. package/dist/chunk-RXPEZXAB.cjs.map +1 -0
  40. package/dist/{chunk-VTR2KGLY.cjs → chunk-S3BCHPXT.cjs} +9 -9
  41. package/dist/{chunk-VTR2KGLY.cjs.map → chunk-S3BCHPXT.cjs.map} +1 -1
  42. package/dist/{chunk-KU3XRHWA.js → chunk-TZX76ZNZ.js} +67 -38
  43. package/dist/chunk-TZX76ZNZ.js.map +1 -0
  44. package/dist/{chunk-MXQ7J4BB.js → chunk-VSVGMMNO.js} +361 -284
  45. package/dist/chunk-VSVGMMNO.js.map +1 -0
  46. package/dist/{chunk-Q7G56ZIO.js → chunk-WUBMDOTG.js} +3 -3
  47. package/dist/{chunk-Q7G56ZIO.js.map → chunk-WUBMDOTG.js.map} +1 -1
  48. package/dist/{chunk-DGRXAIWK.js → chunk-X5YM3KXY.js} +27 -4
  49. package/dist/chunk-X5YM3KXY.js.map +1 -0
  50. package/dist/chunk-XCP454Q6.js +263 -0
  51. package/dist/chunk-XCP454Q6.js.map +1 -0
  52. package/dist/{chunk-I3DQXUSC.js → chunk-Y6DFMDMH.js} +3 -3
  53. package/dist/{chunk-I3DQXUSC.js.map → chunk-Y6DFMDMH.js.map} +1 -1
  54. package/dist/{chunk-ODYQYLO2.js → chunk-YSEMAI4I.js} +8 -4
  55. package/dist/chunk-YSEMAI4I.js.map +1 -0
  56. package/dist/components/AlertDialog/index.cjs +4 -4
  57. package/dist/components/AlertDialog/index.js +3 -3
  58. package/dist/components/Collapsible/index.cjs +6 -4
  59. package/dist/components/Collapsible/index.js +3 -1
  60. package/dist/components/Dropdown/index.cjs +9 -8
  61. package/dist/components/Dropdown/index.js +2 -1
  62. package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
  63. package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
  64. package/dist/components/MediaEditor/index.cjs +8 -8
  65. package/dist/components/MediaEditor/index.js +3 -3
  66. package/dist/components/Modal/index.cjs +10 -10
  67. package/dist/components/Modal/index.js +2 -2
  68. package/dist/components/RichTextEditor/index.cjs +6 -5
  69. package/dist/components/RichTextEditor/index.js +3 -2
  70. package/dist/components/SuperChat/index.cjs +40 -17
  71. package/dist/components/SuperChat/index.cjs.map +1 -1
  72. package/dist/components/SuperChat/index.d.cts +20 -7
  73. package/dist/components/SuperChat/index.d.ts +20 -7
  74. package/dist/components/SuperChat/index.js +35 -12
  75. package/dist/components/SuperChat/index.js.map +1 -1
  76. package/dist/components/SuperChat/plugins/index.cjs +10 -3
  77. package/dist/components/SuperChat/plugins/index.cjs.map +1 -1
  78. package/dist/components/SuperChat/plugins/index.d.cts +3 -3
  79. package/dist/components/SuperChat/plugins/index.d.ts +3 -3
  80. package/dist/components/SuperChat/plugins/index.js +9 -2
  81. package/dist/components/SuperChat/plugins/index.js.map +1 -1
  82. package/dist/esheet.cjs +6 -6
  83. package/dist/esheet.js +3 -3
  84. package/dist/hooks/index.cjs +13 -13
  85. package/dist/hooks/index.js +1 -1
  86. package/dist/index.cjs +720 -1671
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +347 -347
  89. package/dist/index.d.ts +347 -347
  90. package/dist/index.js +459 -1405
  91. package/dist/index.js.map +1 -1
  92. package/dist/motion.cjs +7 -7
  93. package/dist/motion.d.cts +1 -1
  94. package/dist/motion.d.ts +1 -1
  95. package/dist/motion.js +2 -2
  96. package/dist/styles.css +1 -1
  97. package/dist/tailwind-preset.cjs +4 -4
  98. package/dist/tailwind-preset.js +1 -1
  99. package/dist/{types-DZDroUW8.d.cts → types-B97JNRNQ.d.cts} +1 -1
  100. package/dist/{types-B2RLmdVd.d.ts → types-CnPEwzlp.d.cts} +6 -2
  101. package/dist/{types-B2RLmdVd.d.cts → types-CnPEwzlp.d.ts} +6 -2
  102. package/dist/{types-9vK_YdEb.d.ts → types-gZXrfLj6.d.ts} +1 -1
  103. package/package.json +2 -1
  104. package/dist/chunk-4SM3I7WE.cjs.map +0 -1
  105. package/dist/chunk-5BVFVXHN.cjs +0 -1244
  106. package/dist/chunk-5BVFVXHN.cjs.map +0 -1
  107. package/dist/chunk-6XDPJWSC.cjs.map +0 -1
  108. package/dist/chunk-BJKAVWED.js.map +0 -1
  109. package/dist/chunk-BN75TLUN.cjs +0 -163
  110. package/dist/chunk-BN75TLUN.cjs.map +0 -1
  111. package/dist/chunk-CXDMZT45.cjs.map +0 -1
  112. package/dist/chunk-DGRXAIWK.js.map +0 -1
  113. package/dist/chunk-FQBTGS3E.cjs.map +0 -1
  114. package/dist/chunk-IUDY6S7I.cjs.map +0 -1
  115. package/dist/chunk-KU3XRHWA.js.map +0 -1
  116. package/dist/chunk-MXQ7J4BB.js.map +0 -1
  117. package/dist/chunk-O6GJ4IYS.js +0 -1210
  118. package/dist/chunk-O6GJ4IYS.js.map +0 -1
  119. package/dist/chunk-ODYQYLO2.js.map +0 -1
  120. package/dist/chunk-WYMO3IIK.js +0 -136
  121. package/dist/chunk-WYMO3IIK.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunk5BVFVXHN_cjs = require('./chunk-5BVFVXHN.cjs');
3
+ var chunkOYQ7GYAA_cjs = require('./chunk-OYQ7GYAA.cjs');
4
4
  var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
5
- var React5 = require('react');
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 React5__namespace = /*#__PURE__*/_interopNamespace(React5);
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 = React5__namespace.forwardRef(
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 = React5__namespace.forwardRef(
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 = React5__namespace.useRef(null);
904
- const bottomRef = React5__namespace.useRef(null);
905
- const [isUserScrolled, setIsUserScrolled] = React5__namespace.useState(false);
906
- const prevMessageCountRef = React5__namespace.useRef(messages.length);
907
- React5__namespace.useImperativeHandle(ref, () => scrollContainerRef.current);
908
- const handleScroll = React5__namespace.useCallback(() => {
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
- React5__namespace.useEffect(() => {
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
- React5__namespace.useEffect(() => {
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(React5__namespace.Fragment, { children: [
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 = React5__namespace.forwardRef(
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 = React5__namespace.forwardRef(({ className, conversation, isSelected, onSelect, ...props }, ref) => {
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
- React5__namespace.useEffect(() => {
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 = React5__namespace.forwardRef(
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] = React5__namespace.useState(null);
1582
- const [replyTo, setReplyTo] = React5__namespace.useState(null);
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
- await eventHandlers.onSendMessage?.(messageWithReply);
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
- chunk5BVFVXHN_cjs.DragDropZone,
1923
+ chunkOYQ7GYAA_cjs.DragDropZone,
1621
1924
  {
1622
- onFilesDropped: () => {
1623
- onError?.("Drop files on the composer to attach them");
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
- chunk5BVFVXHN_cjs.MessageComposer,
1955
+ "div",
1651
1956
  {
1652
- onSend: handleSendMessage,
1653
- onTypingStart: eventHandlers.onTypingStart,
1654
- onTypingStop: eventHandlers.onTypingStop,
1655
- placeholder,
1656
- maxLength: maxMessageLength,
1657
- showCharacterCount,
1658
- isSending,
1659
- showAttachmentPicker,
1660
- showCameraButton,
1661
- acceptedFileTypes,
1662
- maxFileSize,
1663
- maxAttachments,
1664
- onError,
1665
- replyTo,
1666
- onCancelReply: () => setReplyTo(null)
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-FQBTGS3E.cjs.map
2020
- //# sourceMappingURL=chunk-FQBTGS3E.cjs.map
2097
+ //# sourceMappingURL=chunk-OFUKTVBN.cjs.map
2098
+ //# sourceMappingURL=chunk-OFUKTVBN.cjs.map