@mobileai/react-native 0.9.17 → 0.9.19

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 (292) hide show
  1. package/LICENSE +28 -20
  2. package/MobileAIFloatingOverlay.podspec +25 -0
  3. package/android/build.gradle +61 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +151 -0
  6. package/android/src/main/java/com/mobileai/overlay/MobileAIOverlayPackage.kt +23 -0
  7. package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +45 -0
  8. package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +29 -0
  9. package/ios/MobileAIFloatingOverlayComponentView.mm +73 -0
  10. package/lib/module/components/AIAgent.js +902 -136
  11. package/lib/module/components/AIConsentDialog.js +439 -0
  12. package/lib/module/components/AgentChatBar.js +828 -134
  13. package/lib/module/components/AgentOverlay.js +2 -1
  14. package/lib/module/components/DiscoveryTooltip.js +21 -9
  15. package/lib/module/components/FloatingOverlayWrapper.js +108 -0
  16. package/lib/module/components/Icons.js +123 -0
  17. package/lib/module/config/endpoints.js +12 -2
  18. package/lib/module/core/AgentRuntime.js +373 -27
  19. package/lib/module/core/FiberAdapter.js +56 -0
  20. package/lib/module/core/FiberTreeWalker.js +186 -80
  21. package/lib/module/core/IdleDetector.js +19 -0
  22. package/lib/module/core/NativeAlertInterceptor.js +191 -0
  23. package/lib/module/core/systemPrompt.js +203 -45
  24. package/lib/module/index.js +3 -0
  25. package/lib/module/providers/GeminiProvider.js +72 -56
  26. package/lib/module/providers/ProviderFactory.js +6 -2
  27. package/lib/module/services/AudioInputService.js +3 -12
  28. package/lib/module/services/AudioOutputService.js +1 -13
  29. package/lib/module/services/ConversationService.js +166 -0
  30. package/lib/module/services/MobileAIKnowledgeRetriever.js +41 -0
  31. package/lib/module/services/VoiceService.js +29 -8
  32. package/lib/module/services/telemetry/MobileAI.js +44 -0
  33. package/lib/module/services/telemetry/TelemetryService.js +13 -1
  34. package/lib/module/services/telemetry/TouchAutoCapture.js +44 -18
  35. package/lib/module/specs/FloatingOverlayNativeComponent.ts +19 -0
  36. package/lib/module/support/CSATSurvey.js +95 -12
  37. package/lib/module/support/EscalationSocket.js +70 -1
  38. package/lib/module/support/ReportedIssueEventSource.js +148 -0
  39. package/lib/module/support/escalateTool.js +4 -2
  40. package/lib/module/support/index.js +1 -0
  41. package/lib/module/support/reportIssueTool.js +127 -0
  42. package/lib/module/support/supportPrompt.js +77 -9
  43. package/lib/module/tools/guideTool.js +2 -1
  44. package/lib/module/tools/longPressTool.js +4 -3
  45. package/lib/module/tools/pickerTool.js +6 -4
  46. package/lib/module/tools/tapTool.js +12 -3
  47. package/lib/module/tools/typeTool.js +19 -10
  48. package/lib/module/utils/logger.js +175 -6
  49. package/lib/typescript/react-native.config.d.ts +11 -0
  50. package/lib/typescript/src/components/AIAgent.d.ts +28 -2
  51. package/lib/typescript/src/components/AIConsentDialog.d.ts +153 -0
  52. package/lib/typescript/src/components/AgentChatBar.d.ts +15 -2
  53. package/lib/typescript/src/components/DiscoveryTooltip.d.ts +3 -1
  54. package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +51 -0
  55. package/lib/typescript/src/components/Icons.d.ts +8 -0
  56. package/lib/typescript/src/config/endpoints.d.ts +5 -3
  57. package/lib/typescript/src/core/AgentRuntime.d.ts +4 -0
  58. package/lib/typescript/src/core/FiberAdapter.d.ts +25 -0
  59. package/lib/typescript/src/core/FiberTreeWalker.d.ts +2 -0
  60. package/lib/typescript/src/core/IdleDetector.d.ts +11 -0
  61. package/lib/typescript/src/core/NativeAlertInterceptor.d.ts +55 -0
  62. package/lib/typescript/src/core/types.d.ts +106 -1
  63. package/lib/typescript/src/index.d.ts +9 -4
  64. package/lib/typescript/src/providers/GeminiProvider.d.ts +6 -5
  65. package/lib/typescript/src/services/ConversationService.d.ts +55 -0
  66. package/lib/typescript/src/services/MobileAIKnowledgeRetriever.d.ts +9 -0
  67. package/lib/typescript/src/services/telemetry/MobileAI.d.ts +7 -0
  68. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +1 -1
  69. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts +9 -6
  70. package/lib/typescript/src/services/telemetry/types.d.ts +3 -1
  71. package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +17 -0
  72. package/lib/typescript/src/support/EscalationSocket.d.ts +17 -0
  73. package/lib/typescript/src/support/ReportedIssueEventSource.d.ts +24 -0
  74. package/lib/typescript/src/support/escalateTool.d.ts +5 -0
  75. package/lib/typescript/src/support/index.d.ts +2 -1
  76. package/lib/typescript/src/support/reportIssueTool.d.ts +20 -0
  77. package/lib/typescript/src/support/types.d.ts +56 -1
  78. package/lib/typescript/src/utils/logger.d.ts +15 -0
  79. package/package.json +20 -9
  80. package/react-native.config.js +12 -0
  81. package/lib/module/__cli_tmp__.js.map +0 -1
  82. package/lib/module/components/AIAgent.js.map +0 -1
  83. package/lib/module/components/AIZone.js.map +0 -1
  84. package/lib/module/components/AgentChatBar.js.map +0 -1
  85. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  86. package/lib/module/components/AgentOverlay.js.map +0 -1
  87. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  88. package/lib/module/components/HighlightOverlay.js.map +0 -1
  89. package/lib/module/components/Icons.js.map +0 -1
  90. package/lib/module/components/ProactiveHint.js.map +0 -1
  91. package/lib/module/components/cards/InfoCard.js.map +0 -1
  92. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  93. package/lib/module/config/endpoints.js.map +0 -1
  94. package/lib/module/core/ActionRegistry.js.map +0 -1
  95. package/lib/module/core/AgentRuntime.js.map +0 -1
  96. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  97. package/lib/module/core/IdleDetector.js.map +0 -1
  98. package/lib/module/core/MCPBridge.js.map +0 -1
  99. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  100. package/lib/module/core/ZoneRegistry.js.map +0 -1
  101. package/lib/module/core/systemPrompt.js.map +0 -1
  102. package/lib/module/core/types.js.map +0 -1
  103. package/lib/module/hooks/useAction.js.map +0 -1
  104. package/lib/module/index.js.map +0 -1
  105. package/lib/module/plugin/withAppIntents.js.map +0 -1
  106. package/lib/module/providers/GeminiProvider.js.map +0 -1
  107. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  108. package/lib/module/providers/ProviderFactory.js.map +0 -1
  109. package/lib/module/services/AudioInputService.js.map +0 -1
  110. package/lib/module/services/AudioOutputService.js.map +0 -1
  111. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  112. package/lib/module/services/VoiceService.js.map +0 -1
  113. package/lib/module/services/flags/FlagService.js.map +0 -1
  114. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  115. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  116. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  117. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  118. package/lib/module/services/telemetry/device.js.map +0 -1
  119. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  120. package/lib/module/services/telemetry/index.js.map +0 -1
  121. package/lib/module/services/telemetry/types.js.map +0 -1
  122. package/lib/module/support/CSATSurvey.js.map +0 -1
  123. package/lib/module/support/EscalationEventSource.js.map +0 -1
  124. package/lib/module/support/EscalationSocket.js.map +0 -1
  125. package/lib/module/support/SupportChatModal.js.map +0 -1
  126. package/lib/module/support/SupportGreeting.js.map +0 -1
  127. package/lib/module/support/TicketStore.js.map +0 -1
  128. package/lib/module/support/escalateTool.js.map +0 -1
  129. package/lib/module/support/index.js.map +0 -1
  130. package/lib/module/support/supportPrompt.js.map +0 -1
  131. package/lib/module/support/types.js.map +0 -1
  132. package/lib/module/tools/datePickerTool.js.map +0 -1
  133. package/lib/module/tools/guideTool.js.map +0 -1
  134. package/lib/module/tools/index.js.map +0 -1
  135. package/lib/module/tools/keyboardTool.js.map +0 -1
  136. package/lib/module/tools/longPressTool.js.map +0 -1
  137. package/lib/module/tools/pickerTool.js.map +0 -1
  138. package/lib/module/tools/restoreTool.js.map +0 -1
  139. package/lib/module/tools/scrollTool.js.map +0 -1
  140. package/lib/module/tools/simplifyTool.js.map +0 -1
  141. package/lib/module/tools/sliderTool.js.map +0 -1
  142. package/lib/module/tools/tapTool.js.map +0 -1
  143. package/lib/module/tools/typeTool.js.map +0 -1
  144. package/lib/module/tools/types.js.map +0 -1
  145. package/lib/module/types/jsx.d.js.map +0 -1
  146. package/lib/module/utils/audioUtils.js.map +0 -1
  147. package/lib/module/utils/logger.js.map +0 -1
  148. package/lib/typescript/babel.config.d.ts.map +0 -1
  149. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  150. package/lib/typescript/eslint.config.d.mts.map +0 -1
  151. package/lib/typescript/generate-map.d.ts.map +0 -1
  152. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  153. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  154. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  155. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  156. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  157. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  158. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  159. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  160. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  161. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  162. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  163. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  164. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  165. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  166. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  167. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  168. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  169. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  170. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  171. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  172. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  173. package/lib/typescript/src/core/types.d.ts.map +0 -1
  174. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  175. package/lib/typescript/src/index.d.ts.map +0 -1
  176. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  177. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  178. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  179. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  180. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  181. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  182. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  183. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  184. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  185. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  186. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  187. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  188. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  189. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  190. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  191. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  192. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  193. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  194. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  195. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  196. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  197. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  198. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  199. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  200. package/lib/typescript/src/support/index.d.ts.map +0 -1
  201. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  202. package/lib/typescript/src/support/types.d.ts.map +0 -1
  203. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  204. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  205. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  206. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  207. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  208. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  209. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  210. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  211. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  212. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  213. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  214. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  215. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  216. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  217. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  218. package/src/__cli_tmp__.tsx +0 -9
  219. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  220. package/src/cli/extractors/ai-extractor.ts +0 -6
  221. package/src/cli/extractors/ast-extractor.ts +0 -551
  222. package/src/cli/generate-intents.ts +0 -140
  223. package/src/cli/generate-map.ts +0 -121
  224. package/src/cli/generate-swift.ts +0 -116
  225. package/src/cli/scanners/expo-scanner.ts +0 -203
  226. package/src/cli/scanners/rn-scanner.ts +0 -445
  227. package/src/components/AIAgent.tsx +0 -1716
  228. package/src/components/AIZone.tsx +0 -147
  229. package/src/components/AgentChatBar.tsx +0 -1143
  230. package/src/components/AgentErrorBoundary.tsx +0 -78
  231. package/src/components/AgentOverlay.tsx +0 -73
  232. package/src/components/DiscoveryTooltip.tsx +0 -148
  233. package/src/components/HighlightOverlay.tsx +0 -136
  234. package/src/components/Icons.tsx +0 -253
  235. package/src/components/ProactiveHint.tsx +0 -145
  236. package/src/components/cards/InfoCard.tsx +0 -58
  237. package/src/components/cards/ReviewSummary.tsx +0 -76
  238. package/src/config/endpoints.ts +0 -22
  239. package/src/core/ActionRegistry.ts +0 -105
  240. package/src/core/AgentRuntime.ts +0 -1471
  241. package/src/core/FiberTreeWalker.ts +0 -930
  242. package/src/core/IdleDetector.ts +0 -72
  243. package/src/core/MCPBridge.ts +0 -163
  244. package/src/core/ScreenDehydrator.ts +0 -53
  245. package/src/core/ZoneRegistry.ts +0 -44
  246. package/src/core/systemPrompt.ts +0 -431
  247. package/src/core/types.ts +0 -521
  248. package/src/hooks/useAction.ts +0 -182
  249. package/src/index.ts +0 -83
  250. package/src/plugin/withAppIntents.ts +0 -98
  251. package/src/providers/GeminiProvider.ts +0 -357
  252. package/src/providers/OpenAIProvider.ts +0 -379
  253. package/src/providers/ProviderFactory.ts +0 -36
  254. package/src/services/AudioInputService.ts +0 -226
  255. package/src/services/AudioOutputService.ts +0 -236
  256. package/src/services/KnowledgeBaseService.ts +0 -156
  257. package/src/services/VoiceService.ts +0 -451
  258. package/src/services/flags/FlagService.ts +0 -137
  259. package/src/services/telemetry/MobileAI.ts +0 -66
  260. package/src/services/telemetry/PiiScrubber.ts +0 -17
  261. package/src/services/telemetry/TelemetryService.ts +0 -323
  262. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  263. package/src/services/telemetry/device.ts +0 -93
  264. package/src/services/telemetry/deviceMetadata.ts +0 -13
  265. package/src/services/telemetry/index.ts +0 -13
  266. package/src/services/telemetry/types.ts +0 -75
  267. package/src/support/CSATSurvey.tsx +0 -304
  268. package/src/support/EscalationEventSource.ts +0 -190
  269. package/src/support/EscalationSocket.ts +0 -152
  270. package/src/support/SupportChatModal.tsx +0 -563
  271. package/src/support/SupportGreeting.tsx +0 -161
  272. package/src/support/TicketStore.ts +0 -100
  273. package/src/support/escalateTool.ts +0 -174
  274. package/src/support/index.ts +0 -29
  275. package/src/support/supportPrompt.ts +0 -55
  276. package/src/support/types.ts +0 -155
  277. package/src/tools/datePickerTool.ts +0 -60
  278. package/src/tools/guideTool.ts +0 -76
  279. package/src/tools/index.ts +0 -20
  280. package/src/tools/keyboardTool.ts +0 -30
  281. package/src/tools/longPressTool.ts +0 -61
  282. package/src/tools/pickerTool.ts +0 -115
  283. package/src/tools/restoreTool.ts +0 -33
  284. package/src/tools/scrollTool.ts +0 -156
  285. package/src/tools/simplifyTool.ts +0 -33
  286. package/src/tools/sliderTool.ts +0 -65
  287. package/src/tools/tapTool.ts +0 -93
  288. package/src/tools/typeTool.ts +0 -113
  289. package/src/tools/types.ts +0 -58
  290. package/src/types/jsx.d.ts +0 -20
  291. package/src/utils/audioUtils.ts +0 -54
  292. package/src/utils/logger.ts +0 -38
@@ -1,78 +0,0 @@
1
- /**
2
- * AgentErrorBoundary — Catches React rendering errors caused by AI agent actions.
3
- *
4
- * When the AI taps, scrolls, or navigates, the action itself may succeed
5
- * but trigger async side-effects (useEffect, onViewableItemsChanged) that
6
- * crash during the next React render cycle. This boundary catches those
7
- * errors, preventing red screen crashes and auto-recovering the UI.
8
- *
9
- * Recovery strategy:
10
- * 1. Catch the error via getDerivedStateFromError
11
- * 2. Log it and report to agent runtime via onError callback
12
- * 3. Auto-reset after a brief delay — remounts children cleanly
13
- */
14
-
15
- import React from 'react';
16
- import { logger } from '../utils/logger';
17
-
18
- interface Props {
19
- children: React.ReactNode;
20
- /** Called when an error is caught — reports back to agent runtime */
21
- onError?: (error: Error, componentStack?: string) => void;
22
- telemetryRef?: React.RefObject<any>; // Using any to avoid circular import, we duck-type track()
23
- }
24
-
25
- interface State {
26
- hasError: boolean;
27
- }
28
-
29
- export class AgentErrorBoundary extends React.Component<Props, State> {
30
- state: State = { hasError: false };
31
- private resetTimer: ReturnType<typeof setTimeout> | null = null;
32
-
33
- static getDerivedStateFromError(_error: Error): State {
34
- return { hasError: true };
35
- }
36
-
37
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
38
- const componentStack = errorInfo?.componentStack || '';
39
- logger.warn(
40
- 'AgentErrorBoundary',
41
- `🛡️ Caught rendering error: ${error.message}\n${componentStack}`
42
- );
43
- this.props.onError?.(error, componentStack);
44
-
45
- // Track the render error silently in analytics
46
- if (this.props.telemetryRef?.current?.track) {
47
- this.props.telemetryRef.current.track('render_error', {
48
- message: error.message,
49
- component: componentStack?.split('\n')[1]?.trim() ?? 'unknown',
50
- screen: this.props.telemetryRef.current.screen,
51
- });
52
- }
53
- }
54
-
55
- componentDidUpdate(_prevProps: Props, prevState: State): void {
56
- // Auto-recover: reset error state after brief delay to remount children
57
- if (this.state.hasError && !prevState.hasError) {
58
- this.resetTimer = setTimeout(() => {
59
- this.setState({ hasError: false });
60
- }, 50);
61
- }
62
- }
63
-
64
- componentWillUnmount(): void {
65
- if (this.resetTimer) {
66
- clearTimeout(this.resetTimer);
67
- }
68
- }
69
-
70
- render(): React.ReactNode {
71
- if (this.state.hasError) {
72
- // Return null briefly — children will remount on next tick
73
- // when hasError resets to false via componentDidUpdate
74
- return null;
75
- }
76
- return this.props.children;
77
- }
78
- }
@@ -1,73 +0,0 @@
1
- /**
2
- * AgentOverlay — Subtle thinking indicator shown while the AI agent is processing.
3
- * Includes a cancel button to stop the agent mid-execution.
4
- */
5
-
6
- import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity } from 'react-native';
7
- import { CloseIcon } from './Icons';
8
-
9
- interface AgentOverlayProps {
10
- visible: boolean;
11
- statusText: string;
12
- onCancel?: () => void;
13
- }
14
-
15
- export function AgentOverlay({ visible, statusText, onCancel }: AgentOverlayProps) {
16
- if (!visible) return null;
17
-
18
- return (
19
- <View style={styles.overlay} pointerEvents="box-none">
20
- <View style={styles.pill}>
21
- <ActivityIndicator size="small" color="#fff" />
22
- <Text style={styles.text}>{statusText || 'Thinking...'}</Text>
23
- {onCancel && (
24
- <TouchableOpacity
25
- onPress={onCancel}
26
- style={styles.cancelButton}
27
- hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
28
- >
29
- <CloseIcon size={12} color="#fff" />
30
- </TouchableOpacity>
31
- )}
32
- </View>
33
- </View>
34
- );
35
- }
36
-
37
- const styles = StyleSheet.create({
38
- overlay: {
39
- position: 'absolute',
40
- top: 60,
41
- left: 0,
42
- right: 0,
43
- alignItems: 'center',
44
- zIndex: 9999,
45
- },
46
- pill: {
47
- flexDirection: 'row',
48
- alignItems: 'center',
49
- gap: 8,
50
- backgroundColor: 'rgba(26, 26, 46, 0.9)',
51
- paddingHorizontal: 16,
52
- paddingVertical: 10,
53
- borderRadius: 20,
54
- maxWidth: '85%',
55
- },
56
- text: {
57
- color: '#fff',
58
- fontSize: 14,
59
- fontWeight: '500',
60
- flexShrink: 1,
61
- },
62
- cancelButton: {
63
- marginLeft: 4,
64
- width: 22,
65
- height: 22,
66
- borderRadius: 11,
67
- backgroundColor: 'rgba(255, 255, 255, 0.2)',
68
- alignItems: 'center',
69
- justifyContent: 'center',
70
- flexShrink: 0,
71
- },
72
- });
73
-
@@ -1,148 +0,0 @@
1
- /**
2
- * DiscoveryTooltip — One-time tooltip shown above the FAB on first use.
3
- *
4
- * Tells users the AI can navigate the app and do things for them.
5
- * Shows once, then persists dismissal via AsyncStorage.
6
- * Bilingual: EN/AR.
7
- */
8
-
9
- import { useEffect, useRef } from 'react';
10
- import {
11
- View,
12
- Text,
13
- Pressable,
14
- StyleSheet,
15
- Animated,
16
- } from 'react-native';
17
-
18
- interface DiscoveryTooltipProps {
19
- language: 'en' | 'ar';
20
- primaryColor?: string;
21
- onDismiss: () => void;
22
- }
23
-
24
- const LABELS = {
25
- en: '✨ I can help you navigate the app and do things for you!',
26
- ar: '✨ أقدر أساعدك تتنقل في التطبيق وأعمل حاجات بدالك!',
27
- };
28
-
29
- const AUTO_DISMISS_MS = 6000;
30
-
31
- export function DiscoveryTooltip({
32
- language,
33
- primaryColor,
34
- onDismiss,
35
- }: DiscoveryTooltipProps) {
36
- const scaleAnim = useRef(new Animated.Value(0)).current;
37
- const opacityAnim = useRef(new Animated.Value(0)).current;
38
-
39
- useEffect(() => {
40
- // Spring-in entry
41
- Animated.parallel([
42
- Animated.spring(scaleAnim, {
43
- toValue: 1,
44
- friction: 6,
45
- tension: 80,
46
- useNativeDriver: true,
47
- }),
48
- Animated.timing(opacityAnim, {
49
- toValue: 1,
50
- duration: 200,
51
- useNativeDriver: true,
52
- }),
53
- ]).start();
54
-
55
- // Auto-dismiss after timeout
56
- const timer = setTimeout(() => {
57
- dismissWithAnimation();
58
- }, AUTO_DISMISS_MS);
59
-
60
- return () => clearTimeout(timer);
61
- // eslint-disable-next-line react-hooks/exhaustive-deps
62
- }, []);
63
-
64
- const dismissWithAnimation = () => {
65
- Animated.parallel([
66
- Animated.timing(scaleAnim, {
67
- toValue: 0,
68
- duration: 200,
69
- useNativeDriver: true,
70
- }),
71
- Animated.timing(opacityAnim, {
72
- toValue: 0,
73
- duration: 200,
74
- useNativeDriver: true,
75
- }),
76
- ]).start(() => onDismiss());
77
- };
78
-
79
- const isArabic = language === 'ar';
80
- const bgColor = primaryColor || '#1a1a2e';
81
-
82
- return (
83
- <Animated.View
84
- style={[
85
- styles.container,
86
- {
87
- backgroundColor: bgColor,
88
- transform: [{ scale: scaleAnim }],
89
- opacity: opacityAnim,
90
- },
91
- ]}
92
- >
93
- <Pressable onPress={dismissWithAnimation} style={styles.contentArea}>
94
- <Text style={[styles.text, isArabic && styles.textRTL]}>
95
- {LABELS[language]}
96
- </Text>
97
- </Pressable>
98
-
99
- {/* Triangle pointer toward FAB */}
100
- <View style={[styles.pointer, { borderTopColor: bgColor }]} />
101
- </Animated.View>
102
- );
103
- }
104
-
105
- const styles = StyleSheet.create({
106
- container: {
107
- position: 'absolute',
108
- bottom: 70,
109
- right: -4,
110
- minWidth: 200,
111
- maxWidth: 260,
112
- borderRadius: 16,
113
- paddingHorizontal: 14,
114
- paddingVertical: 10,
115
- shadowColor: '#000',
116
- shadowOffset: { width: 0, height: 4 },
117
- shadowOpacity: 0.3,
118
- shadowRadius: 8,
119
- elevation: 6,
120
- },
121
- contentArea: {
122
- flexDirection: 'row',
123
- alignItems: 'center',
124
- },
125
- text: {
126
- color: '#ffffff',
127
- fontSize: 13,
128
- lineHeight: 19,
129
- fontWeight: '500',
130
- },
131
- textRTL: {
132
- textAlign: 'right',
133
- writingDirection: 'rtl',
134
- },
135
- pointer: {
136
- position: 'absolute',
137
- bottom: -8,
138
- right: 22,
139
- width: 0,
140
- height: 0,
141
- borderLeftWidth: 8,
142
- borderRightWidth: 8,
143
- borderTopWidth: 8,
144
- borderLeftColor: 'transparent',
145
- borderRightColor: 'transparent',
146
- borderTopColor: '#1a1a2e',
147
- },
148
- });
@@ -1,136 +0,0 @@
1
- import { useEffect, useState, useRef } from 'react';
2
- import { View, Text, StyleSheet, Animated, Pressable, DeviceEventEmitter } from 'react-native';
3
-
4
- export interface HighlightEventData {
5
- pageX: number;
6
- pageY: number;
7
- width: number;
8
- height: number;
9
- message: string;
10
- autoRemoveAfterMs?: number;
11
- }
12
-
13
- export function HighlightOverlay() {
14
- const [highlight, setHighlight] = useState<HighlightEventData | null>(null);
15
- const pulseAnim = useRef(new Animated.Value(1)).current;
16
- const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
17
-
18
- useEffect(() => {
19
- const sub = DeviceEventEmitter.addListener('MOBILE_AI_HIGHLIGHT', (data: HighlightEventData | null) => {
20
- if (timerRef.current) clearTimeout(timerRef.current);
21
-
22
- setHighlight(data);
23
-
24
- if (data) {
25
- // Start pulsing ring
26
- pulseAnim.setValue(1);
27
- Animated.loop(
28
- Animated.sequence([
29
- Animated.timing(pulseAnim, { toValue: 1.2, duration: 800, useNativeDriver: true }),
30
- Animated.timing(pulseAnim, { toValue: 1, duration: 800, useNativeDriver: true }),
31
- ])
32
- ).start();
33
-
34
- // Auto-dismiss
35
- const ms = data.autoRemoveAfterMs || 5000;
36
- timerRef.current = setTimeout(() => {
37
- setHighlight(null);
38
- }, ms);
39
- }
40
- });
41
-
42
- return () => sub.remove();
43
- }, [pulseAnim]);
44
-
45
- if (!highlight) return null;
46
-
47
- const { pageX, pageY, width, height, message } = highlight;
48
-
49
- // Calculate tooltip position (prefer top, fallback to bottom if too close to top edge)
50
- const isTooHigh = pageY < 60;
51
- const tooltipTop = isTooHigh ? pageY + height + 12 : pageY - 45;
52
-
53
- return (
54
- <View style={StyleSheet.absoluteFill} pointerEvents="box-none">
55
- {/* Invisible pressable to dismiss on tap anywhere */}
56
- <Pressable testID="highlight-close-zone" style={StyleSheet.absoluteFill} onPress={() => setHighlight(null)} />
57
-
58
- {/* The Animated Ring */}
59
- <Animated.View
60
- style={[
61
- styles.ring,
62
- {
63
- left: pageX - 4,
64
- top: pageY - 4,
65
- width: width + 8,
66
- height: height + 8,
67
- transform: [{ scale: pulseAnim }],
68
- }
69
- ]}
70
- pointerEvents="none"
71
- />
72
-
73
- {/* The Tooltip */}
74
- <View style={[styles.tooltip, { top: tooltipTop }]} pointerEvents="none">
75
- <Text style={styles.message}>{message}</Text>
76
- <View style={isTooHigh ? styles.arrowUp : styles.arrowDown} />
77
- </View>
78
- </View>
79
- );
80
- }
81
-
82
- const styles = StyleSheet.create({
83
- ring: {
84
- position: 'absolute',
85
- borderWidth: 3,
86
- borderColor: '#007AFF', // iOS blue
87
- borderRadius: 8,
88
- backgroundColor: 'rgba(0, 122, 255, 0.15)', // Very subtle fill
89
- },
90
- tooltip: {
91
- position: 'absolute',
92
- alignSelf: 'center',
93
- backgroundColor: '#007AFF',
94
- paddingHorizontal: 12,
95
- paddingVertical: 8,
96
- borderRadius: 8,
97
- maxWidth: '80%',
98
- shadowColor: '#000',
99
- shadowOpacity: 0.2,
100
- shadowOffset: { width: 0, height: 2 },
101
- shadowRadius: 4,
102
- elevation: 4,
103
- },
104
- message: {
105
- color: '#fff',
106
- fontSize: 14,
107
- fontWeight: 'bold',
108
- textAlign: 'center',
109
- },
110
- arrowDown: {
111
- position: 'absolute',
112
- bottom: -6,
113
- alignSelf: 'center',
114
- width: 0,
115
- height: 0,
116
- borderLeftWidth: 6,
117
- borderRightWidth: 6,
118
- borderTopWidth: 6,
119
- borderLeftColor: 'transparent',
120
- borderRightColor: 'transparent',
121
- borderTopColor: '#007AFF',
122
- },
123
- arrowUp: {
124
- position: 'absolute',
125
- top: -6,
126
- alignSelf: 'center',
127
- width: 0,
128
- height: 0,
129
- borderLeftWidth: 6,
130
- borderRightWidth: 6,
131
- borderBottomWidth: 6,
132
- borderLeftColor: 'transparent',
133
- borderRightColor: 'transparent',
134
- borderBottomColor: '#007AFF',
135
- }
136
- });
@@ -1,253 +0,0 @@
1
- /**
2
- * Icons — Zero-dependency, View-based icons for the AI Agent chat bar.
3
- *
4
- * Why not emoji? iOS Simulator 26+ has a bug where emoji renders as "?".
5
- * Why not Unicode symbols? They look obscure and unprofessional.
6
- * Why not icon libraries? This is a library — zero runtime dependencies.
7
- *
8
- * These icons are built purely from React Native View components,
9
- * rendering identically on every platform and screen size.
10
- */
11
-
12
- import { View } from 'react-native';
13
-
14
- // ─── Mic Icon (pill + stem + base) ────────────────────────────
15
-
16
- export function MicIcon({ size = 20, color = '#fff' }: { size?: number; color?: string }) {
17
- const pillW = size * 0.4;
18
- const pillH = size * 0.5;
19
- const stemW = size * 0.08;
20
- const stemH = size * 0.18;
21
- const baseW = size * 0.35;
22
- const arcW = size * 0.55;
23
- const arcH = size * 0.35;
24
- const arcBorder = size * 0.07;
25
-
26
- return (
27
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
28
- {/* Pill (mic head) */}
29
- <View style={{
30
- width: pillW,
31
- height: pillH,
32
- borderRadius: pillW / 2,
33
- backgroundColor: color,
34
- }} />
35
- {/* Arc (U-shape around mic) */}
36
- <View style={{
37
- width: arcW,
38
- height: arcH,
39
- borderBottomLeftRadius: arcW / 2,
40
- borderBottomRightRadius: arcW / 2,
41
- borderWidth: arcBorder,
42
- borderTopWidth: 0,
43
- borderColor: color,
44
- marginTop: -(pillH * 0.3),
45
- }} />
46
- {/* Stem */}
47
- <View style={{
48
- width: stemW,
49
- height: stemH,
50
- backgroundColor: color,
51
- marginTop: -1,
52
- }} />
53
- {/* Base */}
54
- <View style={{
55
- width: baseW,
56
- height: stemW,
57
- backgroundColor: color,
58
- borderRadius: stemW / 2,
59
- }} />
60
- </View>
61
- );
62
- }
63
-
64
- // ─── Speaker Icon (cone + sound waves) ────────────────────────
65
-
66
- export function SpeakerIcon({ size = 20, color = '#fff', muted = false }: { size?: number; color?: string; muted?: boolean }) {
67
- const bodyW = size * 0.25;
68
- const bodyH = size * 0.3;
69
- const coneW = size * 0.2;
70
-
71
- return (
72
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center', flexDirection: 'row' }}>
73
- {/* Speaker body (rectangle) */}
74
- <View style={{
75
- width: bodyW,
76
- height: bodyH,
77
- backgroundColor: color,
78
- borderRadius: size * 0.03,
79
- }} />
80
- {/* Speaker cone (triangle via borders) */}
81
- <View style={{
82
- width: 0,
83
- height: 0,
84
- borderTopWidth: size * 0.25,
85
- borderTopColor: 'transparent',
86
- borderBottomWidth: size * 0.25,
87
- borderBottomColor: 'transparent',
88
- borderLeftWidth: coneW,
89
- borderLeftColor: color,
90
- marginLeft: -1,
91
- }} />
92
- {muted ? (
93
- /* Mute slash */
94
- <View style={{
95
- position: 'absolute',
96
- width: size * 0.08,
97
- height: size * 0.8,
98
- backgroundColor: color,
99
- borderRadius: size * 0.04,
100
- transform: [{ rotate: '45deg' }],
101
- }} />
102
- ) : (
103
- /* Sound waves */
104
- <View style={{ marginLeft: size * 0.05 }}>
105
- <View style={{
106
- width: size * 0.15,
107
- height: size * 0.3,
108
- borderWidth: size * 0.05,
109
- borderColor: color,
110
- borderLeftWidth: 0,
111
- borderTopLeftRadius: 0,
112
- borderBottomLeftRadius: 0,
113
- borderTopRightRadius: size * 0.15,
114
- borderBottomRightRadius: size * 0.15,
115
- }} />
116
- </View>
117
- )}
118
- </View>
119
- );
120
- }
121
-
122
- // ─── Send Arrow (upward arrow) ────────────────────────────────
123
-
124
- export function SendArrowIcon({ size = 18, color = '#fff' }: { size?: number; color?: string }) {
125
- // Filled right-pointing triangle (like iOS Messages send button)
126
- const triH = size * 0.55;
127
- return (
128
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
129
- <View style={{
130
- width: 0,
131
- height: 0,
132
- borderTopWidth: triH / 2,
133
- borderTopColor: 'transparent',
134
- borderBottomWidth: triH / 2,
135
- borderBottomColor: 'transparent',
136
- borderLeftWidth: triH * 0.85,
137
- borderLeftColor: color,
138
- marginLeft: size * 0.1,
139
- }} />
140
- </View>
141
- );
142
- }
143
-
144
- // ─── Stop Icon (filled square) ────────────────────────────────
145
-
146
- export function StopIcon({ size = 18, color = '#fff' }: { size?: number; color?: string }) {
147
- const sq = size * 0.45;
148
- return (
149
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
150
- <View style={{
151
- width: sq,
152
- height: sq,
153
- backgroundColor: color,
154
- borderRadius: size * 0.05,
155
- }} />
156
- </View>
157
- );
158
- }
159
-
160
- // ─── Recording Dot (pulsing filled circle) ────────────────────
161
-
162
- export function RecordingDot({ size = 18, color = '#FF3B30' }: { size?: number; color?: string }) {
163
- const dotSize = size * 0.45;
164
- return (
165
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
166
- <View style={{
167
- width: dotSize,
168
- height: dotSize,
169
- borderRadius: dotSize / 2,
170
- backgroundColor: color,
171
- }} />
172
- </View>
173
- );
174
- }
175
-
176
- // ─── Loading Spinner (three dots) ─────────────────────────────
177
-
178
- export function LoadingDots({ size = 18, color = '#fff' }: { size?: number; color?: string }) {
179
- const dotSize = size * 0.15;
180
- return (
181
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center', flexDirection: 'row', gap: dotSize * 0.8 }}>
182
- {[0.4, 0.7, 1].map((opacity, i) => (
183
- <View key={i} style={{
184
- width: dotSize,
185
- height: dotSize,
186
- borderRadius: dotSize / 2,
187
- backgroundColor: color,
188
- opacity,
189
- }} />
190
- ))}
191
- </View>
192
- );
193
- }
194
-
195
- // ─── Close / Dismiss (X mark) ─────────────────────────────────
196
-
197
- export function CloseIcon({ size = 14, color = 'rgba(255,255,255,0.6)' }: { size?: number; color?: string }) {
198
- const barW = size * 0.7;
199
- const barH = size * 0.12;
200
- return (
201
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
202
- <View style={{
203
- position: 'absolute',
204
- width: barW,
205
- height: barH,
206
- backgroundColor: color,
207
- borderRadius: barH,
208
- transform: [{ rotate: '45deg' }],
209
- }} />
210
- <View style={{
211
- position: 'absolute',
212
- width: barW,
213
- height: barH,
214
- backgroundColor: color,
215
- borderRadius: barH,
216
- transform: [{ rotate: '-45deg' }],
217
- }} />
218
- </View>
219
- );
220
- }
221
-
222
- // ─── AI Badge (for FAB) ───────────────────────────────────────
223
-
224
- export function AIBadge({ size = 28 }: { size?: number }) {
225
- // Chat bubble — clean, universally represents AI assistant
226
- const bubbleW = size * 0.6;
227
- const bubbleH = size * 0.45;
228
- const tailSize = size * 0.12;
229
- return (
230
- <View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
231
- {/* Bubble body */}
232
- <View style={{
233
- width: bubbleW,
234
- height: bubbleH,
235
- backgroundColor: '#fff',
236
- borderRadius: size * 0.12,
237
- marginBottom: tailSize * 0.5,
238
- }} />
239
- {/* Tail (small triangle at bottom-left) */}
240
- <View style={{
241
- position: 'absolute',
242
- bottom: size * 0.18,
243
- left: size * 0.22,
244
- width: 0,
245
- height: 0,
246
- borderTopWidth: tailSize,
247
- borderTopColor: '#fff',
248
- borderRightWidth: tailSize,
249
- borderRightColor: 'transparent',
250
- }} />
251
- </View>
252
- );
253
- }