@assistant-ui/react-native 0.1.41 → 0.1.43

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 (170) hide show
  1. package/dist/index.d.ts +5 -4
  2. package/dist/index.js +4 -3
  3. package/dist/primitives/actionBar/ActionBarCopy.d.ts +3 -3
  4. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  5. package/dist/primitives/actionBar/ActionBarCopy.js +23 -19
  6. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  7. package/dist/primitives/actionBar/ActionBarEdit.d.ts +7 -5
  8. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  9. package/dist/primitives/actionBar/ActionBarEdit.js +21 -11
  10. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  11. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +3 -3
  12. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  13. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +26 -16
  14. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  15. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +3 -3
  16. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  17. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +26 -16
  18. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  19. package/dist/primitives/actionBar/ActionBarReload.d.ts +7 -5
  20. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  21. package/dist/primitives/actionBar/ActionBarReload.js +21 -11
  22. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  23. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +14 -0
  24. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -0
  25. package/dist/primitives/actionBar/ActionBarSpeak.js +61 -0
  26. package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -0
  27. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +14 -0
  28. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -0
  29. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +61 -0
  30. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -0
  31. package/dist/primitives/actionBar.d.ts +4 -2
  32. package/dist/primitives/actionBar.js +6 -2
  33. package/dist/primitives/actionBar.js.map +1 -1
  34. package/dist/primitives/attachment/AttachmentName.d.ts +2 -3
  35. package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
  36. package/dist/primitives/attachment/AttachmentRemove.d.ts +2 -3
  37. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  38. package/dist/primitives/attachment/AttachmentRoot.d.ts +2 -3
  39. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  40. package/dist/primitives/attachment/AttachmentThumb.d.ts +2 -3
  41. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  42. package/dist/primitives/branchPicker/BranchPickerCount.d.ts +2 -3
  43. package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
  44. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +7 -5
  45. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  46. package/dist/primitives/branchPicker/BranchPickerNext.js +21 -11
  47. package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
  48. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +2 -3
  49. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
  50. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +7 -5
  51. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  52. package/dist/primitives/branchPicker/BranchPickerPrevious.js +21 -11
  53. package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
  54. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +2 -3
  55. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  56. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +2 -3
  57. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  58. package/dist/primitives/composer/ComposerAddAttachment.d.ts +4 -7
  59. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  60. package/dist/primitives/composer/ComposerAddAttachment.js +2 -4
  61. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  62. package/dist/primitives/composer/ComposerAttachments.d.ts +4 -5
  63. package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  64. package/dist/primitives/composer/ComposerCancel.d.ts +2 -3
  65. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  66. package/dist/primitives/composer/ComposerInput.d.ts +2 -3
  67. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  68. package/dist/primitives/composer/ComposerQuote.d.ts +2 -3
  69. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  70. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts +2 -3
  71. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts.map +1 -1
  72. package/dist/primitives/composer/ComposerQuoteText.d.ts +2 -3
  73. package/dist/primitives/composer/ComposerQuoteText.d.ts.map +1 -1
  74. package/dist/primitives/composer/ComposerRoot.d.ts +2 -3
  75. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  76. package/dist/primitives/composer/ComposerSend.d.ts +2 -3
  77. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  78. package/dist/primitives/error/ErrorMessage.d.ts +2 -3
  79. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  80. package/dist/primitives/error/ErrorRoot.d.ts +2 -3
  81. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  82. package/dist/primitives/message/MessageAttachments.d.ts +4 -5
  83. package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
  84. package/dist/primitives/message/MessageContent.d.ts +2 -3
  85. package/dist/primitives/message/MessageContent.d.ts.map +1 -1
  86. package/dist/primitives/message/MessageIf.d.ts +2 -3
  87. package/dist/primitives/message/MessageIf.d.ts.map +1 -1
  88. package/dist/primitives/message/MessageParts.d.ts +3 -3
  89. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  90. package/dist/primitives/message/MessageRoot.d.ts +2 -3
  91. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  92. package/dist/primitives/messagePart/MessagePartImage.d.ts +11 -0
  93. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -0
  94. package/dist/primitives/messagePart/MessagePartImage.js +39 -0
  95. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -0
  96. package/dist/primitives/messagePart/MessagePartInProgress.d.ts +2 -0
  97. package/dist/primitives/messagePart/MessagePartInProgress.js +2 -0
  98. package/dist/primitives/messagePart/MessagePartText.d.ts +11 -0
  99. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -0
  100. package/dist/primitives/messagePart/MessagePartText.js +32 -0
  101. package/dist/primitives/messagePart/MessagePartText.js.map +1 -0
  102. package/dist/primitives/messagePart.d.ts +10 -0
  103. package/dist/primitives/messagePart.d.ts.map +1 -0
  104. package/dist/primitives/messagePart.js +16 -0
  105. package/dist/primitives/messagePart.js.map +1 -0
  106. package/dist/primitives/queueItem/QueueItemRemove.d.ts +2 -3
  107. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  108. package/dist/primitives/queueItem/QueueItemSteer.d.ts +2 -3
  109. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  110. package/dist/primitives/queueItem/QueueItemText.d.ts +2 -3
  111. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  112. package/dist/primitives/suggestion/SuggestionDescription.d.ts +2 -3
  113. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  114. package/dist/primitives/suggestion/SuggestionTitle.d.ts +2 -3
  115. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  116. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +2 -3
  117. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  118. package/dist/primitives/thread/ThreadEmpty.d.ts +2 -3
  119. package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
  120. package/dist/primitives/thread/ThreadIf.d.ts +2 -3
  121. package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
  122. package/dist/primitives/thread/ThreadMessages.d.ts +9 -5
  123. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  124. package/dist/primitives/thread/ThreadMessages.js +244 -171
  125. package/dist/primitives/thread/ThreadMessages.js.map +1 -1
  126. package/dist/primitives/thread/ThreadRoot.d.ts +2 -3
  127. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  128. package/dist/primitives/thread/ThreadSuggestion.d.ts +2 -3
  129. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  130. package/dist/primitives/threadList/ThreadListItems.d.ts +2 -3
  131. package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  132. package/dist/primitives/threadList/ThreadListNew.d.ts +2 -3
  133. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  134. package/dist/primitives/threadList/ThreadListRoot.d.ts +2 -3
  135. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  136. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +2 -3
  137. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  138. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +2 -3
  139. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  140. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +2 -3
  141. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  142. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +2 -3
  143. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  144. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +2 -3
  145. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  146. package/package.json +13 -11
  147. package/src/index.ts +30 -0
  148. package/src/primitives/accessibilityRole.test.tsx +20 -0
  149. package/src/primitives/actionBar/ActionBar.test.tsx +299 -0
  150. package/src/primitives/actionBar/ActionBarCopy.tsx +8 -3
  151. package/src/primitives/actionBar/ActionBarEdit.tsx +16 -4
  152. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +14 -3
  153. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +14 -3
  154. package/src/primitives/actionBar/ActionBarReload.tsx +16 -4
  155. package/src/primitives/actionBar/ActionBarSpeak.tsx +42 -0
  156. package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +42 -0
  157. package/src/primitives/actionBar.ts +8 -0
  158. package/src/primitives/branchPicker/BranchPickerNext.test.tsx +52 -3
  159. package/src/primitives/branchPicker/BranchPickerNext.tsx +16 -4
  160. package/src/primitives/branchPicker/BranchPickerPrevious.test.tsx +52 -6
  161. package/src/primitives/branchPicker/BranchPickerPrevious.tsx +16 -4
  162. package/src/primitives/composer/ComposerAddAttachment.tsx +3 -8
  163. package/src/primitives/messagePart/MessagePartImage.test.tsx +91 -0
  164. package/src/primitives/messagePart/MessagePartImage.tsx +33 -0
  165. package/src/primitives/messagePart/MessagePartInProgress.ts +1 -0
  166. package/src/primitives/messagePart/MessagePartText.test.tsx +80 -0
  167. package/src/primitives/messagePart/MessagePartText.tsx +36 -0
  168. package/src/primitives/messagePart.ts +10 -0
  169. package/src/primitives/thread/ThreadMessages.test.tsx +335 -54
  170. package/src/primitives/thread/ThreadMessages.tsx +104 -26
@@ -67,6 +67,13 @@ export type ThreadMessagesFlatListProps = Omit<
67
67
  scrollToBottomOnRunStart?: boolean | undefined;
68
68
  scrollToBottomOnInitialize?: boolean | undefined;
69
69
  scrollToBottomOnThreadSwitch?: boolean | undefined;
70
+ history?:
71
+ | {
72
+ hasMore: boolean;
73
+ isLoadingMore: boolean;
74
+ loadMore: () => void;
75
+ }
76
+ | undefined;
70
77
  };
71
78
 
72
79
  /** @deprecated Use ThreadMessagesFlatListProps instead. */
@@ -206,6 +213,7 @@ const useComposedFlatListRef = (
206
213
  const useThreadMessagesFlatListAutoScroll = ({
207
214
  flatListRef,
208
215
  hasMessages,
216
+ horizontal = false,
209
217
  autoScroll = true,
210
218
  scrollToBottomOnRunStart = true,
211
219
  scrollToBottomOnInitialize = true,
@@ -213,6 +221,7 @@ const useThreadMessagesFlatListAutoScroll = ({
213
221
  }: {
214
222
  flatListRef: RefObject<FlatList<ThreadMessage> | null>;
215
223
  hasMessages: boolean;
224
+ horizontal?: boolean | null | undefined;
216
225
  autoScroll?: boolean | undefined;
217
226
  scrollToBottomOnRunStart?: boolean | undefined;
218
227
  scrollToBottomOnInitialize?: boolean | undefined;
@@ -224,9 +233,16 @@ const useThreadMessagesFlatListAutoScroll = ({
224
233
  scrollY: 0,
225
234
  });
226
235
  const isAtBottomRef = useRef(true);
227
- const lastScrollEventYRef = useRef(0);
236
+ const lastScrollEventOffsetRef = useRef(0);
228
237
  const initializeScrollRequestedRef = useRef(false);
229
- const pendingScrollToBottomRef = useRef<false | { animated: boolean }>(false);
238
+ const contentSizeVersionRef = useRef(0);
239
+ const pendingScrollToBottomRef = useRef<
240
+ | false
241
+ | {
242
+ animated: boolean;
243
+ minimumContentSizeVersion: number;
244
+ }
245
+ >(false);
230
246
 
231
247
  const updateIsAtBottom = useCallback(() => {
232
248
  const { contentHeight, scrollY, viewportHeight } = metricsRef.current;
@@ -241,9 +257,10 @@ const useThreadMessagesFlatListAutoScroll = ({
241
257
  const scrollToBottom = useCallback(
242
258
  (animated: boolean) => {
243
259
  const { contentHeight, viewportHeight } = metricsRef.current;
244
- metricsRef.current.scrollY = Math.max(0, contentHeight - viewportHeight);
260
+ const offset = Math.max(0, contentHeight - viewportHeight);
261
+ metricsRef.current.scrollY = offset;
245
262
  isAtBottomRef.current = true;
246
- flatListRef.current?.scrollToEnd({ animated });
263
+ flatListRef.current?.scrollToOffset({ offset, animated });
247
264
  },
248
265
  [flatListRef],
249
266
  );
@@ -252,9 +269,21 @@ const useThreadMessagesFlatListAutoScroll = ({
252
269
  (event: LayoutChangeEvent) => {
253
270
  const wasAtBottom = isAtBottomRef.current;
254
271
  const previousViewportHeight = metricsRef.current.viewportHeight;
255
- const viewportHeight = event.nativeEvent.layout.height;
272
+ const viewportHeight = horizontal
273
+ ? event.nativeEvent.layout.width
274
+ : event.nativeEvent.layout.height;
256
275
  metricsRef.current.viewportHeight = viewportHeight;
257
276
  updateIsAtBottom();
277
+ const pending = pendingScrollToBottomRef.current;
278
+ if (
279
+ pending &&
280
+ contentSizeVersionRef.current >= pending.minimumContentSizeVersion &&
281
+ viewportHeight > 0
282
+ ) {
283
+ pendingScrollToBottomRef.current = false;
284
+ scrollToBottom(pending.animated);
285
+ return;
286
+ }
258
287
  if (!wasAtBottom) return;
259
288
  // Layout changes are never user gestures, so they must not unpin. Past
260
289
  // the first measurement, a viewport change while pinned re-commands the
@@ -265,29 +294,31 @@ const useThreadMessagesFlatListAutoScroll = ({
265
294
  previousViewportHeight !== 0 &&
266
295
  viewportHeight !== previousViewportHeight
267
296
  ) {
268
- const pending = pendingScrollToBottomRef.current;
269
297
  scrollToBottom(pending ? pending.animated : false);
270
298
  } else {
271
299
  isAtBottomRef.current = true;
272
300
  }
273
301
  },
274
- [autoScroll, scrollToBottom, updateIsAtBottom],
302
+ [autoScroll, horizontal, scrollToBottom, updateIsAtBottom],
275
303
  );
276
304
 
277
305
  const handleScroll = useCallback(
278
306
  (event: NativeSyntheticEvent<NativeScrollEvent>) => {
279
307
  const { contentOffset, contentSize, layoutMeasurement } =
280
308
  event.nativeEvent;
281
- const previousEventY = lastScrollEventYRef.current;
309
+ const scrollOffset = horizontal ? contentOffset.x : contentOffset.y;
310
+ const previousEventOffset = lastScrollEventOffsetRef.current;
282
311
  const wasPinnedToBottom = isAtBottomRef.current;
283
- lastScrollEventYRef.current = contentOffset.y;
312
+ lastScrollEventOffsetRef.current = scrollOffset;
284
313
  metricsRef.current = {
285
- contentHeight: contentSize.height,
286
- viewportHeight: layoutMeasurement.height,
287
- scrollY: contentOffset.y,
314
+ contentHeight: horizontal ? contentSize.width : contentSize.height,
315
+ viewportHeight: horizontal
316
+ ? layoutMeasurement.width
317
+ : layoutMeasurement.height,
318
+ scrollY: scrollOffset,
288
319
  };
289
320
  updateIsAtBottom();
290
- const upwardMove = contentOffset.y < previousEventY;
321
+ const upwardMove = scrollOffset < previousEventOffset;
291
322
  // Only a deliberate upward move unpins or cancels a pending scroll.
292
323
  // Gestures are detected echo-to-echo because a commanded scroll
293
324
  // optimistically moves the tracked position ahead of its ascending
@@ -299,22 +330,28 @@ const useThreadMessagesFlatListAutoScroll = ({
299
330
  pendingScrollToBottomRef.current = false;
300
331
  }
301
332
  },
302
- [updateIsAtBottom],
333
+ [horizontal, updateIsAtBottom],
303
334
  );
304
335
 
305
336
  const handleContentSizeChange = useCallback(
306
- (_width: number, height: number) => {
337
+ (width: number, height: number) => {
307
338
  const metrics = metricsRef.current;
339
+ const contentHeight = horizontal ? width : height;
308
340
  const previousContentHeight = metrics.contentHeight;
309
341
  const wasAtBottom = isAtBottomRef.current;
310
- metrics.contentHeight = height;
342
+ if (contentHeight > 0) contentSizeVersionRef.current += 1;
343
+ metrics.contentHeight = contentHeight;
311
344
  updateIsAtBottom();
312
345
 
313
- // FlatList.scrollToEnd is a no-op before the list has measured, so the
314
- // initialize and thread-switch scrolls land on the next content-size
315
- // event, once real metrics exist.
346
+ // Initialize and thread-switch requests are repeated after the list has
347
+ // measured so the explicit bottom offset uses real content metrics.
316
348
  const pendingScroll = pendingScrollToBottomRef.current;
317
- if (pendingScroll) {
349
+ if (
350
+ pendingScroll &&
351
+ contentSizeVersionRef.current >=
352
+ pendingScroll.minimumContentSizeVersion &&
353
+ metrics.viewportHeight > 0
354
+ ) {
318
355
  pendingScrollToBottomRef.current = false;
319
356
  scrollToBottom(pendingScroll.animated);
320
357
  return;
@@ -323,11 +360,11 @@ const useThreadMessagesFlatListAutoScroll = ({
323
360
  if (!autoScroll) return;
324
361
  if (!wasAtBottom) return;
325
362
  if (previousContentHeight === 0) return;
326
- if (height <= previousContentHeight) return;
363
+ if (contentHeight <= previousContentHeight) return;
327
364
 
328
365
  scrollToBottom(false);
329
366
  },
330
- [autoScroll, scrollToBottom, updateIsAtBottom],
367
+ [autoScroll, horizontal, scrollToBottom, updateIsAtBottom],
331
368
  );
332
369
 
333
370
  useEffect(() => {
@@ -339,21 +376,30 @@ const useThreadMessagesFlatListAutoScroll = ({
339
376
  if (initializeScrollRequestedRef.current) return;
340
377
 
341
378
  initializeScrollRequestedRef.current = true;
342
- pendingScrollToBottomRef.current = { animated: false };
379
+ pendingScrollToBottomRef.current = {
380
+ animated: false,
381
+ minimumContentSizeVersion: Math.max(1, contentSizeVersionRef.current),
382
+ };
343
383
  scrollToBottom(false);
344
384
  }, [hasMessages, scrollToBottom, scrollToBottomOnInitialize]);
345
385
 
346
386
  useAuiEvent("thread.runStart", () => {
347
387
  if (!scrollToBottomOnRunStart) return;
348
- pendingScrollToBottomRef.current = { animated: true };
388
+ pendingScrollToBottomRef.current = {
389
+ animated: true,
390
+ minimumContentSizeVersion: contentSizeVersionRef.current + 1,
391
+ };
349
392
  scrollToBottom(true);
350
393
  });
351
394
 
352
395
  useAuiEvent("threads.selectionChanged", () => {
353
396
  if (!scrollToBottomOnThreadSwitch) return;
354
397
  initializeScrollRequestedRef.current = false;
355
- lastScrollEventYRef.current = 0;
356
- pendingScrollToBottomRef.current = { animated: false };
398
+ lastScrollEventOffsetRef.current = 0;
399
+ pendingScrollToBottomRef.current = {
400
+ animated: false,
401
+ minimumContentSizeVersion: contentSizeVersionRef.current + 1,
402
+ };
357
403
  scrollToBottom(false);
358
404
  });
359
405
 
@@ -376,10 +422,13 @@ export const ThreadMessagesFlatList = forwardRef<
376
422
  onContentSizeChange,
377
423
  onLayout,
378
424
  onScroll,
425
+ onStartReached,
426
+ onStartReachedThreshold,
379
427
  scrollEventThrottle,
380
428
  scrollToBottomOnInitialize,
381
429
  scrollToBottomOnRunStart,
382
430
  scrollToBottomOnThreadSwitch,
431
+ history,
383
432
  ...flatListProps
384
433
  },
385
434
  forwardedRef,
@@ -393,6 +442,7 @@ export const ThreadMessagesFlatList = forwardRef<
393
442
  } = useThreadMessagesFlatListAutoScroll({
394
443
  flatListRef,
395
444
  hasMessages: messages.length > 0,
445
+ horizontal: flatListProps.horizontal,
396
446
  autoScroll,
397
447
  scrollToBottomOnInitialize,
398
448
  scrollToBottomOnRunStart,
@@ -445,12 +495,25 @@ export const ThreadMessagesFlatList = forwardRef<
445
495
  [handleAutoScrollContentSizeChange, onContentSizeChange],
446
496
  );
447
497
 
498
+ const canLoadMore = history?.hasMore && !history.isLoadingMore;
499
+
500
+ const handleStartReached = useCallback<
501
+ NonNullable<FlatListProps<ThreadMessage>["onStartReached"]>
502
+ >(
503
+ (info) => {
504
+ onStartReached?.(info);
505
+ history?.loadMore();
506
+ },
507
+ [history, onStartReached],
508
+ );
509
+
448
510
  return (
449
511
  <FlatList
450
512
  ref={setFlatListRef}
451
513
  data={messages as unknown as ThreadMessage[]}
452
514
  renderItem={renderItem}
453
515
  keyExtractor={keyExtractor}
516
+ maintainVisibleContentPosition={{ minIndexForVisible: 0 }}
454
517
  {...(scrollTracking
455
518
  ? {
456
519
  onContentSizeChange: handleContentSizeChange,
@@ -464,6 +527,21 @@ export const ThreadMessagesFlatList = forwardRef<
464
527
  ...(onScroll && { onScroll }),
465
528
  ...(scrollEventThrottle !== undefined && { scrollEventThrottle }),
466
529
  })}
530
+ {...(history
531
+ ? {
532
+ ...(canLoadMore
533
+ ? { onStartReached: handleStartReached }
534
+ : onStartReached
535
+ ? { onStartReached }
536
+ : {}),
537
+ onStartReachedThreshold: onStartReachedThreshold ?? 1,
538
+ }
539
+ : {
540
+ ...(onStartReached && { onStartReached }),
541
+ ...(onStartReachedThreshold !== undefined && {
542
+ onStartReachedThreshold,
543
+ }),
544
+ })}
467
545
  {...flatListProps}
468
546
  />
469
547
  );