@assistant-ui/react-native 0.1.29 → 0.1.31
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/dist/index.d.ts +2 -2
- package/dist/primitives/actionBar/ActionBarCopy.d.ts +1 -8
- package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarEdit.d.ts +1 -6
- package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +1 -5
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +1 -5
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarReload.d.ts +1 -6
- package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
- package/dist/primitives/actionBar.d.ts +0 -2
- package/dist/primitives/attachment/AttachmentName.d.ts +0 -1
- package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentName.js.map +1 -1
- package/dist/primitives/attachment/AttachmentRemove.d.ts +1 -5
- package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentRoot.d.ts +1 -5
- package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentThumb.d.ts +0 -1
- package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentThumb.js.map +1 -1
- package/dist/primitives/attachment.d.ts +0 -2
- package/dist/primitives/branchPicker/BranchPickerCount.d.ts +0 -1
- package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerCount.js.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNext.d.ts +1 -6
- package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +0 -1
- package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNumber.js.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +1 -6
- package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
- package/dist/primitives/branchPicker.d.ts +0 -2
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +1 -5
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +1 -5
- package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
- package/dist/primitives/chainOfThought.d.ts +0 -2
- package/dist/primitives/composer/ComposerAddAttachment.d.ts +1 -6
- package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAttachments.d.ts +3 -16
- package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/primitives/composer/ComposerCancel.d.ts +1 -6
- package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerInput.d.ts +1 -8
- package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +15 -2
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/ComposerRoot.d.ts +1 -5
- package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerSend.d.ts +1 -6
- package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
- package/dist/primitives/composer.d.ts +3 -5
- package/dist/primitives/composer.js.map +1 -1
- package/dist/primitives/error/ErrorMessage.d.ts +1 -5
- package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
- package/dist/primitives/error/ErrorMessage.js.map +1 -1
- package/dist/primitives/error/ErrorRoot.d.ts +1 -5
- package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
- package/dist/primitives/error/index.d.ts +0 -2
- package/dist/primitives/message/MessageAttachments.d.ts +2 -9
- package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/primitives/message/MessageContent.d.ts +1 -10
- package/dist/primitives/message/MessageContent.d.ts.map +1 -1
- package/dist/primitives/message/MessageIf.d.ts +1 -8
- package/dist/primitives/message/MessageIf.d.ts.map +1 -1
- package/dist/primitives/message/MessageIf.js.map +1 -1
- package/dist/primitives/message/MessageParts.d.ts +0 -1
- package/dist/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/primitives/message/MessageRoot.d.ts +1 -5
- package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
- package/dist/primitives/message.d.ts +3 -5
- package/dist/primitives/message.js.map +1 -1
- package/dist/primitives/suggestion/SuggestionDescription.d.ts +1 -5
- package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
- package/dist/primitives/suggestion/SuggestionDescription.js.map +1 -1
- package/dist/primitives/suggestion/SuggestionTitle.d.ts +1 -5
- package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
- package/dist/primitives/suggestion/SuggestionTitle.js.map +1 -1
- package/dist/primitives/suggestion/SuggestionTrigger.d.ts +1 -8
- package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
- package/dist/primitives/suggestion.d.ts +0 -2
- package/dist/primitives/thread/ThreadEmpty.d.ts +1 -4
- package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadIf.d.ts +1 -6
- package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadIf.js.map +1 -1
- package/dist/primitives/thread/ThreadMessages.d.ts +14 -12
- package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadMessages.js +376 -33
- package/dist/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/primitives/thread/ThreadRoot.d.ts +1 -5
- package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadSuggestion.d.ts +3 -10
- package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
- package/dist/primitives/thread.d.ts +3 -5
- package/dist/primitives/thread.js +3 -2
- package/dist/primitives/thread.js.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.d.ts +1 -5
- package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListNew.d.ts +1 -5
- package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListRoot.d.ts +1 -5
- package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
- package/dist/primitives/threadList.d.ts +0 -2
- package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +1 -5
- package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +1 -5
- package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +1 -5
- package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +1 -5
- package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +1 -5
- package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
- package/dist/primitives/threadListItem.d.ts +0 -2
- package/package.json +9 -9
- package/src/index.ts +2 -0
- package/src/primitives/composer/ComposerAttachments.tsx +3 -15
- package/src/primitives/composer/ComposerInput.test.tsx +106 -8
- package/src/primitives/composer/ComposerInput.tsx +21 -2
- package/src/primitives/composer.ts +2 -0
- package/src/primitives/message/MessageAttachments.tsx +3 -8
- package/src/primitives/message.ts +2 -0
- package/src/primitives/thread/ThreadMessages.test.tsx +444 -10
- package/src/primitives/thread/ThreadMessages.tsx +320 -29
- package/src/primitives/thread.ts +2 -0
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ComponentType,
|
|
3
3
|
type FC,
|
|
4
|
+
type ForwardedRef,
|
|
4
5
|
type ReactNode,
|
|
6
|
+
type RefObject,
|
|
7
|
+
forwardRef,
|
|
5
8
|
memo,
|
|
6
9
|
useCallback,
|
|
10
|
+
useEffect,
|
|
11
|
+
useRef,
|
|
7
12
|
} from "react";
|
|
8
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
FlatList,
|
|
15
|
+
type FlatListProps,
|
|
16
|
+
type LayoutChangeEvent,
|
|
17
|
+
type NativeScrollEvent,
|
|
18
|
+
type NativeSyntheticEvent,
|
|
19
|
+
} from "react-native";
|
|
9
20
|
import type { MessageState, ThreadMessage } from "@assistant-ui/core";
|
|
10
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
RenderChildrenWithAccessor,
|
|
23
|
+
useAuiEvent,
|
|
24
|
+
useAuiState,
|
|
25
|
+
} from "@assistant-ui/store";
|
|
11
26
|
import { MessageByIndexProvider } from "@assistant-ui/core/react";
|
|
12
27
|
|
|
13
28
|
type MessageComponents =
|
|
@@ -43,13 +58,22 @@ type MessagesContent =
|
|
|
43
58
|
components?: never;
|
|
44
59
|
};
|
|
45
60
|
|
|
46
|
-
export type
|
|
61
|
+
export type ThreadMessagesFlatListProps = Omit<
|
|
47
62
|
FlatListProps<ThreadMessage>,
|
|
48
63
|
"data" | "renderItem" | "children"
|
|
49
64
|
> &
|
|
50
|
-
MessagesContent
|
|
65
|
+
MessagesContent & {
|
|
66
|
+
autoScroll?: boolean | undefined;
|
|
67
|
+
scrollToBottomOnRunStart?: boolean | undefined;
|
|
68
|
+
scrollToBottomOnInitialize?: boolean | undefined;
|
|
69
|
+
scrollToBottomOnThreadSwitch?: boolean | undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** @deprecated Use ThreadMessagesFlatListProps instead. */
|
|
73
|
+
export type ThreadMessagesProps = ThreadMessagesFlatListProps;
|
|
51
74
|
|
|
52
75
|
const DEFAULT_SYSTEM_MESSAGE = () => null;
|
|
76
|
+
const AT_BOTTOM_THRESHOLD = 4;
|
|
53
77
|
|
|
54
78
|
const getComponent = (
|
|
55
79
|
components: MessageComponents,
|
|
@@ -154,36 +178,303 @@ const ThreadMessageByChildren = memo(
|
|
|
154
178
|
);
|
|
155
179
|
ThreadMessageByChildren.displayName = "ThreadPrimitive.MessageByChildren";
|
|
156
180
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
const setForwardedRef = <T,>(ref: ForwardedRef<T>, value: T | null) => {
|
|
182
|
+
if (typeof ref === "function") {
|
|
183
|
+
ref(value);
|
|
184
|
+
} else if (ref) {
|
|
185
|
+
ref.current = value;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const useComposedFlatListRef = (
|
|
190
|
+
forwardedRef: ForwardedRef<FlatList<ThreadMessage>>,
|
|
191
|
+
) => {
|
|
192
|
+
const flatListRef = useRef<FlatList<ThreadMessage> | null>(null);
|
|
193
|
+
|
|
194
|
+
const setFlatListRef = useCallback(
|
|
195
|
+
(node: FlatList<ThreadMessage> | null) => {
|
|
196
|
+
flatListRef.current = node;
|
|
197
|
+
setForwardedRef(forwardedRef, node);
|
|
198
|
+
},
|
|
199
|
+
[forwardedRef],
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
return [flatListRef, setFlatListRef] as const;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const useThreadMessagesFlatListAutoScroll = ({
|
|
206
|
+
flatListRef,
|
|
207
|
+
hasMessages,
|
|
208
|
+
autoScroll = true,
|
|
209
|
+
scrollToBottomOnRunStart = true,
|
|
210
|
+
scrollToBottomOnInitialize = true,
|
|
211
|
+
scrollToBottomOnThreadSwitch = true,
|
|
212
|
+
}: {
|
|
213
|
+
flatListRef: RefObject<FlatList<ThreadMessage> | null>;
|
|
214
|
+
hasMessages: boolean;
|
|
215
|
+
autoScroll?: boolean | undefined;
|
|
216
|
+
scrollToBottomOnRunStart?: boolean | undefined;
|
|
217
|
+
scrollToBottomOnInitialize?: boolean | undefined;
|
|
218
|
+
scrollToBottomOnThreadSwitch?: boolean | undefined;
|
|
219
|
+
}) => {
|
|
220
|
+
const metricsRef = useRef({
|
|
221
|
+
contentHeight: 0,
|
|
222
|
+
viewportHeight: 0,
|
|
223
|
+
scrollY: 0,
|
|
224
|
+
});
|
|
225
|
+
const isAtBottomRef = useRef(true);
|
|
226
|
+
const lastScrollEventYRef = useRef(0);
|
|
227
|
+
const initializeScrollRequestedRef = useRef(false);
|
|
228
|
+
const pendingScrollToBottomRef = useRef<false | { animated: boolean }>(false);
|
|
229
|
+
|
|
230
|
+
const updateIsAtBottom = useCallback(() => {
|
|
231
|
+
const { contentHeight, scrollY, viewportHeight } = metricsRef.current;
|
|
232
|
+
isAtBottomRef.current =
|
|
233
|
+
contentHeight <= viewportHeight ||
|
|
234
|
+
contentHeight - scrollY - viewportHeight <= AT_BOTTOM_THRESHOLD;
|
|
235
|
+
}, []);
|
|
236
|
+
|
|
237
|
+
// Commanding a scroll records the intended position immediately; the
|
|
238
|
+
// native scroll echo is bridged and throttled, so waiting for it lets a
|
|
239
|
+
// fast stream observe stale metrics and drop out of following.
|
|
240
|
+
const scrollToBottom = useCallback(
|
|
241
|
+
(animated: boolean) => {
|
|
242
|
+
const { contentHeight, viewportHeight } = metricsRef.current;
|
|
243
|
+
metricsRef.current.scrollY = Math.max(0, contentHeight - viewportHeight);
|
|
244
|
+
isAtBottomRef.current = true;
|
|
245
|
+
flatListRef.current?.scrollToEnd({ animated });
|
|
246
|
+
},
|
|
247
|
+
[flatListRef],
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const handleLayout = useCallback(
|
|
251
|
+
(event: LayoutChangeEvent) => {
|
|
252
|
+
metricsRef.current.viewportHeight = event.nativeEvent.layout.height;
|
|
253
|
+
updateIsAtBottom();
|
|
254
|
+
},
|
|
255
|
+
[updateIsAtBottom],
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const handleScroll = useCallback(
|
|
259
|
+
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
260
|
+
const { contentOffset, contentSize, layoutMeasurement } =
|
|
261
|
+
event.nativeEvent;
|
|
262
|
+
const previousEventY = lastScrollEventYRef.current;
|
|
263
|
+
const wasPinnedToBottom = isAtBottomRef.current;
|
|
264
|
+
lastScrollEventYRef.current = contentOffset.y;
|
|
265
|
+
metricsRef.current = {
|
|
266
|
+
contentHeight: contentSize.height,
|
|
267
|
+
viewportHeight: layoutMeasurement.height,
|
|
268
|
+
scrollY: contentOffset.y,
|
|
269
|
+
};
|
|
270
|
+
updateIsAtBottom();
|
|
271
|
+
const upwardMove = contentOffset.y < previousEventY;
|
|
272
|
+
// Only a deliberate upward move unpins or cancels a pending scroll.
|
|
273
|
+
// Gestures are detected echo-to-echo because a commanded scroll
|
|
274
|
+
// optimistically moves the tracked position ahead of its ascending
|
|
275
|
+
// animation echoes, and those echoes must not unpin mid-flight.
|
|
276
|
+
if (wasPinnedToBottom && !upwardMove) {
|
|
277
|
+
isAtBottomRef.current = true;
|
|
278
|
+
}
|
|
279
|
+
if (!isAtBottomRef.current && upwardMove) {
|
|
280
|
+
pendingScrollToBottomRef.current = false;
|
|
172
281
|
}
|
|
173
|
-
return <ThreadMessageByIndex index={index} components={components!} />;
|
|
174
282
|
},
|
|
175
|
-
[
|
|
283
|
+
[updateIsAtBottom],
|
|
176
284
|
);
|
|
177
285
|
|
|
178
|
-
const
|
|
286
|
+
const handleContentSizeChange = useCallback(
|
|
287
|
+
(_width: number, height: number) => {
|
|
288
|
+
const metrics = metricsRef.current;
|
|
289
|
+
const previousContentHeight = metrics.contentHeight;
|
|
290
|
+
const wasAtBottom = isAtBottomRef.current;
|
|
291
|
+
metrics.contentHeight = height;
|
|
292
|
+
updateIsAtBottom();
|
|
179
293
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
294
|
+
// FlatList.scrollToEnd is a no-op before the list has measured, so the
|
|
295
|
+
// initialize and thread-switch scrolls land on the next content-size
|
|
296
|
+
// event, once real metrics exist.
|
|
297
|
+
const pendingScroll = pendingScrollToBottomRef.current;
|
|
298
|
+
if (pendingScroll) {
|
|
299
|
+
pendingScrollToBottomRef.current = false;
|
|
300
|
+
scrollToBottom(pendingScroll.animated);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!autoScroll) return;
|
|
305
|
+
if (!wasAtBottom) return;
|
|
306
|
+
if (previousContentHeight === 0) return;
|
|
307
|
+
if (height <= previousContentHeight) return;
|
|
308
|
+
|
|
309
|
+
scrollToBottom(false);
|
|
310
|
+
},
|
|
311
|
+
[autoScroll, scrollToBottom, updateIsAtBottom],
|
|
187
312
|
);
|
|
313
|
+
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
if (!scrollToBottomOnInitialize) return;
|
|
316
|
+
if (!hasMessages) {
|
|
317
|
+
initializeScrollRequestedRef.current = false;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (initializeScrollRequestedRef.current) return;
|
|
321
|
+
|
|
322
|
+
initializeScrollRequestedRef.current = true;
|
|
323
|
+
pendingScrollToBottomRef.current = { animated: false };
|
|
324
|
+
scrollToBottom(false);
|
|
325
|
+
}, [hasMessages, scrollToBottom, scrollToBottomOnInitialize]);
|
|
326
|
+
|
|
327
|
+
useAuiEvent("thread.runStart", () => {
|
|
328
|
+
if (!scrollToBottomOnRunStart) return;
|
|
329
|
+
pendingScrollToBottomRef.current = { animated: true };
|
|
330
|
+
scrollToBottom(true);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
useAuiEvent("threadListItem.switchedTo", () => {
|
|
334
|
+
if (!scrollToBottomOnThreadSwitch) return;
|
|
335
|
+
initializeScrollRequestedRef.current = false;
|
|
336
|
+
lastScrollEventYRef.current = 0;
|
|
337
|
+
pendingScrollToBottomRef.current = { animated: false };
|
|
338
|
+
scrollToBottom(false);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
handleLayout,
|
|
343
|
+
handleScroll,
|
|
344
|
+
handleContentSizeChange,
|
|
345
|
+
};
|
|
188
346
|
};
|
|
347
|
+
|
|
348
|
+
export const ThreadMessagesFlatList = forwardRef<
|
|
349
|
+
FlatList<ThreadMessage>,
|
|
350
|
+
ThreadMessagesFlatListProps
|
|
351
|
+
>(
|
|
352
|
+
(
|
|
353
|
+
{
|
|
354
|
+
autoScroll,
|
|
355
|
+
components,
|
|
356
|
+
children,
|
|
357
|
+
onContentSizeChange,
|
|
358
|
+
onLayout,
|
|
359
|
+
onScroll,
|
|
360
|
+
scrollEventThrottle,
|
|
361
|
+
scrollToBottomOnInitialize,
|
|
362
|
+
scrollToBottomOnRunStart,
|
|
363
|
+
scrollToBottomOnThreadSwitch,
|
|
364
|
+
...flatListProps
|
|
365
|
+
},
|
|
366
|
+
forwardedRef,
|
|
367
|
+
) => {
|
|
368
|
+
const messages = useAuiState((s) => s.thread.messages);
|
|
369
|
+
const [flatListRef, setFlatListRef] = useComposedFlatListRef(forwardedRef);
|
|
370
|
+
const {
|
|
371
|
+
handleContentSizeChange: handleAutoScrollContentSizeChange,
|
|
372
|
+
handleLayout: handleAutoScrollLayout,
|
|
373
|
+
handleScroll: handleAutoScrollScroll,
|
|
374
|
+
} = useThreadMessagesFlatListAutoScroll({
|
|
375
|
+
flatListRef,
|
|
376
|
+
hasMessages: messages.length > 0,
|
|
377
|
+
autoScroll,
|
|
378
|
+
scrollToBottomOnInitialize,
|
|
379
|
+
scrollToBottomOnRunStart,
|
|
380
|
+
scrollToBottomOnThreadSwitch,
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const renderItem = useCallback(
|
|
384
|
+
({ index }: { item: ThreadMessage; index: number }) => {
|
|
385
|
+
if (children) {
|
|
386
|
+
return (
|
|
387
|
+
<ThreadMessageByChildren index={index}>
|
|
388
|
+
{children}
|
|
389
|
+
</ThreadMessageByChildren>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return <ThreadMessageByIndex index={index} components={components!} />;
|
|
393
|
+
},
|
|
394
|
+
[components, children],
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
const keyExtractor = useCallback((item: ThreadMessage) => item.id, []);
|
|
398
|
+
|
|
399
|
+
const scrollTracking =
|
|
400
|
+
(autoScroll ?? true) ||
|
|
401
|
+
(scrollToBottomOnInitialize ?? true) ||
|
|
402
|
+
(scrollToBottomOnRunStart ?? true) ||
|
|
403
|
+
(scrollToBottomOnThreadSwitch ?? true);
|
|
404
|
+
|
|
405
|
+
const handleLayout = useCallback(
|
|
406
|
+
(event: LayoutChangeEvent) => {
|
|
407
|
+
handleAutoScrollLayout(event);
|
|
408
|
+
onLayout?.(event);
|
|
409
|
+
},
|
|
410
|
+
[handleAutoScrollLayout, onLayout],
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
const handleScroll = useCallback(
|
|
414
|
+
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
415
|
+
handleAutoScrollScroll(event);
|
|
416
|
+
onScroll?.(event);
|
|
417
|
+
},
|
|
418
|
+
[handleAutoScrollScroll, onScroll],
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
const handleContentSizeChange = useCallback(
|
|
422
|
+
(width: number, height: number) => {
|
|
423
|
+
handleAutoScrollContentSizeChange(width, height);
|
|
424
|
+
onContentSizeChange?.(width, height);
|
|
425
|
+
},
|
|
426
|
+
[handleAutoScrollContentSizeChange, onContentSizeChange],
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
return (
|
|
430
|
+
<FlatList
|
|
431
|
+
ref={setFlatListRef}
|
|
432
|
+
data={messages as unknown as ThreadMessage[]}
|
|
433
|
+
renderItem={renderItem}
|
|
434
|
+
keyExtractor={keyExtractor}
|
|
435
|
+
{...(scrollTracking
|
|
436
|
+
? {
|
|
437
|
+
onContentSizeChange: handleContentSizeChange,
|
|
438
|
+
onLayout: handleLayout,
|
|
439
|
+
onScroll: handleScroll,
|
|
440
|
+
scrollEventThrottle: scrollEventThrottle ?? 16,
|
|
441
|
+
}
|
|
442
|
+
: {
|
|
443
|
+
...(onContentSizeChange && { onContentSizeChange }),
|
|
444
|
+
...(onLayout && { onLayout }),
|
|
445
|
+
...(onScroll && { onScroll }),
|
|
446
|
+
...(scrollEventThrottle !== undefined && { scrollEventThrottle }),
|
|
447
|
+
})}
|
|
448
|
+
{...flatListProps}
|
|
449
|
+
/>
|
|
450
|
+
);
|
|
451
|
+
},
|
|
452
|
+
);
|
|
453
|
+
ThreadMessagesFlatList.displayName = "ThreadPrimitive.MessagesFlatList";
|
|
454
|
+
|
|
455
|
+
/** @deprecated Use ThreadPrimitive.MessagesFlatList instead. */
|
|
456
|
+
export const ThreadMessages = forwardRef<
|
|
457
|
+
FlatList<ThreadMessage>,
|
|
458
|
+
ThreadMessagesProps
|
|
459
|
+
>(
|
|
460
|
+
(
|
|
461
|
+
{
|
|
462
|
+
autoScroll = false,
|
|
463
|
+
scrollToBottomOnInitialize = false,
|
|
464
|
+
scrollToBottomOnRunStart = false,
|
|
465
|
+
scrollToBottomOnThreadSwitch = false,
|
|
466
|
+
...props
|
|
467
|
+
},
|
|
468
|
+
ref,
|
|
469
|
+
) => (
|
|
470
|
+
<ThreadMessagesFlatList
|
|
471
|
+
ref={ref}
|
|
472
|
+
autoScroll={autoScroll}
|
|
473
|
+
scrollToBottomOnInitialize={scrollToBottomOnInitialize}
|
|
474
|
+
scrollToBottomOnRunStart={scrollToBottomOnRunStart}
|
|
475
|
+
scrollToBottomOnThreadSwitch={scrollToBottomOnThreadSwitch}
|
|
476
|
+
{...props}
|
|
477
|
+
/>
|
|
478
|
+
),
|
|
479
|
+
);
|
|
189
480
|
ThreadMessages.displayName = "ThreadPrimitive.Messages";
|
package/src/primitives/thread.ts
CHANGED
|
@@ -3,6 +3,8 @@ export {
|
|
|
3
3
|
type ThreadRootProps as RootProps,
|
|
4
4
|
} from "./thread/ThreadRoot";
|
|
5
5
|
export {
|
|
6
|
+
ThreadMessagesFlatList as MessagesFlatList,
|
|
7
|
+
type ThreadMessagesFlatListProps as MessagesFlatListProps,
|
|
6
8
|
ThreadMessages as Messages,
|
|
7
9
|
type ThreadMessagesProps as MessagesProps,
|
|
8
10
|
} from "./thread/ThreadMessages";
|