@crafter/rn-ai-elements 0.0.1
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/lib/commonjs/chatbot/AIImage.js +126 -0
- package/lib/commonjs/chatbot/AIImage.js.map +1 -0
- package/lib/commonjs/chatbot/Attachments.js +317 -0
- package/lib/commonjs/chatbot/Attachments.js.map +1 -0
- package/lib/commonjs/chatbot/ChatErrorBoundary.js +201 -0
- package/lib/commonjs/chatbot/ChatErrorBoundary.js.map +1 -0
- package/lib/commonjs/chatbot/ChatMessageItem.js +169 -0
- package/lib/commonjs/chatbot/ChatMessageItem.js.map +1 -0
- package/lib/commonjs/chatbot/Conversation.js +415 -0
- package/lib/commonjs/chatbot/Conversation.js.map +1 -0
- package/lib/commonjs/chatbot/ConversationScrollButton.js +131 -0
- package/lib/commonjs/chatbot/ConversationScrollButton.js.map +1 -0
- package/lib/commonjs/chatbot/Message.js +203 -0
- package/lib/commonjs/chatbot/Message.js.map +1 -0
- package/lib/commonjs/chatbot/PromptInput.js +352 -0
- package/lib/commonjs/chatbot/PromptInput.js.map +1 -0
- package/lib/commonjs/chatbot/Reasoning.js +184 -0
- package/lib/commonjs/chatbot/Reasoning.js.map +1 -0
- package/lib/commonjs/chatbot/Shimmer.js +116 -0
- package/lib/commonjs/chatbot/Shimmer.js.map +1 -0
- package/lib/commonjs/chatbot/Sources.js +212 -0
- package/lib/commonjs/chatbot/Sources.js.map +1 -0
- package/lib/commonjs/chatbot/Suggestion.js +99 -0
- package/lib/commonjs/chatbot/Suggestion.js.map +1 -0
- package/lib/commonjs/chatbot/Tool.js +307 -0
- package/lib/commonjs/chatbot/Tool.js.map +1 -0
- package/lib/commonjs/chatbot/adapters/uiMessageAdapter.js +141 -0
- package/lib/commonjs/chatbot/adapters/uiMessageAdapter.js.map +1 -0
- package/lib/commonjs/chatbot/index.js +140 -0
- package/lib/commonjs/chatbot/index.js.map +1 -0
- package/lib/commonjs/chatbot/types.js +6 -0
- package/lib/commonjs/chatbot/types.js.map +1 -0
- package/lib/commonjs/hooks/index.js +34 -0
- package/lib/commonjs/hooks/index.js.map +1 -0
- package/lib/commonjs/hooks/useAutoScroll.js +39 -0
- package/lib/commonjs/hooks/useAutoScroll.js.map +1 -0
- package/lib/commonjs/hooks/useClipboard.js +44 -0
- package/lib/commonjs/hooks/useClipboard.js.map +1 -0
- package/lib/commonjs/hooks/useCollapsible.js +35 -0
- package/lib/commonjs/hooks/useCollapsible.js.map +1 -0
- package/lib/commonjs/hooks/useStickToBottom.js +68 -0
- package/lib/commonjs/hooks/useStickToBottom.js.map +1 -0
- package/lib/commonjs/index.js +257 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/primitives/Badge.js +119 -0
- package/lib/commonjs/primitives/Badge.js.map +1 -0
- package/lib/commonjs/primitives/Button.js +185 -0
- package/lib/commonjs/primitives/Button.js.map +1 -0
- package/lib/commonjs/primitives/Card.js +166 -0
- package/lib/commonjs/primitives/Card.js.map +1 -0
- package/lib/commonjs/primitives/Collapsible.js +137 -0
- package/lib/commonjs/primitives/Collapsible.js.map +1 -0
- package/lib/commonjs/primitives/ScrollArea.js +40 -0
- package/lib/commonjs/primitives/ScrollArea.js.map +1 -0
- package/lib/commonjs/primitives/index.js +83 -0
- package/lib/commonjs/primitives/index.js.map +1 -0
- package/lib/commonjs/streaming/StreamingMarkdown.js +252 -0
- package/lib/commonjs/streaming/StreamingMarkdown.js.map +1 -0
- package/lib/commonjs/streaming/index.js +13 -0
- package/lib/commonjs/streaming/index.js.map +1 -0
- package/lib/commonjs/streaming/parser.js +482 -0
- package/lib/commonjs/streaming/parser.js.map +1 -0
- package/lib/commonjs/streaming/renderers/BlockquoteRenderer.js +35 -0
- package/lib/commonjs/streaming/renderers/BlockquoteRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/CodeRenderer.js +128 -0
- package/lib/commonjs/streaming/renderers/CodeRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/HeadingRenderer.js +61 -0
- package/lib/commonjs/streaming/renderers/HeadingRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/ImageRenderer.js +53 -0
- package/lib/commonjs/streaming/renderers/ImageRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/LinkRenderer.js +49 -0
- package/lib/commonjs/streaming/renderers/LinkRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/ListRenderer.js +63 -0
- package/lib/commonjs/streaming/renderers/ListRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/TableRenderer.js +77 -0
- package/lib/commonjs/streaming/renderers/TableRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/TextRenderer.js +41 -0
- package/lib/commonjs/streaming/renderers/TextRenderer.js.map +1 -0
- package/lib/commonjs/streaming/renderers/index.js +76 -0
- package/lib/commonjs/streaming/renderers/index.js.map +1 -0
- package/lib/commonjs/streaming/renderers/renderInlineChildren.js +112 -0
- package/lib/commonjs/streaming/renderers/renderInlineChildren.js.map +1 -0
- package/lib/commonjs/streaming/renderers/renderNode.js +81 -0
- package/lib/commonjs/streaming/renderers/renderNode.js.map +1 -0
- package/lib/commonjs/theme/ThemeProvider.js +68 -0
- package/lib/commonjs/theme/ThemeProvider.js.map +1 -0
- package/lib/commonjs/theme/defaultTheme.js +96 -0
- package/lib/commonjs/theme/defaultTheme.js.map +1 -0
- package/lib/commonjs/theme/index.js +32 -0
- package/lib/commonjs/theme/index.js.map +1 -0
- package/lib/commonjs/theme/tokens.js +2 -0
- package/lib/commonjs/theme/tokens.js.map +1 -0
- package/lib/commonjs/types.d.js +2 -0
- package/lib/commonjs/types.d.js.map +1 -0
- package/lib/commonjs/voice/index.js +13 -0
- package/lib/commonjs/voice/index.js.map +1 -0
- package/lib/commonjs/voice/useSpeechRecognition.js +172 -0
- package/lib/commonjs/voice/useSpeechRecognition.js.map +1 -0
- package/lib/module/chatbot/AIImage.js +121 -0
- package/lib/module/chatbot/AIImage.js.map +1 -0
- package/lib/module/chatbot/Attachments.js +312 -0
- package/lib/module/chatbot/Attachments.js.map +1 -0
- package/lib/module/chatbot/ChatErrorBoundary.js +196 -0
- package/lib/module/chatbot/ChatErrorBoundary.js.map +1 -0
- package/lib/module/chatbot/ChatMessageItem.js +164 -0
- package/lib/module/chatbot/ChatMessageItem.js.map +1 -0
- package/lib/module/chatbot/Conversation.js +412 -0
- package/lib/module/chatbot/Conversation.js.map +1 -0
- package/lib/module/chatbot/ConversationScrollButton.js +126 -0
- package/lib/module/chatbot/ConversationScrollButton.js.map +1 -0
- package/lib/module/chatbot/Message.js +198 -0
- package/lib/module/chatbot/Message.js.map +1 -0
- package/lib/module/chatbot/PromptInput.js +347 -0
- package/lib/module/chatbot/PromptInput.js.map +1 -0
- package/lib/module/chatbot/Reasoning.js +179 -0
- package/lib/module/chatbot/Reasoning.js.map +1 -0
- package/lib/module/chatbot/Shimmer.js +111 -0
- package/lib/module/chatbot/Shimmer.js.map +1 -0
- package/lib/module/chatbot/Sources.js +207 -0
- package/lib/module/chatbot/Sources.js.map +1 -0
- package/lib/module/chatbot/Suggestion.js +94 -0
- package/lib/module/chatbot/Suggestion.js.map +1 -0
- package/lib/module/chatbot/Tool.js +303 -0
- package/lib/module/chatbot/Tool.js.map +1 -0
- package/lib/module/chatbot/adapters/uiMessageAdapter.js +137 -0
- package/lib/module/chatbot/adapters/uiMessageAdapter.js.map +1 -0
- package/lib/module/chatbot/index.js +39 -0
- package/lib/module/chatbot/index.js.map +1 -0
- package/lib/module/chatbot/types.js +4 -0
- package/lib/module/chatbot/types.js.map +1 -0
- package/lib/module/hooks/index.js +7 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/useAutoScroll.js +35 -0
- package/lib/module/hooks/useAutoScroll.js.map +1 -0
- package/lib/module/hooks/useClipboard.js +40 -0
- package/lib/module/hooks/useClipboard.js.map +1 -0
- package/lib/module/hooks/useCollapsible.js +31 -0
- package/lib/module/hooks/useCollapsible.js.map +1 -0
- package/lib/module/hooks/useStickToBottom.js +64 -0
- package/lib/module/hooks/useStickToBottom.js.map +1 -0
- package/lib/module/index.js +19 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/primitives/Badge.js +114 -0
- package/lib/module/primitives/Badge.js.map +1 -0
- package/lib/module/primitives/Button.js +180 -0
- package/lib/module/primitives/Button.js.map +1 -0
- package/lib/module/primitives/Card.js +156 -0
- package/lib/module/primitives/Card.js.map +1 -0
- package/lib/module/primitives/Collapsible.js +130 -0
- package/lib/module/primitives/Collapsible.js.map +1 -0
- package/lib/module/primitives/ScrollArea.js +35 -0
- package/lib/module/primitives/ScrollArea.js.map +1 -0
- package/lib/module/primitives/index.js +8 -0
- package/lib/module/primitives/index.js.map +1 -0
- package/lib/module/streaming/StreamingMarkdown.js +246 -0
- package/lib/module/streaming/StreamingMarkdown.js.map +1 -0
- package/lib/module/streaming/index.js +4 -0
- package/lib/module/streaming/index.js.map +1 -0
- package/lib/module/streaming/parser.js +477 -0
- package/lib/module/streaming/parser.js.map +1 -0
- package/lib/module/streaming/renderers/BlockquoteRenderer.js +30 -0
- package/lib/module/streaming/renderers/BlockquoteRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/CodeRenderer.js +123 -0
- package/lib/module/streaming/renderers/CodeRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/HeadingRenderer.js +56 -0
- package/lib/module/streaming/renderers/HeadingRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/ImageRenderer.js +48 -0
- package/lib/module/streaming/renderers/ImageRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/LinkRenderer.js +44 -0
- package/lib/module/streaming/renderers/LinkRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/ListRenderer.js +58 -0
- package/lib/module/streaming/renderers/ListRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/TableRenderer.js +72 -0
- package/lib/module/streaming/renderers/TableRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/TextRenderer.js +36 -0
- package/lib/module/streaming/renderers/TextRenderer.js.map +1 -0
- package/lib/module/streaming/renderers/index.js +13 -0
- package/lib/module/streaming/renderers/index.js.map +1 -0
- package/lib/module/streaming/renderers/renderInlineChildren.js +107 -0
- package/lib/module/streaming/renderers/renderInlineChildren.js.map +1 -0
- package/lib/module/streaming/renderers/renderNode.js +78 -0
- package/lib/module/streaming/renderers/renderNode.js.map +1 -0
- package/lib/module/theme/ThemeProvider.js +62 -0
- package/lib/module/theme/ThemeProvider.js.map +1 -0
- package/lib/module/theme/defaultTheme.js +92 -0
- package/lib/module/theme/defaultTheme.js.map +1 -0
- package/lib/module/theme/index.js +5 -0
- package/lib/module/theme/index.js.map +1 -0
- package/lib/module/theme/tokens.js +2 -0
- package/lib/module/theme/tokens.js.map +1 -0
- package/lib/module/types.d.js +2 -0
- package/lib/module/types.d.js.map +1 -0
- package/lib/module/voice/index.js +14 -0
- package/lib/module/voice/index.js.map +1 -0
- package/lib/module/voice/useSpeechRecognition.js +169 -0
- package/lib/module/voice/useSpeechRecognition.js.map +1 -0
- package/lib/typescript/src/chatbot/AIImage.d.ts +24 -0
- package/lib/typescript/src/chatbot/AIImage.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Attachments.d.ts +20 -0
- package/lib/typescript/src/chatbot/Attachments.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/ChatErrorBoundary.d.ts +57 -0
- package/lib/typescript/src/chatbot/ChatErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/ChatMessageItem.d.ts +45 -0
- package/lib/typescript/src/chatbot/ChatMessageItem.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Conversation.d.ts +94 -0
- package/lib/typescript/src/chatbot/Conversation.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/ConversationScrollButton.d.ts +62 -0
- package/lib/typescript/src/chatbot/ConversationScrollButton.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Message.d.ts +39 -0
- package/lib/typescript/src/chatbot/Message.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/PromptInput.d.ts +93 -0
- package/lib/typescript/src/chatbot/PromptInput.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Reasoning.d.ts +14 -0
- package/lib/typescript/src/chatbot/Reasoning.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Shimmer.d.ts +13 -0
- package/lib/typescript/src/chatbot/Shimmer.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Sources.d.ts +17 -0
- package/lib/typescript/src/chatbot/Sources.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Suggestion.d.ts +15 -0
- package/lib/typescript/src/chatbot/Suggestion.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/Tool.d.ts +30 -0
- package/lib/typescript/src/chatbot/Tool.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/adapters/uiMessageAdapter.d.ts +24 -0
- package/lib/typescript/src/chatbot/adapters/uiMessageAdapter.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/index.d.ts +29 -0
- package/lib/typescript/src/chatbot/index.d.ts.map +1 -0
- package/lib/typescript/src/chatbot/types.d.ts +49 -0
- package/lib/typescript/src/chatbot/types.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +9 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useAutoScroll.d.ts +23 -0
- package/lib/typescript/src/hooks/useAutoScroll.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useClipboard.d.ts +22 -0
- package/lib/typescript/src/hooks/useClipboard.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useCollapsible.d.ts +28 -0
- package/lib/typescript/src/hooks/useCollapsible.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useStickToBottom.d.ts +39 -0
- package/lib/typescript/src/hooks/useStickToBottom.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +11 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/primitives/Badge.d.ts +10 -0
- package/lib/typescript/src/primitives/Badge.d.ts.map +1 -0
- package/lib/typescript/src/primitives/Button.d.ts +16 -0
- package/lib/typescript/src/primitives/Button.d.ts.map +1 -0
- package/lib/typescript/src/primitives/Card.d.ts +33 -0
- package/lib/typescript/src/primitives/Card.d.ts.map +1 -0
- package/lib/typescript/src/primitives/Collapsible.d.ts +20 -0
- package/lib/typescript/src/primitives/Collapsible.d.ts.map +1 -0
- package/lib/typescript/src/primitives/ScrollArea.d.ts +10 -0
- package/lib/typescript/src/primitives/ScrollArea.d.ts.map +1 -0
- package/lib/typescript/src/primitives/index.d.ts +11 -0
- package/lib/typescript/src/primitives/index.d.ts.map +1 -0
- package/lib/typescript/src/streaming/StreamingMarkdown.d.ts +47 -0
- package/lib/typescript/src/streaming/StreamingMarkdown.d.ts.map +1 -0
- package/lib/typescript/src/streaming/index.d.ts +3 -0
- package/lib/typescript/src/streaming/index.d.ts.map +1 -0
- package/lib/typescript/src/streaming/parser.d.ts +41 -0
- package/lib/typescript/src/streaming/parser.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/BlockquoteRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/BlockquoteRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/CodeRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/CodeRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/HeadingRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/HeadingRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/ImageRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/ImageRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/LinkRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/LinkRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/ListRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/ListRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/TableRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/TableRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/TextRenderer.d.ts +7 -0
- package/lib/typescript/src/streaming/renderers/TextRenderer.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/index.d.ts +19 -0
- package/lib/typescript/src/streaming/renderers/index.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/renderInlineChildren.d.ts +12 -0
- package/lib/typescript/src/streaming/renderers/renderInlineChildren.d.ts.map +1 -0
- package/lib/typescript/src/streaming/renderers/renderNode.d.ts +8 -0
- package/lib/typescript/src/streaming/renderers/renderNode.d.ts.map +1 -0
- package/lib/typescript/src/theme/ThemeProvider.d.ts +14 -0
- package/lib/typescript/src/theme/ThemeProvider.d.ts.map +1 -0
- package/lib/typescript/src/theme/defaultTheme.d.ts +4 -0
- package/lib/typescript/src/theme/defaultTheme.d.ts.map +1 -0
- package/lib/typescript/src/theme/index.d.ts +5 -0
- package/lib/typescript/src/theme/index.d.ts.map +1 -0
- package/lib/typescript/src/theme/tokens.d.ts +66 -0
- package/lib/typescript/src/theme/tokens.d.ts.map +1 -0
- package/lib/typescript/src/voice/index.d.ts +3 -0
- package/lib/typescript/src/voice/index.d.ts.map +1 -0
- package/lib/typescript/src/voice/useSpeechRecognition.d.ts +77 -0
- package/lib/typescript/src/voice/useSpeechRecognition.d.ts.map +1 -0
- package/package.json +132 -0
- package/src/chatbot/AIImage.tsx +166 -0
- package/src/chatbot/Attachments.tsx +382 -0
- package/src/chatbot/ChatErrorBoundary.tsx +230 -0
- package/src/chatbot/ChatMessageItem.tsx +195 -0
- package/src/chatbot/Conversation.tsx +537 -0
- package/src/chatbot/ConversationScrollButton.tsx +149 -0
- package/src/chatbot/Message.tsx +266 -0
- package/src/chatbot/PromptInput.tsx +532 -0
- package/src/chatbot/Reasoning.tsx +198 -0
- package/src/chatbot/Shimmer.tsx +146 -0
- package/src/chatbot/Sources.tsx +263 -0
- package/src/chatbot/Suggestion.tsx +123 -0
- package/src/chatbot/Tool.tsx +340 -0
- package/src/chatbot/adapters/uiMessageAdapter.ts +177 -0
- package/src/chatbot/index.ts +97 -0
- package/src/chatbot/types.ts +66 -0
- package/src/hooks/index.ts +17 -0
- package/src/hooks/useAutoScroll.ts +43 -0
- package/src/hooks/useClipboard.ts +46 -0
- package/src/hooks/useCollapsible.ts +42 -0
- package/src/hooks/useStickToBottom.ts +82 -0
- package/src/index.ts +139 -0
- package/src/primitives/Badge.tsx +119 -0
- package/src/primitives/Button.tsx +213 -0
- package/src/primitives/Card.tsx +221 -0
- package/src/primitives/Collapsible.tsx +168 -0
- package/src/primitives/ScrollArea.tsx +53 -0
- package/src/primitives/index.ts +36 -0
- package/src/streaming/StreamingMarkdown.tsx +282 -0
- package/src/streaming/index.ts +2 -0
- package/src/streaming/parser.ts +506 -0
- package/src/streaming/renderers/BlockquoteRenderer.tsx +42 -0
- package/src/streaming/renderers/CodeRenderer.tsx +158 -0
- package/src/streaming/renderers/HeadingRenderer.tsx +64 -0
- package/src/streaming/renderers/ImageRenderer.tsx +62 -0
- package/src/streaming/renderers/LinkRenderer.tsx +53 -0
- package/src/streaming/renderers/ListRenderer.tsx +65 -0
- package/src/streaming/renderers/TableRenderer.tsx +103 -0
- package/src/streaming/renderers/TextRenderer.tsx +39 -0
- package/src/streaming/renderers/index.ts +26 -0
- package/src/streaming/renderers/renderInlineChildren.tsx +115 -0
- package/src/streaming/renderers/renderNode.tsx +72 -0
- package/src/theme/ThemeProvider.tsx +77 -0
- package/src/theme/defaultTheme.ts +93 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/tokens.ts +69 -0
- package/src/types.d.ts +71 -0
- package/src/voice/index.ts +15 -0
- package/src/voice/useSpeechRecognition.ts +230 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import React, { Component, type ReactNode } from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import { RotateCcw } from 'lucide-react-native';
|
|
4
|
+
import { useAIElementsTheme, type AIElementsTheme } from '../theme';
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Types
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
export interface ChatErrorBoundaryProps {
|
|
11
|
+
/** The protected subtree. Errors thrown during render are caught here. */
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Optional custom fallback. Receives the caught error and a reset
|
|
15
|
+
* callback that clears the boundary back to the children.
|
|
16
|
+
*/
|
|
17
|
+
fallback?: (error: Error, reset: () => void) => ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Called once when the boundary catches an error. Useful for forwarding
|
|
20
|
+
* to crash reporting (Sentry, Bugsnag, etc).
|
|
21
|
+
*/
|
|
22
|
+
onError?: (error: Error, errorInfo: { componentStack: string }) => void;
|
|
23
|
+
/**
|
|
24
|
+
* When any value in this array changes between renders, the boundary
|
|
25
|
+
* automatically resets. Use this for cases like "the user navigated to a
|
|
26
|
+
* new message id" — re-rendering with a different id should clear a
|
|
27
|
+
* previously caught error.
|
|
28
|
+
*/
|
|
29
|
+
resetKeys?: ReadonlyArray<unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface ChatErrorBoundaryState {
|
|
33
|
+
error: Error | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Helpers
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
function arraysShallowEqual(
|
|
41
|
+
a: ReadonlyArray<unknown> | undefined,
|
|
42
|
+
b: ReadonlyArray<unknown> | undefined,
|
|
43
|
+
): boolean {
|
|
44
|
+
if (a === b) return true;
|
|
45
|
+
if (!a || !b) return false;
|
|
46
|
+
if (a.length !== b.length) return false;
|
|
47
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
48
|
+
if (a[i] !== b[i]) return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Error boundary
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Class-component boundary that wraps individual chat messages. If a single
|
|
59
|
+
* message's render throws (e.g. malformed markdown, a tool call with bad
|
|
60
|
+
* JSON), only that bubble shows a fallback — the rest of the conversation
|
|
61
|
+
* keeps working.
|
|
62
|
+
*
|
|
63
|
+
* React doesn't expose hooks for error boundaries, so this **must** stay a
|
|
64
|
+
* class component. The themed fallback is delegated to a sibling functional
|
|
65
|
+
* component so it can read the theme via hooks.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* <ChatErrorBoundary resetKeys={[message.id]}>
|
|
70
|
+
* <MessageRenderer message={message} />
|
|
71
|
+
* </ChatErrorBoundary>
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export class ChatErrorBoundary extends Component<
|
|
75
|
+
ChatErrorBoundaryProps,
|
|
76
|
+
ChatErrorBoundaryState
|
|
77
|
+
> {
|
|
78
|
+
static displayName = 'ChatErrorBoundary';
|
|
79
|
+
|
|
80
|
+
state: ChatErrorBoundaryState = { error: null };
|
|
81
|
+
|
|
82
|
+
static getDerivedStateFromError(error: Error): ChatErrorBoundaryState {
|
|
83
|
+
return { error };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
componentDidCatch(error: Error, errorInfo: { componentStack: string }) {
|
|
87
|
+
this.props.onError?.(error, errorInfo);
|
|
88
|
+
if (__DEV__) {
|
|
89
|
+
// Format following Expo's what / why / how convention so the warning
|
|
90
|
+
// tells you exactly what to fix instead of just dumping a stack.
|
|
91
|
+
console.warn(
|
|
92
|
+
'[chat-components] A message render threw inside <ChatErrorBoundary>.\n' +
|
|
93
|
+
` what: ${error.message || 'unknown render error'}\n` +
|
|
94
|
+
' why: React unmounted that subtree to prevent a crash.\n' +
|
|
95
|
+
' how: inspect the message payload (markdown / tool args / sources)\n' +
|
|
96
|
+
' below for invalid input. The user can also tap "Retry" to remount.',
|
|
97
|
+
);
|
|
98
|
+
console.error('[chat-components]', error, errorInfo.componentStack);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
componentDidUpdate(prev: ChatErrorBoundaryProps) {
|
|
103
|
+
// Auto-reset if any reset key changed since the last render. This lets
|
|
104
|
+
// callers say "the message id changed, so any error from the previous
|
|
105
|
+
// message no longer applies".
|
|
106
|
+
if (
|
|
107
|
+
this.state.error &&
|
|
108
|
+
!arraysShallowEqual(prev.resetKeys, this.props.resetKeys)
|
|
109
|
+
) {
|
|
110
|
+
this.reset();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
reset = () => {
|
|
115
|
+
this.setState({ error: null });
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
render() {
|
|
119
|
+
const { error } = this.state;
|
|
120
|
+
if (error) {
|
|
121
|
+
if (this.props.fallback) {
|
|
122
|
+
return this.props.fallback(error, this.reset);
|
|
123
|
+
}
|
|
124
|
+
return <DefaultFallback error={error} onReset={this.reset} />;
|
|
125
|
+
}
|
|
126
|
+
return this.props.children;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Default themed fallback
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
interface DefaultFallbackProps {
|
|
135
|
+
error: Error;
|
|
136
|
+
onReset: () => void;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function DefaultFallback({ error, onReset }: DefaultFallbackProps) {
|
|
140
|
+
const theme = useAIElementsTheme();
|
|
141
|
+
const styles = getStyles(theme);
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<View
|
|
145
|
+
style={styles.wrapper}
|
|
146
|
+
accessible
|
|
147
|
+
accessibilityRole="alert"
|
|
148
|
+
accessibilityLabel="Message failed to render"
|
|
149
|
+
>
|
|
150
|
+
<View style={styles.bubble}>
|
|
151
|
+
<Text style={styles.title}>Couldn't render this message</Text>
|
|
152
|
+
<Text style={styles.message} numberOfLines={2}>
|
|
153
|
+
{error.message || 'Unknown render error.'}
|
|
154
|
+
</Text>
|
|
155
|
+
<Pressable
|
|
156
|
+
onPress={onReset}
|
|
157
|
+
accessibilityRole="button"
|
|
158
|
+
accessibilityLabel="Retry rendering this message"
|
|
159
|
+
hitSlop={8}
|
|
160
|
+
style={({ pressed }) => [
|
|
161
|
+
styles.retryButton,
|
|
162
|
+
pressed && styles.retryButtonPressed,
|
|
163
|
+
]}
|
|
164
|
+
>
|
|
165
|
+
<RotateCcw size={12} color={theme.colors.foreground} />
|
|
166
|
+
<Text style={styles.retryText}>Retry</Text>
|
|
167
|
+
</Pressable>
|
|
168
|
+
</View>
|
|
169
|
+
</View>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
DefaultFallback.displayName = 'ChatErrorBoundary.DefaultFallback';
|
|
174
|
+
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Styles
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
function getStyles(theme: AIElementsTheme) {
|
|
180
|
+
return StyleSheet.create({
|
|
181
|
+
wrapper: {
|
|
182
|
+
alignItems: 'flex-start',
|
|
183
|
+
paddingHorizontal: theme.spacing.lg,
|
|
184
|
+
marginBottom: theme.spacing.md,
|
|
185
|
+
},
|
|
186
|
+
bubble: {
|
|
187
|
+
backgroundColor: theme.colors.muted,
|
|
188
|
+
borderColor: theme.colors.border,
|
|
189
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
190
|
+
borderRadius: theme.radius.md,
|
|
191
|
+
paddingHorizontal: theme.spacing.md,
|
|
192
|
+
paddingVertical: theme.spacing.sm,
|
|
193
|
+
maxWidth: '88%',
|
|
194
|
+
},
|
|
195
|
+
title: {
|
|
196
|
+
color: theme.colors.foreground,
|
|
197
|
+
fontFamily: theme.typography.fontFamily,
|
|
198
|
+
fontSize: theme.typography.fontSize.sm,
|
|
199
|
+
fontWeight: theme.typography.fontWeight.semibold as '600',
|
|
200
|
+
marginBottom: 2,
|
|
201
|
+
},
|
|
202
|
+
message: {
|
|
203
|
+
color: theme.colors.mutedForeground,
|
|
204
|
+
fontFamily: theme.typography.fontFamily,
|
|
205
|
+
fontSize: theme.typography.fontSize.sm,
|
|
206
|
+
lineHeight:
|
|
207
|
+
theme.typography.fontSize.sm * theme.typography.lineHeight.normal,
|
|
208
|
+
marginBottom: theme.spacing.sm,
|
|
209
|
+
},
|
|
210
|
+
retryButton: {
|
|
211
|
+
flexDirection: 'row',
|
|
212
|
+
alignItems: 'center',
|
|
213
|
+
gap: 6,
|
|
214
|
+
alignSelf: 'flex-start',
|
|
215
|
+
paddingHorizontal: theme.spacing.sm,
|
|
216
|
+
paddingVertical: 4,
|
|
217
|
+
borderRadius: theme.radius.sm,
|
|
218
|
+
backgroundColor: theme.colors.secondary,
|
|
219
|
+
},
|
|
220
|
+
retryButtonPressed: {
|
|
221
|
+
opacity: 0.7,
|
|
222
|
+
},
|
|
223
|
+
retryText: {
|
|
224
|
+
color: theme.colors.foreground,
|
|
225
|
+
fontFamily: theme.typography.fontFamily,
|
|
226
|
+
fontSize: theme.typography.fontSize.sm,
|
|
227
|
+
fontWeight: theme.typography.fontWeight.medium as '500',
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import { useAIElementsTheme } from '../theme';
|
|
4
|
+
import { StreamingMarkdown } from '../streaming';
|
|
5
|
+
import { Message, MessageContent } from './Message';
|
|
6
|
+
import { Reasoning } from './Reasoning';
|
|
7
|
+
import { Tool } from './Tool';
|
|
8
|
+
import { Sources } from './Sources';
|
|
9
|
+
import type { ChatMessageData } from './types';
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Props
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface ChatMessageItemProps {
|
|
16
|
+
/**
|
|
17
|
+
* The message to render, in the canonical {@link ChatMessageData} shape.
|
|
18
|
+
* Map your own message type to this shape inside `renderMessage`.
|
|
19
|
+
*/
|
|
20
|
+
item: ChatMessageData;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated No longer applied — `StreamingMarkdown` matches Vercel
|
|
23
|
+
* ai-elements' `memo(Streamdown)` pattern and performs no custom fade
|
|
24
|
+
* animation. Kept in the props for backwards compatibility so existing
|
|
25
|
+
* call sites don't break; safe to remove.
|
|
26
|
+
*/
|
|
27
|
+
fadeDuration?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Component
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Renders a single chat message — either a user bubble (delegated to the
|
|
36
|
+
* library's `Message` compound) or an assistant block composed of optional
|
|
37
|
+
* reasoning, tool call, streaming markdown, and sources.
|
|
38
|
+
*
|
|
39
|
+
* Wrapped in `React.memo` with a custom equality function below: rows only
|
|
40
|
+
* re-render when their own `item` content actually changes, **not** when an
|
|
41
|
+
* unrelated message updates elsewhere in the list. The equality function
|
|
42
|
+
* compares fields directly so callers can safely build a fresh
|
|
43
|
+
* `ChatMessageData` object on every render — identity churn is fine.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* const renderMessage = useCallback(
|
|
48
|
+
* (raw: MyMessage) => {
|
|
49
|
+
* const data: ChatMessageData = toChatMessageData(raw);
|
|
50
|
+
* return <ChatMessageItem item={data} />;
|
|
51
|
+
* },
|
|
52
|
+
* [],
|
|
53
|
+
* );
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function ChatMessageItemImpl({ item }: ChatMessageItemProps) {
|
|
57
|
+
const theme = useAIElementsTheme();
|
|
58
|
+
const isUser = item.role === 'user';
|
|
59
|
+
|
|
60
|
+
if (isUser) {
|
|
61
|
+
// Library's Message compound owns padding + bubble layout for user msgs.
|
|
62
|
+
// We pass the canonical data through — `Message` only reads `id`, `role`
|
|
63
|
+
// and `content`, all of which are present.
|
|
64
|
+
return (
|
|
65
|
+
<Message message={item}>
|
|
66
|
+
<MessageContent />
|
|
67
|
+
</Message>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Assistant message — composed from optional sub-blocks.
|
|
72
|
+
return (
|
|
73
|
+
<View
|
|
74
|
+
style={[
|
|
75
|
+
styles.assistantBlock,
|
|
76
|
+
{
|
|
77
|
+
paddingHorizontal: theme.spacing.lg,
|
|
78
|
+
marginBottom: theme.spacing.md,
|
|
79
|
+
},
|
|
80
|
+
]}
|
|
81
|
+
>
|
|
82
|
+
{item.reasoning && (
|
|
83
|
+
<Reasoning
|
|
84
|
+
content={item.reasoning.content}
|
|
85
|
+
isStreaming={item.reasoning.isStreaming}
|
|
86
|
+
// Collapsed by default — the trigger ("Thinking..." → "Thought
|
|
87
|
+
// for Xs") still shows progress; the user can tap to expand.
|
|
88
|
+
defaultOpen={false}
|
|
89
|
+
style={{ marginBottom: theme.spacing.sm }}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{item.tool && (
|
|
94
|
+
<Tool
|
|
95
|
+
name={item.tool.name}
|
|
96
|
+
status={item.tool.status}
|
|
97
|
+
args={item.tool.args}
|
|
98
|
+
result={item.tool.result}
|
|
99
|
+
style={{ marginBottom: theme.spacing.sm }}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
|
|
103
|
+
{item.content.length > 0 && (
|
|
104
|
+
<StreamingMarkdown
|
|
105
|
+
content={item.content}
|
|
106
|
+
// Once sources are attached we treat the message as fully
|
|
107
|
+
// delivered and the streaming hint switches off.
|
|
108
|
+
isStreaming={!item.sources}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{item.sources && item.sources.length > 0 && (
|
|
113
|
+
<Sources
|
|
114
|
+
sources={item.sources}
|
|
115
|
+
style={{ marginTop: theme.spacing.sm }}
|
|
116
|
+
/>
|
|
117
|
+
)}
|
|
118
|
+
</View>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
ChatMessageItemImpl.displayName = 'ChatMessageItem';
|
|
123
|
+
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Custom equality — only re-render when something we actually display changes
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns true when the two prop sets would render identical output. Compares
|
|
130
|
+
* fields directly so a freshly-built `ChatMessageData` object on every render
|
|
131
|
+
* is fine — only real content changes trigger a re-render.
|
|
132
|
+
*/
|
|
133
|
+
function areEqual(
|
|
134
|
+
prev: ChatMessageItemProps,
|
|
135
|
+
next: ChatMessageItemProps,
|
|
136
|
+
): boolean {
|
|
137
|
+
const a = prev.item;
|
|
138
|
+
const b = next.item;
|
|
139
|
+
if (a === b) return true;
|
|
140
|
+
|
|
141
|
+
// Identity / role
|
|
142
|
+
if (a.id !== b.id) return false;
|
|
143
|
+
if (a.role !== b.role) return false;
|
|
144
|
+
|
|
145
|
+
// Content (the streaming hot path — must be cheap)
|
|
146
|
+
if (a.content !== b.content) return false;
|
|
147
|
+
|
|
148
|
+
// Reasoning (object — compare relevant fields, not identity)
|
|
149
|
+
const ar = a.reasoning;
|
|
150
|
+
const br = b.reasoning;
|
|
151
|
+
if (ar !== br) {
|
|
152
|
+
if (!ar || !br) return false;
|
|
153
|
+
if (ar.content !== br.content) return false;
|
|
154
|
+
if (ar.isStreaming !== br.isStreaming) return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Tool — name + status + result are the animating fields. Args are
|
|
158
|
+
// assumed stable per invocation, so we don't deep-compare them.
|
|
159
|
+
const at = a.tool;
|
|
160
|
+
const bt = b.tool;
|
|
161
|
+
if (at !== bt) {
|
|
162
|
+
if (!at || !bt) return false;
|
|
163
|
+
if (at.name !== bt.name) return false;
|
|
164
|
+
if (at.status !== bt.status) return false;
|
|
165
|
+
if (at.result !== bt.result) return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Sources — the typical pattern is to attach the array once at the end
|
|
169
|
+
// of the stream and never mutate it, so a length comparison is enough.
|
|
170
|
+
const as = a.sources;
|
|
171
|
+
const bs = b.sources;
|
|
172
|
+
if (as !== bs) {
|
|
173
|
+
if ((as?.length ?? 0) !== (bs?.length ?? 0)) return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const ChatMessageItem = React.memo(ChatMessageItemImpl, areEqual);
|
|
180
|
+
|
|
181
|
+
// `React.memo` doesn't propagate `displayName` from the inner function, set
|
|
182
|
+
// it on the wrapped export so DevTools shows a meaningful name.
|
|
183
|
+
ChatMessageItem.displayName = 'ChatMessageItem';
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Styles
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
const styles = StyleSheet.create({
|
|
190
|
+
assistantBlock: {
|
|
191
|
+
// Default `alignItems: stretch` so children (Reasoning, Tool,
|
|
192
|
+
// StreamingMarkdown, Sources) span the full available width instead
|
|
193
|
+
// of shrinking to intrinsic content size.
|
|
194
|
+
},
|
|
195
|
+
});
|