@mieweb/ui 0.10.0-dev.8 → 0.10.0-dev.9

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 (38) hide show
  1. package/dist/{chunk-7G3ZIYFY.js → chunk-4A3W4TQF.js} +15 -2
  2. package/dist/chunk-4A3W4TQF.js.map +1 -0
  3. package/dist/{chunk-WNAA6CLE.cjs → chunk-AR7AKDM2.cjs} +2 -2
  4. package/dist/{chunk-WNAA6CLE.cjs.map → chunk-AR7AKDM2.cjs.map} +1 -1
  5. package/dist/{chunk-EZSSESEU.cjs → chunk-ASSDGS4F.cjs} +15 -2
  6. package/dist/chunk-ASSDGS4F.cjs.map +1 -0
  7. package/dist/{chunk-JHULS3EC.js → chunk-AWJBOND5.js} +2 -2
  8. package/dist/{chunk-JHULS3EC.js.map → chunk-AWJBOND5.js.map} +1 -1
  9. package/dist/chunk-BM35CACB.js +148 -0
  10. package/dist/chunk-BM35CACB.js.map +1 -0
  11. package/dist/{chunk-WIAQQNFU.cjs → chunk-FS4VZUFV.cjs} +31 -2
  12. package/dist/chunk-FS4VZUFV.cjs.map +1 -0
  13. package/dist/{chunk-22CYDCXA.js → chunk-HACNIFO3.js} +31 -3
  14. package/dist/chunk-HACNIFO3.js.map +1 -0
  15. package/dist/chunk-VPTASZ2O.cjs +171 -0
  16. package/dist/chunk-VPTASZ2O.cjs.map +1 -0
  17. package/dist/components/SuperChat/index.cjs +261 -112
  18. package/dist/components/SuperChat/index.cjs.map +1 -1
  19. package/dist/components/SuperChat/index.js +255 -106
  20. package/dist/components/SuperChat/index.js.map +1 -1
  21. package/dist/hooks/index.cjs +22 -13
  22. package/dist/hooks/index.d.cts +101 -1
  23. package/dist/hooks/index.d.ts +101 -1
  24. package/dist/hooks/index.js +2 -1
  25. package/dist/index.cjs +193 -70
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +146 -30
  30. package/dist/index.js.map +1 -1
  31. package/dist/styles.css +1 -1
  32. package/dist/tailwind-preset.cjs +4 -4
  33. package/dist/tailwind-preset.js +1 -1
  34. package/package.json +1 -1
  35. package/dist/chunk-22CYDCXA.js.map +0 -1
  36. package/dist/chunk-7G3ZIYFY.js.map +0 -1
  37. package/dist/chunk-EZSSESEU.cjs.map +0 -1
  38. package/dist/chunk-WIAQQNFU.cjs.map +0 -1
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkJFLC7SHM_cjs = require('../../chunk-JFLC7SHM.cjs');
4
- var chunkWIAQQNFU_cjs = require('../../chunk-WIAQQNFU.cjs');
4
+ var chunkFS4VZUFV_cjs = require('../../chunk-FS4VZUFV.cjs');
5
5
  var chunkX4XPNTCZ_cjs = require('../../chunk-X4XPNTCZ.cjs');
6
6
  var chunkSGFYA22I_cjs = require('../../chunk-SGFYA22I.cjs');
7
7
  var chunkJEIW7BSV_cjs = require('../../chunk-JEIW7BSV.cjs');
8
8
  require('../../chunk-VBWRH4UW.cjs');
9
+ var chunkVPTASZ2O_cjs = require('../../chunk-VPTASZ2O.cjs');
9
10
  require('../../chunk-PJ6CC53R.cjs');
10
11
  require('../../chunk-I44YNYI6.cjs');
11
12
  require('../../chunk-Z5S5JEJD.cjs');
@@ -13,11 +14,12 @@ require('../../chunk-FSGEDDF2.cjs');
13
14
  require('../../chunk-AOHJILLU.cjs');
14
15
  require('../../chunk-FHY3K6PL.cjs');
15
16
  require('../../chunk-L7L5S2HO.cjs');
17
+ var chunk6HFFWEM3_cjs = require('../../chunk-6HFFWEM3.cjs');
16
18
  var chunkYVL3XATO_cjs = require('../../chunk-YVL3XATO.cjs');
17
19
  require('../../chunk-NV2CWBI2.cjs');
18
20
  var chunkS5RVSXDV_cjs = require('../../chunk-S5RVSXDV.cjs');
19
21
  require('../../chunk-EUAMEVVI.cjs');
20
- var React2 = require('react');
22
+ var React3 = require('react');
21
23
  var Markdown = require('react-markdown');
22
24
  var remarkGfm = require('remark-gfm');
23
25
  var rehypeSanitize = require('rehype-sanitize');
@@ -46,7 +48,7 @@ function _interopNamespace(e) {
46
48
  return Object.freeze(n);
47
49
  }
48
50
 
49
- var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
51
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
50
52
  var Markdown__default = /*#__PURE__*/_interopDefault(Markdown);
51
53
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
52
54
  var rehypeSanitize__default = /*#__PURE__*/_interopDefault(rehypeSanitize);
@@ -295,7 +297,7 @@ var transformUrl = (url, key, node) => {
295
297
  }
296
298
  return Markdown.defaultUrlTransform(url);
297
299
  };
298
- var MarkdownContent = React2__namespace.memo(function MarkdownContent2({
300
+ var MarkdownContent = React3__namespace.memo(function MarkdownContent2({
299
301
  text,
300
302
  messageId,
301
303
  streaming,
@@ -405,7 +407,7 @@ function ParticipantAvatar({
405
407
  src: participant?.avatar,
406
408
  alt: "",
407
409
  name: participant?.name ?? "?",
408
- fallback: isAgent ? /* @__PURE__ */ jsxRuntime.jsx(chunkWIAQQNFU_cjs.SparklesIcon, { size: "sm" }) : void 0,
410
+ fallback: isAgent ? /* @__PURE__ */ jsxRuntime.jsx(chunkFS4VZUFV_cjs.SparklesIcon, { size: "sm" }) : void 0,
409
411
  style: { backgroundColor },
410
412
  "aria-hidden": "true",
411
413
  className: "shrink-0"
@@ -498,11 +500,11 @@ function useMessageCopy({
498
500
  getText,
499
501
  defaultFormat
500
502
  }) {
501
- const [copied, setCopied] = React2__namespace.useState(false);
502
- const copiedTimer = React2__namespace.useRef(
503
+ const [copied, setCopied] = React3__namespace.useState(false);
504
+ const copiedTimer = React3__namespace.useRef(
503
505
  void 0
504
506
  );
505
- React2__namespace.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
507
+ React3__namespace.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
506
508
  const flash = () => {
507
509
  setCopied(true);
508
510
  window.clearTimeout(copiedTimer.current);
@@ -555,7 +557,7 @@ function FooterActionButton({
555
557
  action,
556
558
  isSelf
557
559
  }) {
558
- const [open, setOpen] = React2__namespace.useState(false);
560
+ const [open, setOpen] = React3__namespace.useState(false);
559
561
  const onClickCapture = action.submenu ? (e) => {
560
562
  if (e.metaKey || e.ctrlKey) {
561
563
  e.preventDefault();
@@ -598,7 +600,7 @@ function FooterActionButton({
598
600
  }
599
601
  );
600
602
  }
601
- var MessageActionsBar = React2__namespace.forwardRef(function MessageActionsBar2({ actions, isSelf }, ref) {
603
+ var MessageActionsBar = React3__namespace.forwardRef(function MessageActionsBar2({ actions, isSelf }, ref) {
602
604
  return /* @__PURE__ */ jsxRuntime.jsx(
603
605
  "div",
604
606
  {
@@ -614,7 +616,7 @@ function MessageOverflowMenu({
614
616
  actions,
615
617
  footerVisible
616
618
  }) {
617
- const [open, setOpen] = React2__namespace.useState(false);
619
+ const [open, setOpen] = React3__namespace.useState(false);
618
620
  const select = (fn) => {
619
621
  setOpen(false);
620
622
  fn();
@@ -667,7 +669,7 @@ function MessageOverflowMenu({
667
669
  }
668
670
  );
669
671
  }
670
- var MessageRow = React2__namespace.memo(function MessageRow2({
672
+ var MessageRow = React3__namespace.memo(function MessageRow2({
671
673
  message,
672
674
  participant,
673
675
  isSelf,
@@ -680,18 +682,18 @@ var MessageRow = React2__namespace.memo(function MessageRow2({
680
682
  }) {
681
683
  const streaming = message.status === "streaming";
682
684
  const hasBody = !!message.text || (message.content?.length ?? 0) > 0;
683
- const [isEditing, setIsEditing] = React2__namespace.useState(false);
684
- const [draft, setDraft] = React2__namespace.useState(message.text ?? "");
685
- const [editMinWidth, setEditMinWidth] = React2__namespace.useState();
686
- const editRef = React2__namespace.useRef(null);
687
- const bubbleRef = React2__namespace.useRef(null);
688
- const autosize = React2__namespace.useCallback(() => {
685
+ const [isEditing, setIsEditing] = React3__namespace.useState(false);
686
+ const [draft, setDraft] = React3__namespace.useState(message.text ?? "");
687
+ const [editMinWidth, setEditMinWidth] = React3__namespace.useState();
688
+ const editRef = React3__namespace.useRef(null);
689
+ const bubbleRef = React3__namespace.useRef(null);
690
+ const autosize = React3__namespace.useCallback(() => {
689
691
  const el = editRef.current;
690
692
  if (!el) return;
691
693
  el.style.height = "auto";
692
694
  el.style.height = `${el.scrollHeight}px`;
693
695
  }, []);
694
- React2__namespace.useEffect(() => {
696
+ React3__namespace.useEffect(() => {
695
697
  if (!isEditing) return;
696
698
  const el = editRef.current;
697
699
  if (!el) return;
@@ -722,9 +724,9 @@ ${block.text}
722
724
  getText: () => bubbleRef.current?.textContent ?? "",
723
725
  defaultFormat: defaultCopyFormat
724
726
  });
725
- const actionsBarRef = React2__namespace.useRef(null);
726
- const [footerVisible, setFooterVisible] = React2__namespace.useState(true);
727
- React2__namespace.useEffect(() => {
727
+ const actionsBarRef = React3__namespace.useRef(null);
728
+ const [footerVisible, setFooterVisible] = React3__namespace.useState(true);
729
+ React3__namespace.useEffect(() => {
728
730
  const el = actionsBarRef.current;
729
731
  if (!el || typeof globalThis.IntersectionObserver === "undefined") return;
730
732
  const observer = new globalThis.IntersectionObserver(([entry]) => {
@@ -936,7 +938,7 @@ ${block.text}
936
938
  isSelf ? "flex-row-reverse" : "flex-row"
937
939
  ),
938
940
  children: /* @__PURE__ */ jsxRuntime.jsx(
939
- chunkWIAQQNFU_cjs.ChatBubble,
941
+ chunkFS4VZUFV_cjs.ChatBubble,
940
942
  {
941
943
  ref: bubbleRef,
942
944
  "data-slot": "superchat-bubble",
@@ -1000,7 +1002,7 @@ ${block.text}
1000
1002
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1001
1003
  message.content?.map((block, i) => {
1002
1004
  if (block.type === "tool_use" && block.toolCall) {
1003
- return /* @__PURE__ */ jsxRuntime.jsx(chunkWIAQQNFU_cjs.MCPToolCallDisplay, { toolCall: block.toolCall }, i);
1005
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkFS4VZUFV_cjs.MCPToolCallDisplay, { toolCall: block.toolCall }, i);
1004
1006
  }
1005
1007
  if ((block.type === "text" || block.type === "thinking") && block.text) {
1006
1008
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1040,7 +1042,7 @@ ${block.text}
1040
1042
  streaming,
1041
1043
  role: participant?.kind === "human" ? "user" : "assistant"
1042
1044
  }) }),
1043
- streaming && !hasBody && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(chunkWIAQQNFU_cjs.AITypingIndicator, {}) })
1045
+ streaming && !hasBody && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(chunkFS4VZUFV_cjs.AITypingIndicator, {}) })
1044
1046
  ] })
1045
1047
  }
1046
1048
  )
@@ -1075,32 +1077,23 @@ function VirtualThread({
1075
1077
  editable,
1076
1078
  onMessageEdited,
1077
1079
  defaultCopyFormat,
1078
- order,
1079
- conversationId,
1080
+ scrollRef,
1081
+ contentRef,
1080
1082
  containerProps
1081
1083
  }) {
1082
- const parentRef = React2__namespace.useRef(null);
1083
1084
  const virtualizer = reactVirtual.useVirtualizer({
1084
1085
  count: items.length,
1085
- getScrollElement: () => parentRef.current,
1086
+ getScrollElement: () => scrollRef.current,
1086
1087
  // Rough first guess; real heights are measured via measureElement.
1087
1088
  estimateSize: () => 88,
1088
1089
  overscan: 10,
1089
1090
  getItemKey: (index) => items[index]?.id ?? index
1090
1091
  });
1091
- const count = items.length;
1092
- React2__namespace.useEffect(() => {
1093
- if (count === 0) return;
1094
- if (order === "desc") {
1095
- virtualizer.scrollToIndex(0, { align: "start" });
1096
- } else {
1097
- virtualizer.scrollToIndex(count - 1, { align: "end" });
1098
- }
1099
- }, [count, conversationId, order]);
1100
1092
  const virtualItems = virtualizer.getVirtualItems();
1101
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ...containerProps, ref: parentRef, children: /* @__PURE__ */ jsxRuntime.jsx(
1093
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...containerProps, ref: scrollRef, children: /* @__PURE__ */ jsxRuntime.jsx(
1102
1094
  "div",
1103
1095
  {
1096
+ ref: contentRef,
1104
1097
  style: {
1105
1098
  height: virtualizer.getTotalSize(),
1106
1099
  position: "relative",
@@ -1161,38 +1154,180 @@ function SuperChat({
1161
1154
  onReferenceClick,
1162
1155
  onBack
1163
1156
  }) {
1164
- const headingId = React2__namespace.useId();
1165
- React2__namespace.useEffect(() => {
1157
+ const headingId = React3__namespace.useId();
1158
+ React3__namespace.useEffect(() => {
1166
1159
  chunkX4XPNTCZ_cjs.notifyComposerMigrationOnce("SuperChat");
1167
1160
  }, []);
1168
- const renderText = React2__namespace.useMemo(
1161
+ const renderText = React3__namespace.useMemo(
1169
1162
  () => renderTextContent ?? createMarkdownRenderer({
1170
1163
  plugins: renderPlugins,
1171
1164
  trusted: trustedContent
1172
1165
  }),
1173
1166
  [renderTextContent, renderPlugins, trustedContent]
1174
1167
  );
1175
- const threadRef = React2__namespace.useRef(null);
1176
- React2__namespace.useEffect(() => {
1177
- if (virtualized) return;
1178
- const el = threadRef.current;
1179
- if (!el) return;
1180
- el.scrollTop = order === "desc" ? 0 : el.scrollHeight;
1181
- }, [conversation.thread.length, conversation.id, order, virtualized]);
1182
- const participantById = React2__namespace.useMemo(() => {
1168
+ const prefersReducedMotion = chunk6HFFWEM3_cjs.usePrefersReducedMotion();
1169
+ const {
1170
+ containerRef: threadRef,
1171
+ contentRef: threadContentRef,
1172
+ isAtBottom,
1173
+ scrollToBottom,
1174
+ anchorToTurnStart,
1175
+ followIfPinned,
1176
+ stopFollowing
1177
+ } = chunkVPTASZ2O_cjs.useStickToBottom({ disabled: order === "desc" });
1178
+ const [hasNewBelow, setHasNewBelow] = React3__namespace.useState(false);
1179
+ const [turnStartId, setTurnStartId] = React3__namespace.useState(null);
1180
+ const [turnMinHeight, setTurnMinHeight] = React3__namespace.useState();
1181
+ const anchoredTurnRef = React3__namespace.useRef(null);
1182
+ React3__namespace.useEffect(() => {
1183
+ setTurnStartId(null);
1184
+ anchoredTurnRef.current = null;
1185
+ if (order === "desc") {
1186
+ const el = threadRef.current;
1187
+ if (el) el.scrollTop = 0;
1188
+ } else {
1189
+ scrollToBottom("auto");
1190
+ }
1191
+ setHasNewBelow(false);
1192
+ }, [conversation.id, order]);
1193
+ const threadLength = conversation.thread.length;
1194
+ const prevThreadLengthRef = React3__namespace.useRef(threadLength);
1195
+ const prevMessageIdsRef = React3__namespace.useRef(
1196
+ new Set(conversation.thread.map((message) => message.id))
1197
+ );
1198
+ const policyConversationRef = React3__namespace.useRef(conversation.id);
1199
+ const policyBaselinedRef = React3__namespace.useRef(false);
1200
+ React3__namespace.useEffect(() => {
1201
+ if (!policyBaselinedRef.current || policyConversationRef.current !== conversation.id) {
1202
+ policyBaselinedRef.current = true;
1203
+ policyConversationRef.current = conversation.id;
1204
+ prevThreadLengthRef.current = threadLength;
1205
+ prevMessageIdsRef.current = new Set(
1206
+ conversation.thread.map((message) => message.id)
1207
+ );
1208
+ if (order !== "desc" && [...conversation.thread].sort(byTime).at(-1)?.status === "streaming") {
1209
+ stopFollowing();
1210
+ }
1211
+ return;
1212
+ }
1213
+ if (threadLength === prevThreadLengthRef.current) return;
1214
+ const grew = threadLength > prevThreadLengthRef.current;
1215
+ prevThreadLengthRef.current = threadLength;
1216
+ if (order === "desc") {
1217
+ const el = threadRef.current;
1218
+ if (el) el.scrollTop = 0;
1219
+ return;
1220
+ }
1221
+ const prevIds = prevMessageIdsRef.current;
1222
+ let turnStart;
1223
+ if (grew && currentParticipantId) {
1224
+ for (const message of [...conversation.thread].sort(byTime)) {
1225
+ if (!prevIds.has(message.id) && message.participantId === currentParticipantId) {
1226
+ turnStart = message.id;
1227
+ }
1228
+ }
1229
+ }
1230
+ if (turnStart) {
1231
+ if (virtualized) {
1232
+ scrollToBottom("auto");
1233
+ } else {
1234
+ setTurnStartId(turnStart);
1235
+ }
1236
+ } else if (grew) {
1237
+ const newest = [...conversation.thread].sort(byTime).at(-1);
1238
+ if (newest?.status === "streaming") {
1239
+ followIfPinned("auto");
1240
+ stopFollowing();
1241
+ } else if (!followIfPinned("auto")) {
1242
+ setHasNewBelow(true);
1243
+ }
1244
+ } else {
1245
+ followIfPinned("auto");
1246
+ }
1247
+ }, [threadLength, order, isAtBottom, conversation.id]);
1248
+ React3__namespace.useLayoutEffect(() => {
1249
+ if (!turnStartId || anchoredTurnRef.current === turnStartId) return;
1250
+ const container = threadRef.current;
1251
+ if (!container) return;
1252
+ const reserve = Math.max(0, container.clientHeight - 32);
1253
+ if (turnMinHeight !== reserve) {
1254
+ setTurnMinHeight(reserve);
1255
+ return;
1256
+ }
1257
+ const target = container.querySelector(
1258
+ '[data-slot="superchat-turn"]'
1259
+ );
1260
+ if (target) {
1261
+ anchorToTurnStart(target, prefersReducedMotion ? "auto" : "smooth");
1262
+ anchoredTurnRef.current = turnStartId;
1263
+ }
1264
+ }, [
1265
+ turnStartId,
1266
+ turnMinHeight,
1267
+ anchorToTurnStart,
1268
+ prefersReducedMotion,
1269
+ threadRef
1270
+ ]);
1271
+ React3__namespace.useEffect(() => {
1272
+ prevMessageIdsRef.current = new Set(
1273
+ conversation.thread.map((message) => message.id)
1274
+ );
1275
+ });
1276
+ React3__namespace.useEffect(() => {
1277
+ if (isAtBottom) setHasNewBelow(false);
1278
+ }, [isAtBottom]);
1279
+ const newestMessage = React3__namespace.useMemo(
1280
+ () => [...conversation.thread].sort(byTime).at(-1),
1281
+ [conversation]
1282
+ );
1283
+ const raiseNewBelow = React3__namespace.useCallback(() => {
1284
+ if (order !== "desc") setHasNewBelow(true);
1285
+ }, [order]);
1286
+ const resumeFollowing = React3__namespace.useCallback(() => {
1287
+ if (order !== "desc") scrollToBottom("auto");
1288
+ }, [order, scrollToBottom]);
1289
+ chunkVPTASZ2O_cjs.useStreamEndedBelowFold(
1290
+ newestMessage,
1291
+ isAtBottom,
1292
+ raiseNewBelow,
1293
+ resumeFollowing
1294
+ );
1295
+ const handleJumpToBottom = React3__namespace.useCallback(() => {
1296
+ scrollToBottom(prefersReducedMotion ? "auto" : "smooth");
1297
+ }, [scrollToBottom, prefersReducedMotion]);
1298
+ const participantById = React3__namespace.useMemo(() => {
1183
1299
  const map = /* @__PURE__ */ new Map();
1184
1300
  conversation.participants.forEach((p) => map.set(p.id, p));
1185
1301
  return map;
1186
1302
  }, [conversation]);
1187
- const orderedThread = React2__namespace.useMemo(() => {
1303
+ const orderedThread = React3__namespace.useMemo(() => {
1188
1304
  const sorted = [...conversation.thread].sort(byTime);
1189
1305
  return order === "desc" ? sorted.reverse() : sorted;
1190
1306
  }, [conversation, order]);
1191
- const onMessageEditedRef = React2__namespace.useRef(onMessageEdited);
1307
+ const turnIndex = React3__namespace.useMemo(
1308
+ () => turnStartId && order !== "desc" ? orderedThread.findIndex((message) => message.id === turnStartId) : -1,
1309
+ [orderedThread, turnStartId, order]
1310
+ );
1311
+ const renderMessageRow = (m) => /* @__PURE__ */ jsxRuntime.jsx(
1312
+ MessageRow,
1313
+ {
1314
+ message: m,
1315
+ participant: participantById.get(m.participantId),
1316
+ isSelf: !!currentParticipantId && m.participantId === currentParticipantId,
1317
+ renderText,
1318
+ linkBuilder,
1319
+ onReferenceClick,
1320
+ editable,
1321
+ onMessageEdited: handleMessageEdited,
1322
+ defaultCopyFormat
1323
+ },
1324
+ m.id
1325
+ );
1326
+ const onMessageEditedRef = React3__namespace.useRef(onMessageEdited);
1192
1327
  onMessageEditedRef.current = onMessageEdited;
1193
- const conversationRef = React2__namespace.useRef(conversation);
1328
+ const conversationRef = React3__namespace.useRef(conversation);
1194
1329
  conversationRef.current = conversation;
1195
- const handleMessageEdited = React2__namespace.useCallback(
1330
+ const handleMessageEdited = React3__namespace.useCallback(
1196
1331
  (messageId, text) => {
1197
1332
  onMessageEditedRef.current?.(messageId, text, {
1198
1333
  conversation: conversationRef.current
@@ -1201,7 +1336,7 @@ function SuperChat({
1201
1336
  []
1202
1337
  );
1203
1338
  const editable = !readOnly && !!onMessageEdited;
1204
- const mentionOptions = React2__namespace.useMemo(
1339
+ const mentionOptions = React3__namespace.useMemo(
1205
1340
  () => conversation.participants.filter((p) => p.kind !== "system").map((p) => ({
1206
1341
  id: p.id,
1207
1342
  label: p.name,
@@ -1211,17 +1346,17 @@ function SuperChat({
1211
1346
  })),
1212
1347
  [conversation.participants]
1213
1348
  );
1214
- const composerAccept = React2__namespace.useMemo(
1349
+ const composerAccept = React3__namespace.useMemo(
1215
1350
  () => acceptTokensFor(acceptedFileTypes),
1216
1351
  [acceptedFileTypes]
1217
1352
  );
1218
- const [draft, setDraft] = React2__namespace.useState("");
1219
- const draftEpochRef = React2__namespace.useRef(0);
1220
- const handleDraftChange = React2__namespace.useCallback((value) => {
1353
+ const [draft, setDraft] = React3__namespace.useState("");
1354
+ const draftEpochRef = React3__namespace.useRef(0);
1355
+ const handleDraftChange = React3__namespace.useCallback((value) => {
1221
1356
  draftEpochRef.current += 1;
1222
1357
  setDraft(value);
1223
1358
  }, []);
1224
- const handleComposerSend = React2__namespace.useCallback(
1359
+ const handleComposerSend = React3__namespace.useCallback(
1225
1360
  async (message) => {
1226
1361
  const epoch = draftEpochRef.current;
1227
1362
  try {
@@ -1311,61 +1446,75 @@ function SuperChat({
1311
1446
  onClick: () => onConversationClosed(conversation),
1312
1447
  "aria-label": "Close conversation",
1313
1448
  className: "rounded-md p-1 text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800",
1314
- children: /* @__PURE__ */ jsxRuntime.jsx(chunkWIAQQNFU_cjs.CloseIcon, {})
1449
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkFS4VZUFV_cjs.CloseIcon, {})
1315
1450
  }
1316
1451
  )
1317
1452
  ]
1318
1453
  }
1319
1454
  ),
1320
- virtualized ? /* @__PURE__ */ jsxRuntime.jsx(
1321
- VirtualThread,
1322
- {
1323
- items: orderedThread,
1324
- participantById,
1325
- currentParticipantId,
1326
- renderText,
1327
- linkBuilder,
1328
- onReferenceClick,
1329
- editable,
1330
- onMessageEdited: handleMessageEdited,
1331
- defaultCopyFormat,
1332
- order,
1333
- conversationId: conversation.id,
1334
- containerProps: {
1335
- "data-slot": "superchat-thread",
1336
- role: "log",
1337
- "aria-label": "Messages",
1338
- "aria-live": "polite",
1339
- // Focusable so keyboard-only users can scroll the message history.
1340
- tabIndex: 0,
1341
- className: "flex-1 overflow-y-auto p-4"
1342
- }
1343
- }
1344
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1455
+ /* @__PURE__ */ jsxRuntime.jsxs(
1345
1456
  "div",
1346
1457
  {
1347
- "data-slot": "superchat-thread",
1348
- ref: threadRef,
1349
- role: "log",
1350
- "aria-label": "Messages",
1351
- "aria-live": "polite",
1352
- tabIndex: 0,
1353
- className: "flex-1 space-y-4 overflow-y-auto p-4",
1354
- children: orderedThread.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
1355
- MessageRow,
1356
- {
1357
- message: m,
1358
- participant: participantById.get(m.participantId),
1359
- isSelf: !!currentParticipantId && m.participantId === currentParticipantId,
1360
- renderText,
1361
- linkBuilder,
1362
- onReferenceClick,
1363
- editable,
1364
- onMessageEdited: handleMessageEdited,
1365
- defaultCopyFormat
1366
- },
1367
- m.id
1368
- ))
1458
+ "data-slot": "superchat-thread-viewport",
1459
+ className: "relative flex min-h-0 flex-1 flex-col",
1460
+ children: [
1461
+ virtualized ? /* @__PURE__ */ jsxRuntime.jsx(
1462
+ VirtualThread,
1463
+ {
1464
+ items: orderedThread,
1465
+ participantById,
1466
+ currentParticipantId,
1467
+ renderText,
1468
+ linkBuilder,
1469
+ onReferenceClick,
1470
+ editable,
1471
+ onMessageEdited: handleMessageEdited,
1472
+ defaultCopyFormat,
1473
+ scrollRef: threadRef,
1474
+ contentRef: threadContentRef,
1475
+ containerProps: {
1476
+ "data-slot": "superchat-thread",
1477
+ role: "log",
1478
+ "aria-label": "Messages",
1479
+ "aria-live": "polite",
1480
+ // Focusable so keyboard-only users can scroll the message history.
1481
+ tabIndex: 0,
1482
+ className: "flex-1 overflow-y-auto p-4"
1483
+ }
1484
+ }
1485
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1486
+ "div",
1487
+ {
1488
+ "data-slot": "superchat-thread",
1489
+ ref: threadRef,
1490
+ role: "log",
1491
+ "aria-label": "Messages",
1492
+ "aria-live": "polite",
1493
+ tabIndex: 0,
1494
+ className: "flex-1 overflow-y-auto p-4",
1495
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: threadContentRef, className: "space-y-4", children: [
1496
+ (turnIndex === -1 ? orderedThread : orderedThread.slice(0, turnIndex)).map(renderMessageRow),
1497
+ turnIndex !== -1 && /* @__PURE__ */ jsxRuntime.jsx(
1498
+ "div",
1499
+ {
1500
+ "data-slot": "superchat-turn",
1501
+ className: "space-y-4",
1502
+ style: { minHeight: turnMinHeight },
1503
+ children: orderedThread.slice(turnIndex).map(renderMessageRow)
1504
+ }
1505
+ )
1506
+ ] })
1507
+ }
1508
+ ),
1509
+ order !== "desc" && !isAtBottom && /* @__PURE__ */ jsxRuntime.jsx(
1510
+ chunkFS4VZUFV_cjs.JumpToBottomButton,
1511
+ {
1512
+ dataSlot: "superchat-jump-to-bottom",
1513
+ hasNewMessages: hasNewBelow,
1514
+ onClick: handleJumpToBottom
1515
+ }
1516
+ )
1517
+ ]
1369
1518
  }
1370
1519
  ),
1371
1520
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1397,12 +1546,12 @@ function SuperChatConversations({
1397
1546
  onConversationOpened,
1398
1547
  onNewConversation
1399
1548
  }) {
1400
- const [internalActive, setInternalActive] = React2__namespace.useState(
1549
+ const [internalActive, setInternalActive] = React3__namespace.useState(
1401
1550
  defaultActiveConversationId ?? conversations[0]?.id
1402
1551
  );
1403
1552
  const requestedId = activeConversationId ?? internalActive;
1404
1553
  const activeId = conversations.some((c) => c.id === requestedId) ? requestedId : conversations[0]?.id;
1405
- const sortedConversations = React2__namespace.useMemo(
1554
+ const sortedConversations = React3__namespace.useMemo(
1406
1555
  () => [...conversations].sort((a, b) => lastActivityOf(b) - lastActivityOf(a)),
1407
1556
  [conversations]
1408
1557
  );
@@ -1491,13 +1640,13 @@ function SuperChatInbox({
1491
1640
  onNewConversation,
1492
1641
  onReferenceClick
1493
1642
  }) {
1494
- const [internalActive, setInternalActive] = React2__namespace.useState(
1643
+ const [internalActive, setInternalActive] = React3__namespace.useState(
1495
1644
  defaultActiveConversationId ?? conversations[0]?.id
1496
1645
  );
1497
1646
  const requestedId = activeConversationId ?? internalActive;
1498
1647
  const active = conversations.find((c) => c.id === requestedId) ?? conversations[0];
1499
1648
  const activeId = active?.id;
1500
- const [mobileView, setMobileView] = React2__namespace.useState("list");
1649
+ const [mobileView, setMobileView] = React3__namespace.useState("list");
1501
1650
  const handleOpen = (c) => {
1502
1651
  if (activeConversationId === void 0) setInternalActive(c.id);
1503
1652
  setMobileView("chat");