@qafka/react-native 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/CONTRIBUTING.md +92 -0
  3. package/LICENSE +22 -0
  4. package/README.md +109 -0
  5. package/SECURITY.md +67 -0
  6. package/android/build.gradle +35 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/qafka/attestation/QafkaAttestationModule.kt +92 -0
  9. package/android/src/main/java/com/qafka/attestation/QafkaAttestationPackage.kt +22 -0
  10. package/android/src/main/java/com/qafka/audio/QafkaAudioModule.kt +290 -0
  11. package/android/src/main/java/com/qafka/clipboard/QafkaClipboardModule.kt +28 -0
  12. package/android/src/main/java/com/qafka/storage/QafkaStorageModule.kt +80 -0
  13. package/app.plugin.js +1 -0
  14. package/dist/QafkaSDK.d.ts +174 -0
  15. package/dist/QafkaSDK.js +461 -0
  16. package/dist/cards/bindings/resolveFieldName.d.ts +25 -0
  17. package/dist/cards/bindings/resolveFieldName.js +82 -0
  18. package/dist/cards/cta/CardContext.d.ts +16 -0
  19. package/dist/cards/cta/CardContext.js +58 -0
  20. package/dist/cards/cta/dispatcher.d.ts +7 -0
  21. package/dist/cards/cta/dispatcher.js +90 -0
  22. package/dist/cards/cta/types.d.ts +66 -0
  23. package/dist/cards/cta/types.js +2 -0
  24. package/dist/cards/index.d.ts +20 -0
  25. package/dist/cards/index.js +34 -0
  26. package/dist/cards/primitives/QButton.d.ts +10 -0
  27. package/dist/cards/primitives/QButton.js +115 -0
  28. package/dist/cards/primitives/QDivider.d.ts +7 -0
  29. package/dist/cards/primitives/QDivider.js +17 -0
  30. package/dist/cards/primitives/QIcon.d.ts +13 -0
  31. package/dist/cards/primitives/QIcon.js +26 -0
  32. package/dist/cards/primitives/QImage.d.ts +9 -0
  33. package/dist/cards/primitives/QImage.js +22 -0
  34. package/dist/cards/primitives/QText.d.ts +9 -0
  35. package/dist/cards/primitives/QText.js +30 -0
  36. package/dist/cards/primitives/QView.d.ts +8 -0
  37. package/dist/cards/primitives/QView.js +19 -0
  38. package/dist/cards/renderer/CardRenderer.d.ts +19 -0
  39. package/dist/cards/renderer/CardRenderer.js +64 -0
  40. package/dist/cards/renderer/renderNode.d.ts +13 -0
  41. package/dist/cards/renderer/renderNode.js +42 -0
  42. package/dist/cards/types.d.ts +110 -0
  43. package/dist/cards/types.js +6 -0
  44. package/dist/components/ActionResultBadge.d.ts +12 -0
  45. package/dist/components/ActionResultBadge.js +58 -0
  46. package/dist/components/ChatPage.d.ts +44 -0
  47. package/dist/components/ChatPage.js +84 -0
  48. package/dist/components/DataChip.d.ts +8 -0
  49. package/dist/components/DataChip.js +80 -0
  50. package/dist/components/DataChipList.d.ts +13 -0
  51. package/dist/components/DataChipList.js +21 -0
  52. package/dist/components/FloatingButton.d.ts +11 -0
  53. package/dist/components/FloatingButton.js +162 -0
  54. package/dist/components/InputArea.d.ts +57 -0
  55. package/dist/components/InputArea.js +142 -0
  56. package/dist/components/MarkdownText.d.ts +15 -0
  57. package/dist/components/MarkdownText.js +283 -0
  58. package/dist/components/MessageBubble.d.ts +134 -0
  59. package/dist/components/MessageBubble.js +384 -0
  60. package/dist/components/NavigationSuggestion.d.ts +11 -0
  61. package/dist/components/NavigationSuggestion.js +109 -0
  62. package/dist/components/Qafka.d.ts +39 -0
  63. package/dist/components/Qafka.handlers.d.ts +21 -0
  64. package/dist/components/Qafka.handlers.js +54 -0
  65. package/dist/components/Qafka.js +493 -0
  66. package/dist/components/Qafka.styles.d.ts +19 -0
  67. package/dist/components/Qafka.styles.js +101 -0
  68. package/dist/components/Qafka.types.d.ts +744 -0
  69. package/dist/components/Qafka.types.js +2 -0
  70. package/dist/components/Qafka.utils.d.ts +7 -0
  71. package/dist/components/Qafka.utils.js +34 -0
  72. package/dist/components/QafkaProvider.d.ts +12 -0
  73. package/dist/components/QafkaProvider.js +87 -0
  74. package/dist/components/QuickReplies.d.ts +14 -0
  75. package/dist/components/QuickReplies.js +48 -0
  76. package/dist/components/StepProgressIndicator.d.ts +12 -0
  77. package/dist/components/StepProgressIndicator.js +48 -0
  78. package/dist/components/SuggestionButton.d.ts +42 -0
  79. package/dist/components/SuggestionButton.js +67 -0
  80. package/dist/components/ToolStatusPill.d.ts +20 -0
  81. package/dist/components/ToolStatusPill.js +43 -0
  82. package/dist/components/TypingIndicator.d.ts +28 -0
  83. package/dist/components/TypingIndicator.js +109 -0
  84. package/dist/components/VoicePage.d.ts +48 -0
  85. package/dist/components/VoicePage.js +683 -0
  86. package/dist/components/defaults/DefaultCard.d.ts +14 -0
  87. package/dist/components/defaults/DefaultCard.js +156 -0
  88. package/dist/components/defaults/DefaultDetail.d.ts +14 -0
  89. package/dist/components/defaults/DefaultDetail.js +138 -0
  90. package/dist/components/defaults/DefaultList.d.ts +12 -0
  91. package/dist/components/defaults/DefaultList.js +98 -0
  92. package/dist/components/defaults/DefaultTable.d.ts +14 -0
  93. package/dist/components/defaults/DefaultTable.js +204 -0
  94. package/dist/components/defaults/index.d.ts +14 -0
  95. package/dist/components/defaults/index.js +25 -0
  96. package/dist/components/index.d.ts +22 -0
  97. package/dist/components/index.js +36 -0
  98. package/dist/constants.d.ts +10 -0
  99. package/dist/constants.js +13 -0
  100. package/dist/hooks/useChatMessages.d.ts +72 -0
  101. package/dist/hooks/useChatMessages.js +505 -0
  102. package/dist/hooks/useContextManager.d.ts +12 -0
  103. package/dist/hooks/useContextManager.js +46 -0
  104. package/dist/hooks/useProjectTheme.d.ts +19 -0
  105. package/dist/hooks/useProjectTheme.js +163 -0
  106. package/dist/hooks/useSDK.d.ts +31 -0
  107. package/dist/hooks/useSDK.js +103 -0
  108. package/dist/hooks/useVoiceChat.d.ts +110 -0
  109. package/dist/hooks/useVoiceChat.js +436 -0
  110. package/dist/index.d.ts +13 -0
  111. package/dist/index.js +59 -0
  112. package/dist/native/QafkaAttestation.d.ts +23 -0
  113. package/dist/native/QafkaAttestation.js +70 -0
  114. package/dist/native/QafkaAudio.d.ts +14 -0
  115. package/dist/native/QafkaAudio.js +31 -0
  116. package/dist/native/QafkaClipboard.d.ts +11 -0
  117. package/dist/native/QafkaClipboard.js +14 -0
  118. package/dist/native/QafkaStorage.d.ts +15 -0
  119. package/dist/native/QafkaStorage.js +12 -0
  120. package/dist/resolve-project-config.d.ts +35 -0
  121. package/dist/resolve-project-config.js +41 -0
  122. package/dist/runtime-config-loader.d.ts +37 -0
  123. package/dist/runtime-config-loader.js +53 -0
  124. package/dist/services/AttestationManager.d.ts +38 -0
  125. package/dist/services/AttestationManager.js +296 -0
  126. package/dist/services/BackendService.d.ts +156 -0
  127. package/dist/services/BackendService.js +755 -0
  128. package/dist/services/ConversationManager.d.ts +43 -0
  129. package/dist/services/ConversationManager.js +96 -0
  130. package/dist/services/NavigationHandler.d.ts +29 -0
  131. package/dist/services/NavigationHandler.js +70 -0
  132. package/dist/services/RealtimeService.d.ts +83 -0
  133. package/dist/services/RealtimeService.js +203 -0
  134. package/dist/services/storage.d.ts +11 -0
  135. package/dist/services/storage.js +15 -0
  136. package/dist/services/storageCore.d.ts +17 -0
  137. package/dist/services/storageCore.js +46 -0
  138. package/dist/themes/dark.d.ts +5 -0
  139. package/dist/themes/dark.js +129 -0
  140. package/dist/themes/index.d.ts +12 -0
  141. package/dist/themes/index.js +33 -0
  142. package/dist/themes/light.d.ts +5 -0
  143. package/dist/themes/light.js +129 -0
  144. package/dist/themes/types.d.ts +155 -0
  145. package/dist/themes/types.js +5 -0
  146. package/dist/types/chat.d.ts +126 -0
  147. package/dist/types/chat.js +5 -0
  148. package/dist/types/components.d.ts +56 -0
  149. package/dist/types/components.js +16 -0
  150. package/dist/types/external-navigation.d.ts +19 -0
  151. package/dist/types/external-navigation.js +8 -0
  152. package/dist/types/index.d.ts +9 -0
  153. package/dist/types/index.js +25 -0
  154. package/dist/types/navigation.d.ts +86 -0
  155. package/dist/types/navigation.js +5 -0
  156. package/dist/types/sdk.d.ts +36 -0
  157. package/dist/types/sdk.js +5 -0
  158. package/dist/utils/deepMerge.d.ts +46 -0
  159. package/dist/utils/deepMerge.js +70 -0
  160. package/dist/utils/fontUtils.d.ts +8 -0
  161. package/dist/utils/fontUtils.js +16 -0
  162. package/dist/validate-end-user.d.ts +18 -0
  163. package/dist/validate-end-user.js +74 -0
  164. package/expo-plugin/withQafkaAttestation.js +57 -0
  165. package/ios/QafkaAttestation.m +25 -0
  166. package/ios/QafkaAttestation.swift +128 -0
  167. package/ios/QafkaAudio.m +23 -0
  168. package/ios/QafkaAudio.swift +519 -0
  169. package/ios/QafkaClipboard.m +10 -0
  170. package/ios/QafkaClipboard.swift +21 -0
  171. package/ios/QafkaReactImports.h +2 -0
  172. package/ios/QafkaStorage.m +26 -0
  173. package/ios/QafkaStorage.swift +118 -0
  174. package/package.json +82 -0
  175. package/qafka.config.d.ts +9 -0
  176. package/qafka.config.js +9 -0
  177. package/react-native-qafka.podspec +28 -0
  178. package/react-native.config.js +14 -0
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.InputArea = InputArea;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const fontUtils_1 = require("../utils/fontUtils");
40
+ /**
41
+ * InputArea Component
42
+ *
43
+ * Text input area with send button for chat messages.
44
+ *
45
+ * Features:
46
+ * - Multi-line text input
47
+ * - Character limit with counter
48
+ * - Send button with loading state
49
+ * - Auto-disable when empty or sending
50
+ * - Theme support
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * <InputArea
55
+ * theme={lightTheme}
56
+ * placeholder="Type a message..."
57
+ * onSend={(msg) => handleSend(msg)}
58
+ * isSending={loading}
59
+ * maxLength={500}
60
+ * showCharacterCount
61
+ * />
62
+ * ```
63
+ */
64
+ function InputArea({ theme, placeholder = 'Type a message...', onSend, isSending = false, maxLength = 500, disabled = false, showCharacterCount = false, }) {
65
+ const [text, setText] = (0, react_1.useState)('');
66
+ const handleSend = () => {
67
+ const trimmedText = text?.trim?.() || '';
68
+ if (!trimmedText || isSending || disabled)
69
+ return;
70
+ onSend(trimmedText);
71
+ setText('');
72
+ };
73
+ const canSend = text.trim().length > 0 && !isSending && !disabled;
74
+ const containerStyle = {
75
+ flexDirection: 'row',
76
+ alignItems: 'flex-end',
77
+ paddingHorizontal: theme.spacing.md,
78
+ paddingVertical: theme.spacing.sm,
79
+ backgroundColor: theme.colors.background,
80
+ borderTopWidth: 1,
81
+ borderTopColor: theme.colors.border,
82
+ };
83
+ const inputContainerStyle = {
84
+ flex: 1,
85
+ backgroundColor: theme.colors.inputBackground,
86
+ borderRadius: theme.borderRadius.xl,
87
+ borderWidth: 1,
88
+ borderColor: theme.colors.inputBorder,
89
+ paddingHorizontal: theme.spacing.md,
90
+ paddingVertical: theme.spacing.sm,
91
+ marginRight: theme.spacing.sm,
92
+ maxHeight: 100,
93
+ };
94
+ const inputStyle = {
95
+ fontSize: theme.typography.fontSize.md,
96
+ color: theme.colors.text,
97
+ lineHeight: theme.typography.fontSize.md * theme.typography.lineHeight.normal,
98
+ minHeight: 20,
99
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'regular'),
100
+ };
101
+ const sendButtonStyle = {
102
+ width: 40,
103
+ height: 40,
104
+ borderRadius: 20,
105
+ backgroundColor: canSend
106
+ ? theme.colors.buttonBackground
107
+ : theme.colors.buttonDisabled,
108
+ alignItems: 'center',
109
+ justifyContent: 'center',
110
+ ...theme.shadows.small,
111
+ };
112
+ const sendButtonTextStyle = {
113
+ fontSize: theme.typography.fontSize.lg,
114
+ color: theme.colors.buttonText,
115
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'medium'),
116
+ };
117
+ const charCountStyle = {
118
+ fontSize: theme.typography.fontSize.xs,
119
+ color: text.length >= maxLength
120
+ ? theme.colors.error
121
+ : theme.colors.textSecondary,
122
+ marginTop: theme.spacing.xs / 2,
123
+ marginLeft: theme.spacing.sm,
124
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'regular'),
125
+ };
126
+ return (<react_native_1.View>
127
+ <react_native_1.View style={containerStyle}>
128
+ <react_native_1.View style={inputContainerStyle}>
129
+ <react_native_1.TextInput style={inputStyle} value={text} onChangeText={setText} placeholder={placeholder} placeholderTextColor={theme.colors.inputPlaceholder} multiline maxLength={maxLength} editable={!disabled && !isSending} returnKeyType="default" blurOnSubmit={false}/>
130
+ </react_native_1.View>
131
+
132
+ <react_native_1.TouchableOpacity style={sendButtonStyle} onPress={handleSend} disabled={!canSend} activeOpacity={0.7}>
133
+ {isSending ? (<react_native_1.ActivityIndicator color={theme.colors.buttonText} size="small"/>) : (<react_native_1.Text style={sendButtonTextStyle}>↑</react_native_1.Text>)}
134
+ </react_native_1.TouchableOpacity>
135
+ </react_native_1.View>
136
+
137
+ {/* Character counter */}
138
+ {showCharacterCount && text.length > 0 && (<react_native_1.Text style={charCountStyle}>
139
+ {text.length} / {maxLength}
140
+ </react_native_1.Text>)}
141
+ </react_native_1.View>);
142
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { TextStyle } from 'react-native';
3
+ import { Theme } from '../themes/types';
4
+ interface MarkdownTextProps {
5
+ children: string;
6
+ style: TextStyle;
7
+ theme: Theme;
8
+ isUserMessage: boolean;
9
+ }
10
+ /**
11
+ * Enhanced Markdown Renderer
12
+ * Supports: headings (###), **bold**, *italic*, `code`, ```code blocks```, links, bullet lists, numbered lists
13
+ */
14
+ export declare function MarkdownText({ children, style, theme, isUserMessage, }: MarkdownTextProps): React.JSX.Element;
15
+ export {};
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MarkdownText = MarkdownText;
7
+ const react_1 = __importDefault(require("react"));
8
+ const react_native_1 = require("react-native");
9
+ const fontUtils_1 = require("../utils/fontUtils");
10
+ /**
11
+ * Enhanced Markdown Renderer
12
+ * Supports: headings (###), **bold**, *italic*, `code`, ```code blocks```, links, bullet lists, numbered lists
13
+ */
14
+ function MarkdownText({ children, style, theme, isUserMessage, }) {
15
+ // Extract base styles (without fontWeight/fontStyle that might interfere with markdown)
16
+ const baseTextStyle = {
17
+ color: style.color,
18
+ fontSize: style.fontSize,
19
+ lineHeight: style.lineHeight,
20
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'regular'),
21
+ };
22
+ // Process line by line for block elements
23
+ const processLine = (line, lineIndex) => {
24
+ // Check for headings (### Heading)
25
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
26
+ if (headingMatch) {
27
+ const level = headingMatch[1].length;
28
+ const headingText = headingMatch[2];
29
+ const headingSize = style.fontSize + (6 - level) * 2;
30
+ return (<react_native_1.Text key={`heading-${lineIndex}`} style={[
31
+ baseTextStyle,
32
+ {
33
+ fontSize: headingSize,
34
+ fontWeight: '700',
35
+ marginTop: theme.spacing.sm,
36
+ marginBottom: theme.spacing.xs,
37
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'bold'),
38
+ },
39
+ ]}>
40
+ {parseInlineMarkdown(headingText)}
41
+ </react_native_1.Text>);
42
+ }
43
+ // Check for bullet lists (- item or * item)
44
+ const bulletMatch = line.match(/^[\-\*]\s+(.+)$/);
45
+ if (bulletMatch) {
46
+ return (<react_native_1.View key={`bullet-${lineIndex}`} style={{
47
+ flexDirection: 'row',
48
+ marginBottom: theme.spacing.xs / 2,
49
+ paddingLeft: theme.spacing.md,
50
+ }}>
51
+ <react_native_1.Text style={[baseTextStyle, { marginRight: theme.spacing.xs }]}>
52
+
53
+ </react_native_1.Text>
54
+ <react_native_1.Text style={[baseTextStyle, { flexShrink: 1 }]}>
55
+ {parseInlineMarkdown(bulletMatch[1])}
56
+ </react_native_1.Text>
57
+ </react_native_1.View>);
58
+ }
59
+ // Check for numbered lists (1. item)
60
+ const numberedMatch = line.match(/^(\d+)\.\s+(.+)$/);
61
+ if (numberedMatch) {
62
+ return (<react_native_1.View key={`numbered-${lineIndex}`} style={{
63
+ flexDirection: 'row',
64
+ marginBottom: theme.spacing.xs / 2,
65
+ paddingLeft: theme.spacing.md,
66
+ }}>
67
+ <react_native_1.Text style={[baseTextStyle, { marginRight: theme.spacing.xs }]}>
68
+ {numberedMatch[1]}.
69
+ </react_native_1.Text>
70
+ <react_native_1.Text style={[baseTextStyle, { flexShrink: 1 }]}>
71
+ {parseInlineMarkdown(numberedMatch[2])}
72
+ </react_native_1.Text>
73
+ </react_native_1.View>);
74
+ }
75
+ // Check for code blocks (```code```)
76
+ if (line.startsWith('```')) {
77
+ return null; // Handle code blocks separately
78
+ }
79
+ // Regular paragraph
80
+ return (<react_native_1.Text key={`line-${lineIndex}`} style={baseTextStyle}>
81
+ {parseInlineMarkdown(line)}
82
+ </react_native_1.Text>);
83
+ };
84
+ const parseInlineMarkdown = (text) => {
85
+ const elements = [];
86
+ let currentIndex = 0;
87
+ let key = 0;
88
+ // Regex patterns for inline formatting
89
+ // Process in order: bold first, then italic (to avoid conflicts)
90
+ const patterns = {
91
+ bold: /\*\*(.+?)\*\*/g,
92
+ italic: /(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, // Negative lookahead/behind to avoid **
93
+ code: /`(.+?)`/g,
94
+ link: /\[(.+?)\]\((.+?)\)/g,
95
+ };
96
+ // Find all matches
97
+ const allMatches = [];
98
+ // Bold - process first
99
+ let boldMatch;
100
+ while ((boldMatch = patterns.bold.exec(text)) !== null) {
101
+ allMatches.push({
102
+ index: boldMatch.index,
103
+ length: boldMatch[0].length,
104
+ type: 'bold',
105
+ content: boldMatch[1],
106
+ });
107
+ }
108
+ // Italic - check if not overlapping with bold
109
+ const italicPattern = /\*(.+?)\*/g;
110
+ let italicMatch;
111
+ while ((italicMatch = italicPattern.exec(text)) !== null) {
112
+ // Check if this position is inside a bold match
113
+ const isInsideBold = allMatches.some((m) => m.type === 'bold' &&
114
+ italicMatch.index >= m.index &&
115
+ italicMatch.index < m.index + m.length);
116
+ // Also check if preceded or followed by another asterisk (bold marker)
117
+ const prevChar = text[italicMatch.index - 1];
118
+ const nextChar = text[italicMatch.index + italicMatch[0].length];
119
+ const isBoldMarker = prevChar === '*' || nextChar === '*';
120
+ if (!isInsideBold && !isBoldMarker) {
121
+ allMatches.push({
122
+ index: italicMatch.index,
123
+ length: italicMatch[0].length,
124
+ type: 'italic',
125
+ content: italicMatch[1],
126
+ });
127
+ }
128
+ }
129
+ // Code
130
+ patterns.code.lastIndex = 0;
131
+ let codeMatch;
132
+ while ((codeMatch = patterns.code.exec(text)) !== null) {
133
+ allMatches.push({
134
+ index: codeMatch.index,
135
+ length: codeMatch[0].length,
136
+ type: 'code',
137
+ content: codeMatch[1],
138
+ });
139
+ }
140
+ // Links
141
+ patterns.link.lastIndex = 0;
142
+ let linkMatch;
143
+ while ((linkMatch = patterns.link.exec(text)) !== null) {
144
+ allMatches.push({
145
+ index: linkMatch.index,
146
+ length: linkMatch[0].length,
147
+ type: 'link',
148
+ content: linkMatch[1],
149
+ url: linkMatch[2],
150
+ });
151
+ }
152
+ // Sort by index
153
+ allMatches.sort((a, b) => a.index - b.index);
154
+ // Build elements
155
+ allMatches.forEach((item) => {
156
+ // Add text before match
157
+ if (currentIndex < item.index) {
158
+ const plainText = text.substring(currentIndex, item.index);
159
+ elements.push(<react_native_1.Text key={`text-${key++}`} style={baseTextStyle}>
160
+ {plainText}
161
+ </react_native_1.Text>);
162
+ }
163
+ // Add formatted text
164
+ switch (item.type) {
165
+ case 'bold':
166
+ elements.push(<react_native_1.Text key={`bold-${key++}`} style={[
167
+ baseTextStyle,
168
+ {
169
+ fontWeight: 'bold',
170
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'bold'),
171
+ },
172
+ ]}>
173
+ {item.content}
174
+ </react_native_1.Text>);
175
+ break;
176
+ case 'italic':
177
+ elements.push(<react_native_1.Text key={`italic-${key++}`} style={[
178
+ baseTextStyle,
179
+ {
180
+ fontStyle: 'italic',
181
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'italic'),
182
+ },
183
+ ]}>
184
+ {item.content}
185
+ </react_native_1.Text>);
186
+ break;
187
+ case 'code':
188
+ elements.push(<react_native_1.Text key={`code-${key++}`} style={[
189
+ baseTextStyle,
190
+ {
191
+ backgroundColor: isUserMessage
192
+ ? 'rgba(255,255,255,0.2)'
193
+ : theme.colors.surface,
194
+ paddingHorizontal: theme.spacing.xs,
195
+ paddingVertical: 2,
196
+ borderRadius: theme.borderRadius.sm,
197
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'code') || 'Courier',
198
+ },
199
+ ]}>
200
+ {item.content}
201
+ </react_native_1.Text>);
202
+ break;
203
+ case 'link':
204
+ elements.push(<react_native_1.Text key={`link-${key++}`} style={[
205
+ baseTextStyle,
206
+ {
207
+ color: isUserMessage
208
+ ? baseTextStyle.color
209
+ : theme.colors.primary,
210
+ textDecorationLine: 'underline',
211
+ },
212
+ ]}>
213
+ {item.content}
214
+ </react_native_1.Text>);
215
+ break;
216
+ }
217
+ currentIndex = item.index + item.length;
218
+ });
219
+ // Add remaining text
220
+ if (currentIndex < text.length) {
221
+ const remainingText = text.substring(currentIndex);
222
+ elements.push(<react_native_1.Text key={`text-${key++}`} style={baseTextStyle}>
223
+ {remainingText}
224
+ </react_native_1.Text>);
225
+ }
226
+ return elements.length > 0 ? (elements) : (<react_native_1.Text style={baseTextStyle}>{text}</react_native_1.Text>);
227
+ };
228
+ // Split into lines and process
229
+ const lines = children.split('\n');
230
+ const processedLines = [];
231
+ let codeBlockLines = [];
232
+ let inCodeBlock = false;
233
+ let codeBlockKey = 0;
234
+ lines.forEach((line, index) => {
235
+ // Handle code blocks
236
+ if (line.trim().startsWith('```')) {
237
+ if (!inCodeBlock) {
238
+ // Start code block
239
+ inCodeBlock = true;
240
+ codeBlockLines = [];
241
+ }
242
+ else {
243
+ // End code block
244
+ inCodeBlock = false;
245
+ if (codeBlockLines.length > 0) {
246
+ processedLines.push(<react_native_1.View key={`codeblock-${codeBlockKey++}`} style={{
247
+ backgroundColor: isUserMessage
248
+ ? 'rgba(255,255,255,0.2)'
249
+ : theme.colors.surface,
250
+ padding: theme.spacing.sm,
251
+ borderRadius: theme.borderRadius.sm,
252
+ marginVertical: theme.spacing.xs,
253
+ }}>
254
+ <react_native_1.Text style={[
255
+ baseTextStyle,
256
+ {
257
+ fontFamily: (0, fontUtils_1.getFontFamily)(theme, 'code') || 'Courier',
258
+ fontSize: theme.typography.fontSize.sm,
259
+ },
260
+ ]}>
261
+ {codeBlockLines.join('\n')}
262
+ </react_native_1.Text>
263
+ </react_native_1.View>);
264
+ }
265
+ }
266
+ return;
267
+ }
268
+ if (inCodeBlock) {
269
+ codeBlockLines.push(line);
270
+ return;
271
+ }
272
+ // Process regular line
273
+ const processed = processLine(line, index);
274
+ if (processed) {
275
+ processedLines.push(processed);
276
+ }
277
+ // Add spacing between lines
278
+ if (index < lines.length - 1 && line.trim() !== '') {
279
+ processedLines.push(<react_native_1.View key={`spacing-${index}`} style={{ height: theme.spacing.xs / 2 }}/>);
280
+ }
281
+ });
282
+ return <react_native_1.View>{processedLines}</react_native_1.View>;
283
+ }
@@ -0,0 +1,134 @@
1
+ import React from 'react';
2
+ import { Theme } from '../themes/types';
3
+ import { ComponentRegistry } from '../types/components';
4
+ import { NavigationButtonProps } from './Qafka.types';
5
+ import { ExternalSuggestion } from '../types/external-navigation';
6
+ export interface MessageBubbleProps {
7
+ /**
8
+ * Message content
9
+ */
10
+ message: string;
11
+ /**
12
+ * Message role - user or AI assistant
13
+ */
14
+ role: 'user' | 'assistant';
15
+ /**
16
+ * Message timestamp
17
+ */
18
+ timestamp: Date;
19
+ /**
20
+ * Theme configuration
21
+ */
22
+ theme: Theme;
23
+ /**
24
+ * Show timestamp below message
25
+ */
26
+ showTimestamp?: boolean;
27
+ /**
28
+ * Action buttons to display below message
29
+ */
30
+ actions?: Array<{
31
+ id: string;
32
+ type: 'navigation' | 'api' | 'custom';
33
+ label: string;
34
+ icon?: string;
35
+ data?: any;
36
+ style?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning';
37
+ }>;
38
+ /**
39
+ * Callback when action button is pressed
40
+ */
41
+ onActionPress?: (action: any) => void;
42
+ /**
43
+ * Component registry for rendering tool responses
44
+ */
45
+ componentRegistry?: ComponentRegistry;
46
+ /**
47
+ * Custom Navigation Button Component
48
+ * Overrides the default navigation button
49
+ */
50
+ NavigationButtonComponent?: React.ComponentType<NavigationButtonProps>;
51
+ /**
52
+ * Tool definition (if this message contains tool result)
53
+ */
54
+ toolDefinition?: {
55
+ key: string;
56
+ response: {
57
+ type: 'list' | 'card' | 'detail' | 'table';
58
+ dataPath?: string;
59
+ itemComponent?: string;
60
+ maxItems?: number;
61
+ fallbackMessage?: string;
62
+ layout?: 'vertical' | 'horizontal' | 'custom';
63
+ position?: 'before' | 'after';
64
+ };
65
+ };
66
+ /**
67
+ * Tool result data (if this message contains tool result)
68
+ */
69
+ toolResultData?: any;
70
+ /**
71
+ * Action execution results to display as badges
72
+ */
73
+ actionResults?: Array<{
74
+ actionType: string;
75
+ success: boolean;
76
+ message: string;
77
+ }>;
78
+ /**
79
+ * Completed steps for multi-step tool flows
80
+ */
81
+ completedSteps?: Array<{
82
+ tool: string;
83
+ step: string;
84
+ data: Record<string, any>;
85
+ }>;
86
+ /**
87
+ * External suggestions (WhatsApp, phone, map, app store, …)
88
+ * to render as tappable buttons below the message.
89
+ */
90
+ externalSuggestions?: ExternalSuggestion[];
91
+ /**
92
+ * Callback when user taps an external suggestion button.
93
+ */
94
+ onExternalPress?: (suggestion: ExternalSuggestion) => void;
95
+ /**
96
+ * Card Template envelope to render below the message bubble.
97
+ * Populated when the tool's `uiTemplateType === "card"`.
98
+ */
99
+ card?: {
100
+ templateId: string;
101
+ templateSlug: string;
102
+ definition: any;
103
+ data: any;
104
+ };
105
+ /**
106
+ * Host callbacks invoked from card CTAs.
107
+ * Forwarded directly to the CardRenderer.
108
+ */
109
+ cardHostCallbacks?: import('../cards/cta/types').CardCTAHostCallbacks;
110
+ /**
111
+ * CTA telemetry / lifecycle hooks.
112
+ */
113
+ cardLifecycle?: import('../cards/cta/types').CardCTALifecycle;
114
+ }
115
+ /**
116
+ * MessageBubble Component
117
+ *
118
+ * Displays a chat message bubble with support for:
119
+ * - User and AI messages with different styles
120
+ * - Timestamps
121
+ * - Theming support
122
+ *
123
+ * @example
124
+ * ```tsx
125
+ * <MessageBubble
126
+ * message="Hello, how can I help?"
127
+ * role="assistant"
128
+ * timestamp={new Date()}
129
+ * theme={lightTheme}
130
+ * showTimestamp
131
+ * />
132
+ * ```
133
+ */
134
+ export declare function MessageBubble({ message, role, timestamp, theme, showTimestamp, actions, onActionPress, componentRegistry, toolDefinition, toolResultData, NavigationButtonComponent, actionResults, completedSteps, externalSuggestions, onExternalPress, card, cardHostCallbacks, cardLifecycle, }: MessageBubbleProps): React.JSX.Element;