@assistant-ui/react-native 0.1.35 → 0.1.37
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/primitives/composer/ComposerInput.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +1 -0
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadMessages.js +2 -2
- package/dist/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.js +8 -3
- package/dist/primitives/threadList/ThreadListItems.js.map +1 -1
- package/package.json +8 -7
- package/src/primitives/composer/ComposerInput.test.tsx +12 -0
- package/src/primitives/composer/ComposerInput.tsx +18 -15
- package/src/primitives/thread/ThreadMessages.test.tsx +18 -4
- package/src/primitives/thread/ThreadMessages.tsx +3 -2
- package/src/primitives/threadList/ThreadListItems.test.tsx +166 -0
- package/src/primitives/threadList/ThreadListItems.tsx +6 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerInput.d.ts","names":[],"sources":["../../../src/primitives/composer/ComposerInput.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"ComposerInput.d.ts","names":[],"sources":["../../../src/primitives/composer/ComposerInput.tsx"],"mappings":";;KAUY,qBAAqB,KAC/B;;;;;;;EASA;;cAoCW,kBAAiB,YAAA,YAAA,gBAAA,eAAA,UAAA,SAM3B,uCAAkB,IAAA"}
|
|
@@ -86,6 +86,7 @@ const ComposerInput = (t0) => {
|
|
|
86
86
|
if ($[11] !== aui || $[12] !== onKeyPressProp || $[13] !== submitMode) {
|
|
87
87
|
t5 = (e) => {
|
|
88
88
|
onKeyPressProp?.(e);
|
|
89
|
+
if (e.isDefaultPrevented()) return;
|
|
89
90
|
if (Platform.OS !== "web") return;
|
|
90
91
|
if (submitMode !== "enter") return;
|
|
91
92
|
const nativeEvent = e.nativeEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerInput.js","names":["useCallback","useEffect","useRef","Platform","TextInput","
|
|
1
|
+
{"version":3,"file":"ComposerInput.js","names":["useCallback","useEffect","useRef","Platform","TextInput","TextInputProps","useAui","useAuiState","flushTapSync","TextInputInstance","React","ComponentRef","TextInputKeyPressEvent","Parameters","NonNullable","ComposerInputProps","Omit","submitMode","getWebTextareaMaxHeight","el","HTMLTextAreaElement","computedMaxHeight","globalThis","getComputedStyle","maxHeight","parsedComputedMaxHeight","Number","parseFloat","isFinite","inlineMaxHeight","style","adjustWebTextareaHeight","ref","RefObject","OS","current","rows","overflowX","overflowY","height","scrollHeight","needsScrollbar","nextHeight","Math","min","ComposerInput","t0","$","_c","numberOfLines","onKeyPressProp","props","t1","onKeyPress","undefined","aui","text","_temp","inputRef","t2","value","composer","setText","onChangeText","t3","Symbol","for","t4","t5","e","isDefaultPrevented","nativeEvent","shiftKey","isComposing","keyCode","key","Event","preventDefault","send","t6","t7","s"],"sources":["../../../src/primitives/composer/ComposerInput.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport { Platform, TextInput, type TextInputProps } from \"react-native\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\n\ntype TextInputInstance = React.ComponentRef<typeof TextInput>;\ntype TextInputKeyPressEvent = Parameters<\n NonNullable<TextInputProps[\"onKeyPress\"]>\n>[0];\n\nexport type ComposerInputProps = Omit<\n TextInputProps,\n \"value\" | \"onChangeText\"\n> & {\n /**\n * Controls how the Enter key submits messages (web only).\n * - \"enter\": Plain Enter submits (Shift+Enter for newline)\n * - \"none\": Enter inserts newline (no keyboard submission)\n * @default \"enter\"\n */\n submitMode?: \"enter\" | \"none\";\n};\n\nconst getWebTextareaMaxHeight = (el: HTMLTextAreaElement) => {\n const computedMaxHeight = globalThis.getComputedStyle?.(el).maxHeight;\n const parsedComputedMaxHeight = Number.parseFloat(computedMaxHeight ?? \"\");\n if (Number.isFinite(parsedComputedMaxHeight)) return parsedComputedMaxHeight;\n\n const inlineMaxHeight = Number.parseFloat(el.style.maxHeight);\n return Number.isFinite(inlineMaxHeight) ? inlineMaxHeight : null;\n};\n\nconst adjustWebTextareaHeight = (\n ref: React.RefObject<TextInputInstance | null>,\n) => {\n if (Platform.OS !== \"web\") return;\n // On web, the TextInput ref IS the DOM element\n const el = ref.current as unknown as HTMLTextAreaElement | null;\n if (!el) return;\n // Ensure rows=1 so scrollHeight reflects actual content\n if (el.rows !== 1) el.rows = 1;\n\n el.style.overflowX = \"hidden\";\n el.style.overflowY = \"hidden\";\n el.style.height = \"auto\";\n\n const scrollHeight = el.scrollHeight;\n const maxHeight = getWebTextareaMaxHeight(el);\n const needsScrollbar = maxHeight !== null && scrollHeight > maxHeight;\n const nextHeight =\n maxHeight === null ? scrollHeight : Math.min(scrollHeight, maxHeight);\n\n el.style.overflowY = needsScrollbar ? \"auto\" : \"hidden\";\n el.style.height = `${nextHeight}px`;\n};\n\nexport const ComposerInput = ({\n submitMode = \"enter\",\n onKeyPress: onKeyPressProp,\n numberOfLines,\n style,\n ...props\n}: ComposerInputProps) => {\n const aui = useAui();\n const text = useAuiState((s) => s.composer.text);\n const inputRef = useRef<TextInputInstance>(null);\n\n const onChangeText = useCallback(\n (value: string) => {\n if (Platform.OS === \"web\") {\n // Keep the controlled value in sync mid-IME so react-dom does not reset the textarea to a stale value\n flushTapSync(() => {\n aui.composer.setText(value);\n });\n return;\n }\n aui.composer.setText(value);\n },\n [aui],\n );\n\n // Auto-resize textarea on web when text changes\n useEffect(() => {\n void text; // trigger re-run when text changes\n adjustWebTextareaHeight(inputRef);\n }, [text]);\n\n const onKeyPress = useCallback(\n (e: TextInputKeyPressEvent) => {\n onKeyPressProp?.(e);\n if (e.isDefaultPrevented()) return;\n\n if (Platform.OS !== \"web\") return;\n if (submitMode !== \"enter\") return;\n\n const nativeEvent =\n e.nativeEvent as TextInputKeyPressEvent[\"nativeEvent\"] & {\n shiftKey?: boolean;\n isComposing?: boolean;\n keyCode?: number;\n };\n // react-native-web forwards the raw DOM keydown before its own composition guard, so re-check it here (mirrors isEventComposing)\n if (nativeEvent.isComposing || nativeEvent.keyCode === 229) return;\n if (nativeEvent.key === \"Enter\" && !nativeEvent.shiftKey) {\n (e as unknown as Event).preventDefault?.();\n aui.composer.send();\n }\n },\n [aui, submitMode, onKeyPressProp],\n );\n\n return (\n <TextInput\n ref={inputRef}\n value={text}\n onChangeText={onChangeText}\n onKeyPress={onKeyPress}\n numberOfLines={numberOfLines ?? (Platform.OS === \"web\" ? 1 : undefined)}\n style={style}\n {...props}\n />\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadMessages.d.ts","names":[],"sources":["../../../src/primitives/thread/ThreadMessages.tsx"],"mappings":";;;;KA2BK;EAEC,SAAS;EACT,eAAe;EACf,mBAAmB;EACnB,wBAAwB;EACxB,qBAAqB;EACrB,cAAc;EACd,mBAAmB;EACnB,gBAAgB;;EAGhB,UAAU;EACV,eAAe;EACf,mBAAmB;EACnB,wBAAwB;EACxB,qBAAqB;EACrB,aAAa;EACb,kBAAkB;EAClB,gBAAgB;;KAGjB;;EAGC,YAAY;EACZ;;EAGA,WAAW;IAAS,SAAS;QAAmB;EAChD;;KAGM,8BAA8B,KACxC,cAAc,sDAGd;EACE;EACA;EACA;EACA;;;KAIQ,sBAAsB;
|
|
1
|
+
{"version":3,"file":"ThreadMessages.d.ts","names":[],"sources":["../../../src/primitives/thread/ThreadMessages.tsx"],"mappings":";;;;KA2BK;EAEC,SAAS;EACT,eAAe;EACf,mBAAmB;EACnB,wBAAwB;EACxB,qBAAqB;EACrB,cAAc;EACd,mBAAmB;EACnB,gBAAgB;;EAGhB,UAAU;EACV,eAAe;EACf,mBAAmB;EACnB,wBAAwB;EACxB,qBAAqB;EACrB,aAAa;EACb,kBAAkB;EAClB,gBAAgB;;KAGjB;;EAGC,YAAY;EACZ;;EAGA,WAAW;IAAS,SAAS;QAAmB;EAChD;;KAGM,8BAA8B,KACxC,cAAc,sDAGd;EACE;EACA;EACA;EACA;;;KAIQ,sBAAsB;cAsSrB,wCAAsB,0BAAA,8CAAA,cAAA,SAAA;;cA4GtB,gCAAc,0BAAA,8CAAA,cAAA,SAAA"}
|
|
@@ -13,7 +13,7 @@ const getComponent = (components, role, isEditing) => {
|
|
|
13
13
|
else return components.UserMessage ?? components.Message;
|
|
14
14
|
case "assistant": if (isEditing) return components.AssistantEditComposer ?? components.EditComposer ?? components.AssistantMessage ?? components.Message;
|
|
15
15
|
else return components.AssistantMessage ?? components.Message;
|
|
16
|
-
case "system": if (isEditing) return components.SystemEditComposer ?? components.EditComposer ?? components.SystemMessage ?? components.Message;
|
|
16
|
+
case "system": if (isEditing) return components.SystemEditComposer ?? components.EditComposer ?? components.SystemMessage ?? components.Message ?? DEFAULT_SYSTEM_MESSAGE;
|
|
17
17
|
else return components.SystemMessage ?? components.Message ?? DEFAULT_SYSTEM_MESSAGE;
|
|
18
18
|
default: throw new Error(`Unknown message role: ${role}`);
|
|
19
19
|
}
|
|
@@ -259,7 +259,7 @@ const useThreadMessagesFlatListAutoScroll = (t0) => {
|
|
|
259
259
|
$[20] = scrollToBottomOnThreadSwitch;
|
|
260
260
|
$[21] = t14;
|
|
261
261
|
} else t14 = $[21];
|
|
262
|
-
useAuiEvent("
|
|
262
|
+
useAuiEvent("threads.selectionChanged", t14);
|
|
263
263
|
let t15;
|
|
264
264
|
if ($[22] !== handleContentSizeChange || $[23] !== handleLayout) {
|
|
265
265
|
t15 = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadMessages.js","names":["ComponentType","FC","ForwardedRef","ReactNode","RefObject","forwardRef","memo","useCallback","useEffect","useRef","FlatList","FlatListProps","LayoutChangeEvent","NativeScrollEvent","NativeSyntheticEvent","MessageState","ThreadMessage","RenderChildrenWithAccessor","useAuiEvent","useAuiState","MessageByIndexProvider","MessageComponents","Message","EditComposer","UserEditComposer","AssistantEditComposer","SystemEditComposer","UserMessage","AssistantMessage","SystemMessage","MessagesContent","components","children","value","message","ThreadMessagesFlatListProps","Omit","autoScroll","scrollToBottomOnRunStart","scrollToBottomOnInitialize","scrollToBottomOnThreadSwitch","ThreadMessagesProps","DEFAULT_SYSTEM_MESSAGE","AT_BOTTOM_THRESHOLD","getComponent","role","isEditing","_exhaustiveCheck","Error","ThreadMessageComponent","t0","$","_c","_temp","_temp2","t1","Component","t2","ThreadMessageByIndex","index","prev","next","displayName","ThreadMessageByChildren","aui","thread","getState","getItem","setForwardedRef","ref","T","current","useComposedFlatListRef","forwardedRef","flatListRef","node","setFlatListRef","const","useThreadMessagesFlatListAutoScroll","hasMessages","t3","t4","undefined","t5","Symbol","for","contentHeight","viewportHeight","scrollY","metricsRef","isAtBottomRef","lastScrollEventYRef","initializeScrollRequestedRef","pendingScrollToBottomRef","t6","updateIsAtBottom","t7","animated","contentHeight_0","viewportHeight_0","Math","max","scrollToEnd","scrollToBottom","t8","event","wasAtBottom","previousViewportHeight","viewportHeight_1","nativeEvent","layout","height","pending","handleLayout","t9","event_0","contentOffset","contentSize","layoutMeasurement","previousEventY","wasPinnedToBottom","y","upwardMove","handleScroll","t10","_width","metrics","previousContentHeight","wasAtBottom_0","pendingScroll","handleContentSizeChange","t11","t12","t13","t14","t15","ThreadMessagesFlatList","flatListProps","onContentSizeChange","onLayout","onScroll","scrollEventThrottle","messages","_temp3","length","handleAutoScrollContentSizeChange","handleAutoScrollLayout","handleAutoScrollScroll","renderItem","keyExtractor","_temp4","scrollTracking","width","ThreadMessages","props","s","s_0","composer","item","id"],"sources":["../../../src/primitives/thread/ThreadMessages.tsx"],"sourcesContent":["import {\n type ComponentType,\n type FC,\n type ForwardedRef,\n type ReactNode,\n type RefObject,\n forwardRef,\n memo,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport {\n FlatList,\n type FlatListProps,\n type LayoutChangeEvent,\n type NativeScrollEvent,\n type NativeSyntheticEvent,\n} from \"react-native\";\nimport type { MessageState, ThreadMessage } from \"@assistant-ui/core\";\nimport {\n RenderChildrenWithAccessor,\n useAuiEvent,\n useAuiState,\n} from \"@assistant-ui/store\";\nimport { MessageByIndexProvider } from \"@assistant-ui/core/react\";\n\ntype MessageComponents =\n | {\n Message: ComponentType;\n EditComposer?: ComponentType | undefined;\n UserEditComposer?: ComponentType | undefined;\n AssistantEditComposer?: ComponentType | undefined;\n SystemEditComposer?: ComponentType | undefined;\n UserMessage?: ComponentType | undefined;\n AssistantMessage?: ComponentType | undefined;\n SystemMessage?: ComponentType | undefined;\n }\n | {\n Message?: ComponentType | undefined;\n EditComposer?: ComponentType | undefined;\n UserEditComposer?: ComponentType | undefined;\n AssistantEditComposer?: ComponentType | undefined;\n SystemEditComposer?: ComponentType | undefined;\n UserMessage: ComponentType;\n AssistantMessage: ComponentType;\n SystemMessage?: ComponentType | undefined;\n };\n\ntype MessagesContent =\n | {\n /** @deprecated Use the children render function instead. */\n components: MessageComponents;\n children?: never;\n }\n | {\n children: (value: { message: MessageState }) => ReactNode;\n components?: never;\n };\n\nexport type ThreadMessagesFlatListProps = Omit<\n FlatListProps<ThreadMessage>,\n \"data\" | \"renderItem\" | \"children\"\n> &\n MessagesContent & {\n autoScroll?: boolean | undefined;\n scrollToBottomOnRunStart?: boolean | undefined;\n scrollToBottomOnInitialize?: boolean | undefined;\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n };\n\n/** @deprecated Use ThreadMessagesFlatListProps instead. */\nexport type ThreadMessagesProps = ThreadMessagesFlatListProps;\n\nconst DEFAULT_SYSTEM_MESSAGE = () => null;\nconst AT_BOTTOM_THRESHOLD = 4;\n\nconst getComponent = (\n components: MessageComponents,\n role: ThreadMessage[\"role\"],\n isEditing: boolean,\n) => {\n switch (role) {\n case \"user\":\n if (isEditing) {\n return (\n components.UserEditComposer ??\n components.EditComposer ??\n components.UserMessage ??\n (components.Message as ComponentType)\n );\n } else {\n return components.UserMessage ?? (components.Message as ComponentType);\n }\n case \"assistant\":\n if (isEditing) {\n return (\n components.AssistantEditComposer ??\n components.EditComposer ??\n components.AssistantMessage ??\n (components.Message as ComponentType)\n );\n } else {\n return (\n components.AssistantMessage ?? (components.Message as ComponentType)\n );\n }\n case \"system\":\n if (isEditing) {\n return (\n components.SystemEditComposer ??\n components.EditComposer ??\n components.SystemMessage ??\n (components.Message as ComponentType)\n );\n } else {\n return (\n components.SystemMessage ??\n (components.Message as ComponentType) ??\n DEFAULT_SYSTEM_MESSAGE\n );\n }\n default: {\n const _exhaustiveCheck: never = role;\n throw new Error(`Unknown message role: ${_exhaustiveCheck}`);\n }\n }\n};\n\nconst ThreadMessageComponent: FC<{ components: MessageComponents }> = ({\n components,\n}) => {\n const role = useAuiState((s) => s.message.role);\n const isEditing = useAuiState((s) => s.message.composer.isEditing);\n const Component = getComponent(components, role, isEditing);\n\n return <Component />;\n};\n\nconst ThreadMessageByIndex = memo(\n ({ index, components }: { index: number; components: MessageComponents }) => {\n return (\n <MessageByIndexProvider index={index}>\n <ThreadMessageComponent components={components} />\n </MessageByIndexProvider>\n );\n },\n (prev, next) =>\n prev.index === next.index && prev.components === next.components,\n);\nThreadMessageByIndex.displayName = \"ThreadPrimitive.MessageByIndex\";\n\nconst ThreadMessageByChildren = memo(\n ({\n index,\n children,\n }: {\n index: number;\n children: (value: { message: MessageState }) => ReactNode;\n }) => {\n return (\n <MessageByIndexProvider index={index}>\n <RenderChildrenWithAccessor\n getItemState={(aui) => aui.thread.message({ index }).getState()}\n >\n {(getItem) =>\n children({\n get message() {\n return getItem();\n },\n })\n }\n </RenderChildrenWithAccessor>\n </MessageByIndexProvider>\n );\n },\n (prev, next) => prev.index === next.index && prev.children === next.children,\n);\nThreadMessageByChildren.displayName = \"ThreadPrimitive.MessageByChildren\";\n\nconst setForwardedRef = <T,>(ref: ForwardedRef<T>, value: T | null) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst useComposedFlatListRef = (\n forwardedRef: ForwardedRef<FlatList<ThreadMessage>>,\n) => {\n const flatListRef = useRef<FlatList<ThreadMessage> | null>(null);\n\n const setFlatListRef = useCallback(\n (node: FlatList<ThreadMessage> | null) => {\n flatListRef.current = node;\n setForwardedRef(forwardedRef, node);\n },\n [forwardedRef],\n );\n\n return [flatListRef, setFlatListRef] as const;\n};\n\nconst useThreadMessagesFlatListAutoScroll = ({\n flatListRef,\n hasMessages,\n autoScroll = true,\n scrollToBottomOnRunStart = true,\n scrollToBottomOnInitialize = true,\n scrollToBottomOnThreadSwitch = true,\n}: {\n flatListRef: RefObject<FlatList<ThreadMessage> | null>;\n hasMessages: boolean;\n autoScroll?: boolean | undefined;\n scrollToBottomOnRunStart?: boolean | undefined;\n scrollToBottomOnInitialize?: boolean | undefined;\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n}) => {\n const metricsRef = useRef({\n contentHeight: 0,\n viewportHeight: 0,\n scrollY: 0,\n });\n const isAtBottomRef = useRef(true);\n const lastScrollEventYRef = useRef(0);\n const initializeScrollRequestedRef = useRef(false);\n const pendingScrollToBottomRef = useRef<false | { animated: boolean }>(false);\n\n const updateIsAtBottom = useCallback(() => {\n const { contentHeight, scrollY, viewportHeight } = metricsRef.current;\n isAtBottomRef.current =\n contentHeight <= viewportHeight ||\n contentHeight - scrollY - viewportHeight <= AT_BOTTOM_THRESHOLD;\n }, []);\n\n // Commanding a scroll records the intended position immediately; the\n // native scroll echo is bridged and throttled, so waiting for it lets a\n // fast stream observe stale metrics and drop out of following.\n const scrollToBottom = useCallback(\n (animated: boolean) => {\n const { contentHeight, viewportHeight } = metricsRef.current;\n metricsRef.current.scrollY = Math.max(0, contentHeight - viewportHeight);\n isAtBottomRef.current = true;\n flatListRef.current?.scrollToEnd({ animated });\n },\n [flatListRef],\n );\n\n const handleLayout = useCallback(\n (event: LayoutChangeEvent) => {\n const wasAtBottom = isAtBottomRef.current;\n const previousViewportHeight = metricsRef.current.viewportHeight;\n const viewportHeight = event.nativeEvent.layout.height;\n metricsRef.current.viewportHeight = viewportHeight;\n updateIsAtBottom();\n if (!wasAtBottom) return;\n // Layout changes are never user gestures, so they must not unpin. Past\n // the first measurement, a viewport change while pinned re-commands the\n // bottom position, since no content-size event follows a bare keyboard\n // open or close.\n if (\n autoScroll &&\n previousViewportHeight !== 0 &&\n viewportHeight !== previousViewportHeight\n ) {\n const pending = pendingScrollToBottomRef.current;\n scrollToBottom(pending ? pending.animated : false);\n } else {\n isAtBottomRef.current = true;\n }\n },\n [autoScroll, scrollToBottom, updateIsAtBottom],\n );\n\n const handleScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n const { contentOffset, contentSize, layoutMeasurement } =\n event.nativeEvent;\n const previousEventY = lastScrollEventYRef.current;\n const wasPinnedToBottom = isAtBottomRef.current;\n lastScrollEventYRef.current = contentOffset.y;\n metricsRef.current = {\n contentHeight: contentSize.height,\n viewportHeight: layoutMeasurement.height,\n scrollY: contentOffset.y,\n };\n updateIsAtBottom();\n const upwardMove = contentOffset.y < previousEventY;\n // Only a deliberate upward move unpins or cancels a pending scroll.\n // Gestures are detected echo-to-echo because a commanded scroll\n // optimistically moves the tracked position ahead of its ascending\n // animation echoes, and those echoes must not unpin mid-flight.\n if (wasPinnedToBottom && !upwardMove) {\n isAtBottomRef.current = true;\n }\n if (!isAtBottomRef.current && upwardMove) {\n pendingScrollToBottomRef.current = false;\n }\n },\n [updateIsAtBottom],\n );\n\n const handleContentSizeChange = useCallback(\n (_width: number, height: number) => {\n const metrics = metricsRef.current;\n const previousContentHeight = metrics.contentHeight;\n const wasAtBottom = isAtBottomRef.current;\n metrics.contentHeight = height;\n updateIsAtBottom();\n\n // FlatList.scrollToEnd is a no-op before the list has measured, so the\n // initialize and thread-switch scrolls land on the next content-size\n // event, once real metrics exist.\n const pendingScroll = pendingScrollToBottomRef.current;\n if (pendingScroll) {\n pendingScrollToBottomRef.current = false;\n scrollToBottom(pendingScroll.animated);\n return;\n }\n\n if (!autoScroll) return;\n if (!wasAtBottom) return;\n if (previousContentHeight === 0) return;\n if (height <= previousContentHeight) return;\n\n scrollToBottom(false);\n },\n [autoScroll, scrollToBottom, updateIsAtBottom],\n );\n\n useEffect(() => {\n if (!scrollToBottomOnInitialize) return;\n if (!hasMessages) {\n initializeScrollRequestedRef.current = false;\n return;\n }\n if (initializeScrollRequestedRef.current) return;\n\n initializeScrollRequestedRef.current = true;\n pendingScrollToBottomRef.current = { animated: false };\n scrollToBottom(false);\n }, [hasMessages, scrollToBottom, scrollToBottomOnInitialize]);\n\n useAuiEvent(\"thread.runStart\", () => {\n if (!scrollToBottomOnRunStart) return;\n pendingScrollToBottomRef.current = { animated: true };\n scrollToBottom(true);\n });\n\n useAuiEvent(\"threadListItem.switchedTo\", () => {\n if (!scrollToBottomOnThreadSwitch) return;\n initializeScrollRequestedRef.current = false;\n lastScrollEventYRef.current = 0;\n pendingScrollToBottomRef.current = { animated: false };\n scrollToBottom(false);\n });\n\n return {\n handleLayout,\n handleScroll,\n handleContentSizeChange,\n };\n};\n\nexport const ThreadMessagesFlatList = forwardRef<\n FlatList<ThreadMessage>,\n ThreadMessagesFlatListProps\n>(\n (\n {\n autoScroll,\n components,\n children,\n onContentSizeChange,\n onLayout,\n onScroll,\n scrollEventThrottle,\n scrollToBottomOnInitialize,\n scrollToBottomOnRunStart,\n scrollToBottomOnThreadSwitch,\n ...flatListProps\n },\n forwardedRef,\n ) => {\n const messages = useAuiState((s) => s.thread.messages);\n const [flatListRef, setFlatListRef] = useComposedFlatListRef(forwardedRef);\n const {\n handleContentSizeChange: handleAutoScrollContentSizeChange,\n handleLayout: handleAutoScrollLayout,\n handleScroll: handleAutoScrollScroll,\n } = useThreadMessagesFlatListAutoScroll({\n flatListRef,\n hasMessages: messages.length > 0,\n autoScroll,\n scrollToBottomOnInitialize,\n scrollToBottomOnRunStart,\n scrollToBottomOnThreadSwitch,\n });\n\n const renderItem = useCallback(\n ({ index }: { item: ThreadMessage; index: number }) => {\n if (children) {\n return (\n <ThreadMessageByChildren index={index}>\n {children}\n </ThreadMessageByChildren>\n );\n }\n return <ThreadMessageByIndex index={index} components={components!} />;\n },\n [components, children],\n );\n\n const keyExtractor = useCallback((item: ThreadMessage) => item.id, []);\n\n const scrollTracking =\n (autoScroll ?? true) ||\n (scrollToBottomOnInitialize ?? true) ||\n (scrollToBottomOnRunStart ?? true) ||\n (scrollToBottomOnThreadSwitch ?? true);\n\n const handleLayout = useCallback(\n (event: LayoutChangeEvent) => {\n handleAutoScrollLayout(event);\n onLayout?.(event);\n },\n [handleAutoScrollLayout, onLayout],\n );\n\n const handleScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n handleAutoScrollScroll(event);\n onScroll?.(event);\n },\n [handleAutoScrollScroll, onScroll],\n );\n\n const handleContentSizeChange = useCallback(\n (width: number, height: number) => {\n handleAutoScrollContentSizeChange(width, height);\n onContentSizeChange?.(width, height);\n },\n [handleAutoScrollContentSizeChange, onContentSizeChange],\n );\n\n return (\n <FlatList\n ref={setFlatListRef}\n data={messages as unknown as ThreadMessage[]}\n renderItem={renderItem}\n keyExtractor={keyExtractor}\n {...(scrollTracking\n ? {\n onContentSizeChange: handleContentSizeChange,\n onLayout: handleLayout,\n onScroll: handleScroll,\n scrollEventThrottle: scrollEventThrottle ?? 16,\n }\n : {\n ...(onContentSizeChange && { onContentSizeChange }),\n ...(onLayout && { onLayout }),\n ...(onScroll && { onScroll }),\n ...(scrollEventThrottle !== undefined && { scrollEventThrottle }),\n })}\n {...flatListProps}\n />\n );\n },\n);\nThreadMessagesFlatList.displayName = \"ThreadPrimitive.MessagesFlatList\";\n\n/** @deprecated Use ThreadPrimitive.MessagesFlatList instead. */\nexport const ThreadMessages = forwardRef<\n FlatList<ThreadMessage>,\n ThreadMessagesProps\n>(\n (\n {\n autoScroll = false,\n scrollToBottomOnInitialize = false,\n scrollToBottomOnRunStart = false,\n scrollToBottomOnThreadSwitch = false,\n ...props\n },\n ref,\n ) => (\n <ThreadMessagesFlatList\n ref={ref}\n autoScroll={autoScroll}\n scrollToBottomOnInitialize={scrollToBottomOnInitialize}\n scrollToBottomOnRunStart={scrollToBottomOnRunStart}\n scrollToBottomOnThreadSwitch={scrollToBottomOnThreadSwitch}\n {...props}\n />\n ),\n);\nThreadMessages.displayName = \"ThreadPrimitive.Messages\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ThreadMessages.js","names":["ComponentType","FC","ForwardedRef","ReactNode","RefObject","forwardRef","memo","useCallback","useEffect","useRef","FlatList","FlatListProps","LayoutChangeEvent","NativeScrollEvent","NativeSyntheticEvent","MessageState","ThreadMessage","RenderChildrenWithAccessor","useAuiEvent","useAuiState","MessageByIndexProvider","MessageComponents","Message","EditComposer","UserEditComposer","AssistantEditComposer","SystemEditComposer","UserMessage","AssistantMessage","SystemMessage","MessagesContent","components","children","value","message","ThreadMessagesFlatListProps","Omit","autoScroll","scrollToBottomOnRunStart","scrollToBottomOnInitialize","scrollToBottomOnThreadSwitch","ThreadMessagesProps","DEFAULT_SYSTEM_MESSAGE","AT_BOTTOM_THRESHOLD","getComponent","role","isEditing","_exhaustiveCheck","Error","ThreadMessageComponent","t0","$","_c","_temp","_temp2","t1","Component","t2","ThreadMessageByIndex","index","prev","next","displayName","ThreadMessageByChildren","aui","thread","getState","getItem","setForwardedRef","ref","T","current","useComposedFlatListRef","forwardedRef","flatListRef","node","setFlatListRef","const","useThreadMessagesFlatListAutoScroll","hasMessages","t3","t4","undefined","t5","Symbol","for","contentHeight","viewportHeight","scrollY","metricsRef","isAtBottomRef","lastScrollEventYRef","initializeScrollRequestedRef","pendingScrollToBottomRef","t6","updateIsAtBottom","t7","animated","contentHeight_0","viewportHeight_0","Math","max","scrollToEnd","scrollToBottom","t8","event","wasAtBottom","previousViewportHeight","viewportHeight_1","nativeEvent","layout","height","pending","handleLayout","t9","event_0","contentOffset","contentSize","layoutMeasurement","previousEventY","wasPinnedToBottom","y","upwardMove","handleScroll","t10","_width","metrics","previousContentHeight","wasAtBottom_0","pendingScroll","handleContentSizeChange","t11","t12","t13","t14","t15","ThreadMessagesFlatList","flatListProps","onContentSizeChange","onLayout","onScroll","scrollEventThrottle","messages","_temp3","length","handleAutoScrollContentSizeChange","handleAutoScrollLayout","handleAutoScrollScroll","renderItem","keyExtractor","_temp4","scrollTracking","width","ThreadMessages","props","s","s_0","composer","item","id"],"sources":["../../../src/primitives/thread/ThreadMessages.tsx"],"sourcesContent":["import {\n type ComponentType,\n type FC,\n type ForwardedRef,\n type ReactNode,\n type RefObject,\n forwardRef,\n memo,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport {\n FlatList,\n type FlatListProps,\n type LayoutChangeEvent,\n type NativeScrollEvent,\n type NativeSyntheticEvent,\n} from \"react-native\";\nimport type { MessageState, ThreadMessage } from \"@assistant-ui/core\";\nimport {\n RenderChildrenWithAccessor,\n useAuiEvent,\n useAuiState,\n} from \"@assistant-ui/store\";\nimport { MessageByIndexProvider } from \"@assistant-ui/core/react\";\n\ntype MessageComponents =\n | {\n Message: ComponentType;\n EditComposer?: ComponentType | undefined;\n UserEditComposer?: ComponentType | undefined;\n AssistantEditComposer?: ComponentType | undefined;\n SystemEditComposer?: ComponentType | undefined;\n UserMessage?: ComponentType | undefined;\n AssistantMessage?: ComponentType | undefined;\n SystemMessage?: ComponentType | undefined;\n }\n | {\n Message?: ComponentType | undefined;\n EditComposer?: ComponentType | undefined;\n UserEditComposer?: ComponentType | undefined;\n AssistantEditComposer?: ComponentType | undefined;\n SystemEditComposer?: ComponentType | undefined;\n UserMessage: ComponentType;\n AssistantMessage: ComponentType;\n SystemMessage?: ComponentType | undefined;\n };\n\ntype MessagesContent =\n | {\n /** @deprecated Use the children render function instead. */\n components: MessageComponents;\n children?: never;\n }\n | {\n children: (value: { message: MessageState }) => ReactNode;\n components?: never;\n };\n\nexport type ThreadMessagesFlatListProps = Omit<\n FlatListProps<ThreadMessage>,\n \"data\" | \"renderItem\" | \"children\"\n> &\n MessagesContent & {\n autoScroll?: boolean | undefined;\n scrollToBottomOnRunStart?: boolean | undefined;\n scrollToBottomOnInitialize?: boolean | undefined;\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n };\n\n/** @deprecated Use ThreadMessagesFlatListProps instead. */\nexport type ThreadMessagesProps = ThreadMessagesFlatListProps;\n\nconst DEFAULT_SYSTEM_MESSAGE = () => null;\nconst AT_BOTTOM_THRESHOLD = 4;\n\nconst getComponent = (\n components: MessageComponents,\n role: ThreadMessage[\"role\"],\n isEditing: boolean,\n) => {\n switch (role) {\n case \"user\":\n if (isEditing) {\n return (\n components.UserEditComposer ??\n components.EditComposer ??\n components.UserMessage ??\n (components.Message as ComponentType)\n );\n } else {\n return components.UserMessage ?? (components.Message as ComponentType);\n }\n case \"assistant\":\n if (isEditing) {\n return (\n components.AssistantEditComposer ??\n components.EditComposer ??\n components.AssistantMessage ??\n (components.Message as ComponentType)\n );\n } else {\n return (\n components.AssistantMessage ?? (components.Message as ComponentType)\n );\n }\n case \"system\":\n if (isEditing) {\n return (\n components.SystemEditComposer ??\n components.EditComposer ??\n components.SystemMessage ??\n (components.Message as ComponentType) ??\n DEFAULT_SYSTEM_MESSAGE\n );\n } else {\n return (\n components.SystemMessage ??\n (components.Message as ComponentType) ??\n DEFAULT_SYSTEM_MESSAGE\n );\n }\n default: {\n const _exhaustiveCheck: never = role;\n throw new Error(`Unknown message role: ${_exhaustiveCheck}`);\n }\n }\n};\n\nconst ThreadMessageComponent: FC<{ components: MessageComponents }> = ({\n components,\n}) => {\n const role = useAuiState((s) => s.message.role);\n const isEditing = useAuiState((s) => s.message.composer.isEditing);\n const Component = getComponent(components, role, isEditing);\n\n return <Component />;\n};\n\nconst ThreadMessageByIndex = memo(\n ({ index, components }: { index: number; components: MessageComponents }) => {\n return (\n <MessageByIndexProvider index={index}>\n <ThreadMessageComponent components={components} />\n </MessageByIndexProvider>\n );\n },\n (prev, next) =>\n prev.index === next.index && prev.components === next.components,\n);\nThreadMessageByIndex.displayName = \"ThreadPrimitive.MessageByIndex\";\n\nconst ThreadMessageByChildren = memo(\n ({\n index,\n children,\n }: {\n index: number;\n children: (value: { message: MessageState }) => ReactNode;\n }) => {\n return (\n <MessageByIndexProvider index={index}>\n <RenderChildrenWithAccessor\n getItemState={(aui) => aui.thread.message({ index }).getState()}\n >\n {(getItem) =>\n children({\n get message() {\n return getItem();\n },\n })\n }\n </RenderChildrenWithAccessor>\n </MessageByIndexProvider>\n );\n },\n (prev, next) => prev.index === next.index && prev.children === next.children,\n);\nThreadMessageByChildren.displayName = \"ThreadPrimitive.MessageByChildren\";\n\nconst setForwardedRef = <T,>(ref: ForwardedRef<T>, value: T | null) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst useComposedFlatListRef = (\n forwardedRef: ForwardedRef<FlatList<ThreadMessage>>,\n) => {\n const flatListRef = useRef<FlatList<ThreadMessage> | null>(null);\n\n const setFlatListRef = useCallback(\n (node: FlatList<ThreadMessage> | null) => {\n flatListRef.current = node;\n setForwardedRef(forwardedRef, node);\n },\n [forwardedRef],\n );\n\n return [flatListRef, setFlatListRef] as const;\n};\n\nconst useThreadMessagesFlatListAutoScroll = ({\n flatListRef,\n hasMessages,\n autoScroll = true,\n scrollToBottomOnRunStart = true,\n scrollToBottomOnInitialize = true,\n scrollToBottomOnThreadSwitch = true,\n}: {\n flatListRef: RefObject<FlatList<ThreadMessage> | null>;\n hasMessages: boolean;\n autoScroll?: boolean | undefined;\n scrollToBottomOnRunStart?: boolean | undefined;\n scrollToBottomOnInitialize?: boolean | undefined;\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n}) => {\n const metricsRef = useRef({\n contentHeight: 0,\n viewportHeight: 0,\n scrollY: 0,\n });\n const isAtBottomRef = useRef(true);\n const lastScrollEventYRef = useRef(0);\n const initializeScrollRequestedRef = useRef(false);\n const pendingScrollToBottomRef = useRef<false | { animated: boolean }>(false);\n\n const updateIsAtBottom = useCallback(() => {\n const { contentHeight, scrollY, viewportHeight } = metricsRef.current;\n isAtBottomRef.current =\n contentHeight <= viewportHeight ||\n contentHeight - scrollY - viewportHeight <= AT_BOTTOM_THRESHOLD;\n }, []);\n\n // Commanding a scroll records the intended position immediately; the\n // native scroll echo is bridged and throttled, so waiting for it lets a\n // fast stream observe stale metrics and drop out of following.\n const scrollToBottom = useCallback(\n (animated: boolean) => {\n const { contentHeight, viewportHeight } = metricsRef.current;\n metricsRef.current.scrollY = Math.max(0, contentHeight - viewportHeight);\n isAtBottomRef.current = true;\n flatListRef.current?.scrollToEnd({ animated });\n },\n [flatListRef],\n );\n\n const handleLayout = useCallback(\n (event: LayoutChangeEvent) => {\n const wasAtBottom = isAtBottomRef.current;\n const previousViewportHeight = metricsRef.current.viewportHeight;\n const viewportHeight = event.nativeEvent.layout.height;\n metricsRef.current.viewportHeight = viewportHeight;\n updateIsAtBottom();\n if (!wasAtBottom) return;\n // Layout changes are never user gestures, so they must not unpin. Past\n // the first measurement, a viewport change while pinned re-commands the\n // bottom position, since no content-size event follows a bare keyboard\n // open or close.\n if (\n autoScroll &&\n previousViewportHeight !== 0 &&\n viewportHeight !== previousViewportHeight\n ) {\n const pending = pendingScrollToBottomRef.current;\n scrollToBottom(pending ? pending.animated : false);\n } else {\n isAtBottomRef.current = true;\n }\n },\n [autoScroll, scrollToBottom, updateIsAtBottom],\n );\n\n const handleScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n const { contentOffset, contentSize, layoutMeasurement } =\n event.nativeEvent;\n const previousEventY = lastScrollEventYRef.current;\n const wasPinnedToBottom = isAtBottomRef.current;\n lastScrollEventYRef.current = contentOffset.y;\n metricsRef.current = {\n contentHeight: contentSize.height,\n viewportHeight: layoutMeasurement.height,\n scrollY: contentOffset.y,\n };\n updateIsAtBottom();\n const upwardMove = contentOffset.y < previousEventY;\n // Only a deliberate upward move unpins or cancels a pending scroll.\n // Gestures are detected echo-to-echo because a commanded scroll\n // optimistically moves the tracked position ahead of its ascending\n // animation echoes, and those echoes must not unpin mid-flight.\n if (wasPinnedToBottom && !upwardMove) {\n isAtBottomRef.current = true;\n }\n if (!isAtBottomRef.current && upwardMove) {\n pendingScrollToBottomRef.current = false;\n }\n },\n [updateIsAtBottom],\n );\n\n const handleContentSizeChange = useCallback(\n (_width: number, height: number) => {\n const metrics = metricsRef.current;\n const previousContentHeight = metrics.contentHeight;\n const wasAtBottom = isAtBottomRef.current;\n metrics.contentHeight = height;\n updateIsAtBottom();\n\n // FlatList.scrollToEnd is a no-op before the list has measured, so the\n // initialize and thread-switch scrolls land on the next content-size\n // event, once real metrics exist.\n const pendingScroll = pendingScrollToBottomRef.current;\n if (pendingScroll) {\n pendingScrollToBottomRef.current = false;\n scrollToBottom(pendingScroll.animated);\n return;\n }\n\n if (!autoScroll) return;\n if (!wasAtBottom) return;\n if (previousContentHeight === 0) return;\n if (height <= previousContentHeight) return;\n\n scrollToBottom(false);\n },\n [autoScroll, scrollToBottom, updateIsAtBottom],\n );\n\n useEffect(() => {\n if (!scrollToBottomOnInitialize) return;\n if (!hasMessages) {\n initializeScrollRequestedRef.current = false;\n return;\n }\n if (initializeScrollRequestedRef.current) return;\n\n initializeScrollRequestedRef.current = true;\n pendingScrollToBottomRef.current = { animated: false };\n scrollToBottom(false);\n }, [hasMessages, scrollToBottom, scrollToBottomOnInitialize]);\n\n useAuiEvent(\"thread.runStart\", () => {\n if (!scrollToBottomOnRunStart) return;\n pendingScrollToBottomRef.current = { animated: true };\n scrollToBottom(true);\n });\n\n useAuiEvent(\"threads.selectionChanged\", () => {\n if (!scrollToBottomOnThreadSwitch) return;\n initializeScrollRequestedRef.current = false;\n lastScrollEventYRef.current = 0;\n pendingScrollToBottomRef.current = { animated: false };\n scrollToBottom(false);\n });\n\n return {\n handleLayout,\n handleScroll,\n handleContentSizeChange,\n };\n};\n\nexport const ThreadMessagesFlatList = forwardRef<\n FlatList<ThreadMessage>,\n ThreadMessagesFlatListProps\n>(\n (\n {\n autoScroll,\n components,\n children,\n onContentSizeChange,\n onLayout,\n onScroll,\n scrollEventThrottle,\n scrollToBottomOnInitialize,\n scrollToBottomOnRunStart,\n scrollToBottomOnThreadSwitch,\n ...flatListProps\n },\n forwardedRef,\n ) => {\n const messages = useAuiState((s) => s.thread.messages);\n const [flatListRef, setFlatListRef] = useComposedFlatListRef(forwardedRef);\n const {\n handleContentSizeChange: handleAutoScrollContentSizeChange,\n handleLayout: handleAutoScrollLayout,\n handleScroll: handleAutoScrollScroll,\n } = useThreadMessagesFlatListAutoScroll({\n flatListRef,\n hasMessages: messages.length > 0,\n autoScroll,\n scrollToBottomOnInitialize,\n scrollToBottomOnRunStart,\n scrollToBottomOnThreadSwitch,\n });\n\n const renderItem = useCallback(\n ({ index }: { item: ThreadMessage; index: number }) => {\n if (children) {\n return (\n <ThreadMessageByChildren index={index}>\n {children}\n </ThreadMessageByChildren>\n );\n }\n return <ThreadMessageByIndex index={index} components={components!} />;\n },\n [components, children],\n );\n\n const keyExtractor = useCallback((item: ThreadMessage) => item.id, []);\n\n const scrollTracking =\n (autoScroll ?? true) ||\n (scrollToBottomOnInitialize ?? true) ||\n (scrollToBottomOnRunStart ?? true) ||\n (scrollToBottomOnThreadSwitch ?? true);\n\n const handleLayout = useCallback(\n (event: LayoutChangeEvent) => {\n handleAutoScrollLayout(event);\n onLayout?.(event);\n },\n [handleAutoScrollLayout, onLayout],\n );\n\n const handleScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n handleAutoScrollScroll(event);\n onScroll?.(event);\n },\n [handleAutoScrollScroll, onScroll],\n );\n\n const handleContentSizeChange = useCallback(\n (width: number, height: number) => {\n handleAutoScrollContentSizeChange(width, height);\n onContentSizeChange?.(width, height);\n },\n [handleAutoScrollContentSizeChange, onContentSizeChange],\n );\n\n return (\n <FlatList\n ref={setFlatListRef}\n data={messages as unknown as ThreadMessage[]}\n renderItem={renderItem}\n keyExtractor={keyExtractor}\n {...(scrollTracking\n ? {\n onContentSizeChange: handleContentSizeChange,\n onLayout: handleLayout,\n onScroll: handleScroll,\n scrollEventThrottle: scrollEventThrottle ?? 16,\n }\n : {\n ...(onContentSizeChange && { onContentSizeChange }),\n ...(onLayout && { onLayout }),\n ...(onScroll && { onScroll }),\n ...(scrollEventThrottle !== undefined && { scrollEventThrottle }),\n })}\n {...flatListProps}\n />\n );\n },\n);\nThreadMessagesFlatList.displayName = \"ThreadPrimitive.MessagesFlatList\";\n\n/** @deprecated Use ThreadPrimitive.MessagesFlatList instead. */\nexport const ThreadMessages = forwardRef<\n FlatList<ThreadMessage>,\n ThreadMessagesProps\n>(\n (\n {\n autoScroll = false,\n scrollToBottomOnInitialize = false,\n scrollToBottomOnRunStart = false,\n scrollToBottomOnThreadSwitch = false,\n ...props\n },\n ref,\n ) => (\n <ThreadMessagesFlatList\n ref={ref}\n autoScroll={autoScroll}\n scrollToBottomOnInitialize={scrollToBottomOnInitialize}\n scrollToBottomOnRunStart={scrollToBottomOnRunStart}\n scrollToBottomOnThreadSwitch={scrollToBottomOnThreadSwitch}\n {...props}\n />\n ),\n);\nThreadMessages.displayName = \"ThreadPrimitive.Messages\";\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadListItems.d.ts","names":[],"sources":["../../../src/primitives/threadList/ThreadListItems.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ThreadListItems.d.ts","names":[],"sources":["../../../src/primitives/threadList/ThreadListItems.tsx"],"mappings":";;;KAKY,uBAAuB,KACjC;EAGA,aAAa;IAAS;IAAkB;QAAoB;;cAGjD,oBAAmB,eAAA,iBAG7B,yCAAoB,IAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useAuiState } from "@assistant-ui/store";
|
|
2
|
+
import { ThreadListItemByIndexProvider } from "@assistant-ui/core/react";
|
|
2
3
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
3
4
|
import { FlatList } from "react-native";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -22,9 +23,13 @@ const ThreadListItems = (t0) => {
|
|
|
22
23
|
if ($[3] !== renderItem) {
|
|
23
24
|
t1 = (t2) => {
|
|
24
25
|
const { item, index } = t2;
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
return /* @__PURE__ */ jsx(ThreadListItemByIndexProvider, {
|
|
27
|
+
index,
|
|
28
|
+
archived: false,
|
|
29
|
+
children: renderItem({
|
|
30
|
+
threadId: item,
|
|
31
|
+
index
|
|
32
|
+
})
|
|
28
33
|
});
|
|
29
34
|
};
|
|
30
35
|
$[3] = renderItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadListItems.js","names":["ReactElement","useCallback","FlatList","FlatListProps","useAuiState","ThreadListItemsProps","Omit","renderItem","props","threadId","index","ThreadListItems","t0","$","_c","flatListProps","threadIds","_temp","t1","t2","item","renderFlatListItem","keyExtractor","_temp2","t3","s","threads","item_0"],"sources":["../../../src/primitives/threadList/ThreadListItems.tsx"],"sourcesContent":["import { type ReactElement, useCallback } from \"react\";\nimport { FlatList, type FlatListProps } from \"react-native\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport type ThreadListItemsProps = Omit<\n FlatListProps<string>,\n \"data\" | \"renderItem\"\n> & {\n renderItem: (props: { threadId: string; index: number }) => ReactElement;\n};\n\nexport const ThreadListItems = ({\n renderItem,\n ...flatListProps\n}: ThreadListItemsProps) => {\n const threadIds = useAuiState((s) => s.threads.threadIds);\n\n const renderFlatListItem = useCallback(\n ({ item, index }: { item: string; index: number }) => {\n return renderItem({ threadId: item, index });\n },\n [renderItem],\n );\n\n const keyExtractor = useCallback((item: string) => item, []);\n\n return (\n <FlatList\n data={threadIds as string[]}\n renderItem={renderFlatListItem}\n keyExtractor={keyExtractor}\n {...flatListProps}\n />\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ThreadListItems.js","names":["ReactElement","useCallback","FlatList","FlatListProps","useAuiState","ThreadListItemByIndexProvider","ThreadListItemsProps","Omit","renderItem","props","threadId","index","ThreadListItems","t0","$","_c","flatListProps","threadIds","_temp","t1","t2","item","renderFlatListItem","keyExtractor","_temp2","t3","s","threads","item_0"],"sources":["../../../src/primitives/threadList/ThreadListItems.tsx"],"sourcesContent":["import { type ReactElement, useCallback } from \"react\";\nimport { FlatList, type FlatListProps } from \"react-native\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { ThreadListItemByIndexProvider } from \"@assistant-ui/core/react\";\n\nexport type ThreadListItemsProps = Omit<\n FlatListProps<string>,\n \"data\" | \"renderItem\"\n> & {\n renderItem: (props: { threadId: string; index: number }) => ReactElement;\n};\n\nexport const ThreadListItems = ({\n renderItem,\n ...flatListProps\n}: ThreadListItemsProps) => {\n const threadIds = useAuiState((s) => s.threads.threadIds);\n\n const renderFlatListItem = useCallback(\n ({ item, index }: { item: string; index: number }) => {\n return (\n <ThreadListItemByIndexProvider index={index} archived={false}>\n {renderItem({ threadId: item, index })}\n </ThreadListItemByIndexProvider>\n );\n },\n [renderItem],\n );\n\n const keyExtractor = useCallback((item: string) => item, []);\n\n return (\n <FlatList\n data={threadIds as string[]}\n renderItem={renderFlatListItem}\n keyExtractor={keyExtractor}\n {...flatListProps}\n />\n );\n};\n"],"mappings":";;;;;;;AAYA,MAAaY,mBAAkBC,OAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAC;CAAA,IAAAR;CAAA,IAAAM,EAAA,OAAAD,IAAA;EAAC,CAAA,CAAAL,eAAAQ,iBAAAH;EAGTC,EAAA,KAAAD;EAAAC,EAAA,KAAAE;EAAAF,EAAA,KAAAN;CAAA,OAAA;EAAAQ,gBAAAF,EAAA;EAAAN,aAAAM,EAAA;CAAA;CACrB,MAAAG,YAAkBb,YAAYc,KAA0B;CAAE,IAAAC;CAAA,IAAAL,EAAA,OAAAN,YAAA;EAGxDW,MAAAC,OAAA;GAAC,MAAA,EAAAC,MAAAV,UAAAS;GAAgD,OAE7C,oBAAC,+BAAD;IAAsCT;IAAiB,UAAA;IACpDH,UAAAA,WAAW;KAAAE,UAAYW;KAAIV;IAAQ,CAAC;GADT,CAAA;EAEE;EAEnCG,EAAA,KAAAN;EAAAM,EAAA,KAAAK;CAAA,OAAAA,KAAAL,EAAA;CAPH,MAAAQ,qBAA2BH;CAW3B,MAAAI,eAAqBC;CAIX,MAAAJ,KAAAH;CAAqB,IAAAQ;CAAA,IAAAX,EAAA,OAAAE,iBAAAF,EAAA,OAAAQ,sBAAAR,EAAA,OAAAM,IAAA;EAD7BK,KAAA,oBAAC,UAAD;GACQ,MAAAL;GACME,YAAAA;GACEC;GAAY,GACtBP;EAAa,CAAA;EACjBF,EAAA,KAAAE;EAAAF,EAAA,KAAAQ;EAAAR,EAAA,KAAAM;EAAAN,EAAA,KAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,OALFW;AAKE;AAzByB,SAAAP,MAAAQ,GAAA;CAAA,OAIQA,EAACC,QAAQV;AAAU;AAJ3B,SAAAO,OAAAI,QAAA;CAAA,OAiBsBP;AAAI"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "React Native bindings for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
],
|
|
32
32
|
"sideEffects": false,
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@assistant-ui/core": "^0.3.
|
|
35
|
-
"@assistant-ui/store": "^0.3.
|
|
36
|
-
"@assistant-ui/tap": "^0.9.
|
|
37
|
-
"assistant-stream": "^0.3.
|
|
34
|
+
"@assistant-ui/core": "^0.3.14",
|
|
35
|
+
"@assistant-ui/store": "^0.3.10",
|
|
36
|
+
"@assistant-ui/tap": "^0.9.13",
|
|
37
|
+
"assistant-stream": "^0.3.38",
|
|
38
38
|
"zustand": "^5.0.14"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -48,15 +48,16 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
+
"@babel/core": "^7.29.7",
|
|
51
52
|
"@types/react": "^19.2.18",
|
|
52
53
|
"@types/react-dom": "^19.2.4",
|
|
53
54
|
"jsdom": "^30.0.1",
|
|
54
55
|
"react": "^19.2.8",
|
|
55
56
|
"react-dom": "^19.2.8",
|
|
56
|
-
"react-native": "^0.
|
|
57
|
+
"react-native": "^0.87.0",
|
|
57
58
|
"react-native-web": "^0.21.2",
|
|
58
59
|
"vitest": "^4.1.10",
|
|
59
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
60
|
+
"@assistant-ui/x-buildutils": "0.0.23"
|
|
60
61
|
},
|
|
61
62
|
"publishConfig": {
|
|
62
63
|
"access": "public",
|
|
@@ -315,6 +315,18 @@ describe("ComposerInput", () => {
|
|
|
315
315
|
|
|
316
316
|
expect(onKeyPress).toHaveBeenCalledTimes(2);
|
|
317
317
|
});
|
|
318
|
+
|
|
319
|
+
it("does not submit when the consumer prevents the key event", async () => {
|
|
320
|
+
const input = await mount({
|
|
321
|
+
onKeyPress: (event) => event.preventDefault(),
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
await act(async () => {
|
|
325
|
+
fireKeyDown(input, { key: "Enter" });
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
expect(h.sendSpy).not.toHaveBeenCalled();
|
|
329
|
+
});
|
|
318
330
|
});
|
|
319
331
|
|
|
320
332
|
describe("native", () => {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Platform,
|
|
4
|
-
TextInput,
|
|
5
|
-
type NativeSyntheticEvent,
|
|
6
|
-
type TextInputKeyPressEventData,
|
|
7
|
-
type TextInputProps,
|
|
8
|
-
} from "react-native";
|
|
2
|
+
import { Platform, TextInput, type TextInputProps } from "react-native";
|
|
9
3
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
10
4
|
import { flushTapSync } from "@assistant-ui/tap";
|
|
11
5
|
|
|
6
|
+
type TextInputInstance = React.ComponentRef<typeof TextInput>;
|
|
7
|
+
type TextInputKeyPressEvent = Parameters<
|
|
8
|
+
NonNullable<TextInputProps["onKeyPress"]>
|
|
9
|
+
>[0];
|
|
10
|
+
|
|
12
11
|
export type ComposerInputProps = Omit<
|
|
13
12
|
TextInputProps,
|
|
14
13
|
"value" | "onChangeText"
|
|
@@ -31,7 +30,9 @@ const getWebTextareaMaxHeight = (el: HTMLTextAreaElement) => {
|
|
|
31
30
|
return Number.isFinite(inlineMaxHeight) ? inlineMaxHeight : null;
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
const adjustWebTextareaHeight = (
|
|
33
|
+
const adjustWebTextareaHeight = (
|
|
34
|
+
ref: React.RefObject<TextInputInstance | null>,
|
|
35
|
+
) => {
|
|
35
36
|
if (Platform.OS !== "web") return;
|
|
36
37
|
// On web, the TextInput ref IS the DOM element
|
|
37
38
|
const el = ref.current as unknown as HTMLTextAreaElement | null;
|
|
@@ -62,7 +63,7 @@ export const ComposerInput = ({
|
|
|
62
63
|
}: ComposerInputProps) => {
|
|
63
64
|
const aui = useAui();
|
|
64
65
|
const text = useAuiState((s) => s.composer.text);
|
|
65
|
-
const inputRef = useRef<
|
|
66
|
+
const inputRef = useRef<TextInputInstance>(null);
|
|
66
67
|
|
|
67
68
|
const onChangeText = useCallback(
|
|
68
69
|
(value: string) => {
|
|
@@ -85,17 +86,19 @@ export const ComposerInput = ({
|
|
|
85
86
|
}, [text]);
|
|
86
87
|
|
|
87
88
|
const onKeyPress = useCallback(
|
|
88
|
-
(e:
|
|
89
|
+
(e: TextInputKeyPressEvent) => {
|
|
89
90
|
onKeyPressProp?.(e);
|
|
91
|
+
if (e.isDefaultPrevented()) return;
|
|
90
92
|
|
|
91
93
|
if (Platform.OS !== "web") return;
|
|
92
94
|
if (submitMode !== "enter") return;
|
|
93
95
|
|
|
94
|
-
const nativeEvent =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
const nativeEvent =
|
|
97
|
+
e.nativeEvent as TextInputKeyPressEvent["nativeEvent"] & {
|
|
98
|
+
shiftKey?: boolean;
|
|
99
|
+
isComposing?: boolean;
|
|
100
|
+
keyCode?: number;
|
|
101
|
+
};
|
|
99
102
|
// react-native-web forwards the raw DOM keydown before its own composition guard, so re-check it here (mirrors isEventComposing)
|
|
100
103
|
if (nativeEvent.isComposing || nativeEvent.keyCode === 229) return;
|
|
101
104
|
if (nativeEvent.key === "Enter" && !nativeEvent.shiftKey) {
|
|
@@ -273,6 +273,20 @@ describe("ThreadMessages", () => {
|
|
|
273
273
|
expect(container.querySelector('[data-testid="c-message"]')).toBeNull();
|
|
274
274
|
});
|
|
275
275
|
|
|
276
|
+
it("renders nothing for an editing system role with no system or Message component", async () => {
|
|
277
|
+
h.state.thread.messages = [{ id: "1", role: "system" }];
|
|
278
|
+
h.state.message.role = "system";
|
|
279
|
+
h.state.message.composer.isEditing = true;
|
|
280
|
+
const components = makeComponents() as Record<string, unknown>;
|
|
281
|
+
delete components.SystemEditComposer;
|
|
282
|
+
delete components.EditComposer;
|
|
283
|
+
delete components.SystemMessage;
|
|
284
|
+
delete components.Message;
|
|
285
|
+
await mount({ components: components as never });
|
|
286
|
+
expect(container.querySelector('[data-testid="c-system"]')).toBeNull();
|
|
287
|
+
expect(container.querySelector('[data-testid="c-message"]')).toBeNull();
|
|
288
|
+
});
|
|
289
|
+
|
|
276
290
|
it("throws for an unknown role", async () => {
|
|
277
291
|
h.state.thread.messages = [{ id: "1", role: "ghost" }];
|
|
278
292
|
h.state.message.role = "ghost";
|
|
@@ -354,7 +368,7 @@ describe("ThreadMessages", () => {
|
|
|
354
368
|
props.onContentSizeChange?.(0, 140);
|
|
355
369
|
});
|
|
356
370
|
await emit("thread.runStart");
|
|
357
|
-
await emit("
|
|
371
|
+
await emit("threads.selectionChanged");
|
|
358
372
|
|
|
359
373
|
expect(h.scrollToEnd).not.toHaveBeenCalled();
|
|
360
374
|
});
|
|
@@ -442,7 +456,7 @@ describe("ThreadMessages", () => {
|
|
|
442
456
|
const props = getFlatListProps();
|
|
443
457
|
h.scrollToEnd.mockClear();
|
|
444
458
|
|
|
445
|
-
await emit("
|
|
459
|
+
await emit("threads.selectionChanged");
|
|
446
460
|
expect(h.scrollToEnd).toHaveBeenCalledTimes(1);
|
|
447
461
|
|
|
448
462
|
await act(async () => {
|
|
@@ -560,7 +574,7 @@ describe("ThreadMessages", () => {
|
|
|
560
574
|
await mountFlatList({ components: messageComponents });
|
|
561
575
|
h.scrollToEnd.mockClear();
|
|
562
576
|
|
|
563
|
-
await emit("
|
|
577
|
+
await emit("threads.selectionChanged");
|
|
564
578
|
|
|
565
579
|
expect(h.scrollToEnd).toHaveBeenCalledWith({ animated: false });
|
|
566
580
|
});
|
|
@@ -573,7 +587,7 @@ describe("ThreadMessages", () => {
|
|
|
573
587
|
});
|
|
574
588
|
h.scrollToEnd.mockClear();
|
|
575
589
|
|
|
576
|
-
await emit("
|
|
590
|
+
await emit("threads.selectionChanged");
|
|
577
591
|
|
|
578
592
|
h.state.thread.messages = [
|
|
579
593
|
{ id: "2", role: "user" },
|
|
@@ -111,7 +111,8 @@ const getComponent = (
|
|
|
111
111
|
components.SystemEditComposer ??
|
|
112
112
|
components.EditComposer ??
|
|
113
113
|
components.SystemMessage ??
|
|
114
|
-
(components.Message as ComponentType)
|
|
114
|
+
(components.Message as ComponentType) ??
|
|
115
|
+
DEFAULT_SYSTEM_MESSAGE
|
|
115
116
|
);
|
|
116
117
|
} else {
|
|
117
118
|
return (
|
|
@@ -348,7 +349,7 @@ const useThreadMessagesFlatListAutoScroll = ({
|
|
|
348
349
|
scrollToBottom(true);
|
|
349
350
|
});
|
|
350
351
|
|
|
351
|
-
useAuiEvent("
|
|
352
|
+
useAuiEvent("threads.selectionChanged", () => {
|
|
352
353
|
if (!scrollToBottomOnThreadSwitch) return;
|
|
353
354
|
initializeScrollRequestedRef.current = false;
|
|
354
355
|
lastScrollEventYRef.current = 0;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { act } from "react";
|
|
2
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { Text } from "react-native";
|
|
5
|
+
import { ThreadListItems } from "./ThreadListItems";
|
|
6
|
+
|
|
7
|
+
const h = vi.hoisted(() => ({
|
|
8
|
+
state: { threads: { threadIds: [] as string[] } },
|
|
9
|
+
flatListProps: null as Record<string, unknown> | null,
|
|
10
|
+
providerProps: vi.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
vi.mock("react-native", async (importOriginal) => {
|
|
14
|
+
const actual = await importOriginal<typeof import("react-native")>();
|
|
15
|
+
const React = await import("react");
|
|
16
|
+
|
|
17
|
+
const FlatListMock = React.forwardRef(function FlatListMock(
|
|
18
|
+
props: Record<string, unknown>,
|
|
19
|
+
_ref,
|
|
20
|
+
) {
|
|
21
|
+
h.flatListProps = props;
|
|
22
|
+
|
|
23
|
+
const data = (props.data as unknown[]) ?? [];
|
|
24
|
+
const renderItem = props.renderItem as
|
|
25
|
+
| ((value: { item: unknown; index: number }) => React.ReactNode)
|
|
26
|
+
| undefined;
|
|
27
|
+
const keyExtractor = props.keyExtractor as
|
|
28
|
+
| ((item: unknown, index: number) => string)
|
|
29
|
+
| undefined;
|
|
30
|
+
|
|
31
|
+
return React.createElement(
|
|
32
|
+
"div",
|
|
33
|
+
{ "data-testid": "flatlist" },
|
|
34
|
+
data.map((item, index) =>
|
|
35
|
+
React.createElement(
|
|
36
|
+
"div",
|
|
37
|
+
{ key: keyExtractor?.(item, index) ?? index },
|
|
38
|
+
renderItem?.({ item, index }),
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...actual,
|
|
46
|
+
FlatList: FlatListMock,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
vi.mock("@assistant-ui/store", async (importOriginal) => {
|
|
51
|
+
const actual = await importOriginal<typeof import("@assistant-ui/store")>();
|
|
52
|
+
return {
|
|
53
|
+
...actual,
|
|
54
|
+
useAuiState: <T,>(selector: (s: typeof h.state) => T) => selector(h.state),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
vi.mock("@assistant-ui/core/react", async (importOriginal) => {
|
|
59
|
+
const actual =
|
|
60
|
+
await importOriginal<typeof import("@assistant-ui/core/react")>();
|
|
61
|
+
return {
|
|
62
|
+
...actual,
|
|
63
|
+
ThreadListItemByIndexProvider: ({
|
|
64
|
+
index,
|
|
65
|
+
archived,
|
|
66
|
+
children,
|
|
67
|
+
}: {
|
|
68
|
+
index: number;
|
|
69
|
+
archived: boolean;
|
|
70
|
+
children?: React.ReactNode;
|
|
71
|
+
}) => {
|
|
72
|
+
h.providerProps({ index, archived });
|
|
73
|
+
return <>{children}</>;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
(globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
|
|
79
|
+
|
|
80
|
+
describe("ThreadListItems", () => {
|
|
81
|
+
let container: HTMLDivElement;
|
|
82
|
+
let root: Root;
|
|
83
|
+
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
h.state.threads.threadIds = [];
|
|
86
|
+
h.flatListProps = null;
|
|
87
|
+
h.providerProps.mockReset();
|
|
88
|
+
|
|
89
|
+
container = document.createElement("div");
|
|
90
|
+
document.body.appendChild(container);
|
|
91
|
+
root = createRoot(container);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
afterEach(async () => {
|
|
95
|
+
await act(async () => {
|
|
96
|
+
root.unmount();
|
|
97
|
+
});
|
|
98
|
+
container.remove();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const mount = async (
|
|
102
|
+
props: Partial<Parameters<typeof ThreadListItems>[0]> = {},
|
|
103
|
+
) => {
|
|
104
|
+
await act(async () => {
|
|
105
|
+
root.render(
|
|
106
|
+
<ThreadListItems
|
|
107
|
+
renderItem={({ threadId }) => <Text>{threadId}</Text>}
|
|
108
|
+
{...props}
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
it("wraps each row in ThreadListItemByIndexProvider with its index", async () => {
|
|
115
|
+
h.state.threads.threadIds = ["t-1", "t-2", "t-3"];
|
|
116
|
+
|
|
117
|
+
await mount();
|
|
118
|
+
|
|
119
|
+
expect(h.providerProps.mock.calls.map((call) => call[0])).toEqual([
|
|
120
|
+
{ index: 0, archived: false },
|
|
121
|
+
{ index: 1, archived: false },
|
|
122
|
+
{ index: 2, archived: false },
|
|
123
|
+
]);
|
|
124
|
+
expect(container.textContent).toContain("t-1");
|
|
125
|
+
expect(container.textContent).toContain("t-3");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("passes threadId and index to renderItem", async () => {
|
|
129
|
+
const renderItem = vi.fn(
|
|
130
|
+
({ threadId }: { threadId: string; index: number }) => (
|
|
131
|
+
<Text>{threadId}</Text>
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
h.state.threads.threadIds = ["a", "b"];
|
|
135
|
+
|
|
136
|
+
await mount({ renderItem });
|
|
137
|
+
|
|
138
|
+
expect(renderItem.mock.calls.map((call) => call[0])).toEqual([
|
|
139
|
+
{ threadId: "a", index: 0 },
|
|
140
|
+
{ threadId: "b", index: 1 },
|
|
141
|
+
]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("keys rows by threadId via keyExtractor", async () => {
|
|
145
|
+
h.state.threads.threadIds = ["t-1", "t-2"];
|
|
146
|
+
|
|
147
|
+
await mount();
|
|
148
|
+
|
|
149
|
+
const keyExtractor = h.flatListProps?.keyExtractor as (
|
|
150
|
+
item: string,
|
|
151
|
+
index: number,
|
|
152
|
+
) => string;
|
|
153
|
+
expect(keyExtractor("t-1", 0)).toBe("t-1");
|
|
154
|
+
expect(keyExtractor("t-2", 1)).toBe("t-2");
|
|
155
|
+
expect(h.flatListProps?.data).toEqual(["t-1", "t-2"]);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("forwards extra FlatList props", async () => {
|
|
159
|
+
h.state.threads.threadIds = ["t-1"];
|
|
160
|
+
|
|
161
|
+
await mount({ horizontal: true, testID: "thread-list" });
|
|
162
|
+
|
|
163
|
+
expect(h.flatListProps?.horizontal).toBe(true);
|
|
164
|
+
expect(h.flatListProps?.testID).toBe("thread-list");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactElement, useCallback } from "react";
|
|
2
2
|
import { FlatList, type FlatListProps } from "react-native";
|
|
3
3
|
import { useAuiState } from "@assistant-ui/store";
|
|
4
|
+
import { ThreadListItemByIndexProvider } from "@assistant-ui/core/react";
|
|
4
5
|
|
|
5
6
|
export type ThreadListItemsProps = Omit<
|
|
6
7
|
FlatListProps<string>,
|
|
@@ -17,7 +18,11 @@ export const ThreadListItems = ({
|
|
|
17
18
|
|
|
18
19
|
const renderFlatListItem = useCallback(
|
|
19
20
|
({ item, index }: { item: string; index: number }) => {
|
|
20
|
-
return
|
|
21
|
+
return (
|
|
22
|
+
<ThreadListItemByIndexProvider index={index} archived={false}>
|
|
23
|
+
{renderItem({ threadId: item, index })}
|
|
24
|
+
</ThreadListItemByIndexProvider>
|
|
25
|
+
);
|
|
21
26
|
},
|
|
22
27
|
[renderItem],
|
|
23
28
|
);
|