@revrag-ai/embed-react-native 1.0.26 → 1.0.28

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 (111) hide show
  1. package/README.md +5 -0
  2. package/android/build.gradle +1 -0
  3. package/dist/commonjs/api/api.js.map +1 -1
  4. package/dist/commonjs/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
  5. package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
  6. package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
  7. package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
  8. package/dist/commonjs/components/DynamicComponent/Typewriter.js +124 -0
  9. package/dist/commonjs/components/DynamicComponent/Typewriter.js.map +1 -0
  10. package/dist/commonjs/components/Embed/EmbedButton.js +362 -113
  11. package/dist/commonjs/components/Embed/EmbedButton.js.map +1 -1
  12. package/dist/commonjs/components/styles/EmbedButton.style.js +112 -158
  13. package/dist/commonjs/components/styles/EmbedButton.style.js.map +1 -1
  14. package/dist/commonjs/context/EmbedProvider.js +187 -14
  15. package/dist/commonjs/context/EmbedProvider.js.map +1 -1
  16. package/dist/commonjs/events/clickEventTracker.js +210 -0
  17. package/dist/commonjs/events/clickEventTracker.js.map +1 -0
  18. package/dist/commonjs/events/embed.event.js +11 -3
  19. package/dist/commonjs/events/embed.event.js.map +1 -1
  20. package/dist/commonjs/hooks/EmbedButton.animations.js +115 -15
  21. package/dist/commonjs/hooks/EmbedButton.animations.js.map +1 -1
  22. package/dist/commonjs/hooks/EmbedButton.helpers.js +11 -3
  23. package/dist/commonjs/hooks/EmbedButton.helpers.js.map +1 -1
  24. package/dist/commonjs/hooks/EmbedButton.hooks.js +17 -11
  25. package/dist/commonjs/hooks/EmbedButton.hooks.js.map +1 -1
  26. package/dist/commonjs/hooks/voiceagent.js +34 -12
  27. package/dist/commonjs/hooks/voiceagent.js.map +1 -1
  28. package/dist/commonjs/index.js +6 -2
  29. package/dist/commonjs/index.js.map +1 -1
  30. package/dist/commonjs/utils/constant.js +6 -1
  31. package/dist/commonjs/utils/constant.js.map +1 -1
  32. package/dist/commonjs/utils/permision.js +42 -1
  33. package/dist/commonjs/utils/permision.js.map +1 -1
  34. package/dist/commonjs/utils/reanimated.helper.js +4 -0
  35. package/dist/commonjs/utils/reanimated.helper.js.map +1 -1
  36. package/dist/module/api/api.js.map +1 -1
  37. package/dist/module/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
  38. package/dist/module/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
  39. package/dist/module/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
  40. package/dist/module/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
  41. package/dist/module/components/DynamicComponent/Typewriter.js +122 -0
  42. package/dist/module/components/DynamicComponent/Typewriter.js.map +1 -0
  43. package/dist/module/components/Embed/EmbedButton.js +367 -118
  44. package/dist/module/components/Embed/EmbedButton.js.map +1 -1
  45. package/dist/module/components/styles/EmbedButton.style.js +111 -157
  46. package/dist/module/components/styles/EmbedButton.style.js.map +1 -1
  47. package/dist/module/context/EmbedProvider.js +187 -14
  48. package/dist/module/context/EmbedProvider.js.map +1 -1
  49. package/dist/module/events/clickEventTracker.js +199 -0
  50. package/dist/module/events/clickEventTracker.js.map +1 -0
  51. package/dist/module/events/embed.event.js +11 -3
  52. package/dist/module/events/embed.event.js.map +1 -1
  53. package/dist/module/hooks/EmbedButton.animations.js +109 -13
  54. package/dist/module/hooks/EmbedButton.animations.js.map +1 -1
  55. package/dist/module/hooks/EmbedButton.helpers.js +10 -2
  56. package/dist/module/hooks/EmbedButton.helpers.js.map +1 -1
  57. package/dist/module/hooks/EmbedButton.hooks.js +17 -11
  58. package/dist/module/hooks/EmbedButton.hooks.js.map +1 -1
  59. package/dist/module/hooks/voiceagent.js +34 -12
  60. package/dist/module/hooks/voiceagent.js.map +1 -1
  61. package/dist/module/index.js +8 -3
  62. package/dist/module/index.js.map +1 -1
  63. package/dist/module/utils/constant.js +6 -1
  64. package/dist/module/utils/constant.js.map +1 -1
  65. package/dist/module/utils/permision.js +42 -1
  66. package/dist/module/utils/permision.js.map +1 -1
  67. package/dist/module/utils/reanimated.helper.js +4 -0
  68. package/dist/module/utils/reanimated.helper.js.map +1 -1
  69. package/dist/typescript/src/api/api.d.ts.map +1 -1
  70. package/dist/typescript/src/components/DynamicComponent/Typewriter.d.ts +15 -0
  71. package/dist/typescript/src/components/DynamicComponent/Typewriter.d.ts.map +1 -0
  72. package/dist/typescript/src/components/Embed/EmbedButton.d.ts +7 -1
  73. package/dist/typescript/src/components/Embed/EmbedButton.d.ts.map +1 -1
  74. package/dist/typescript/src/components/styles/EmbedButton.style.d.ts +22 -114
  75. package/dist/typescript/src/components/styles/EmbedButton.style.d.ts.map +1 -1
  76. package/dist/typescript/src/context/EmbedProvider.d.ts +30 -0
  77. package/dist/typescript/src/context/EmbedProvider.d.ts.map +1 -1
  78. package/dist/typescript/src/events/__tests__/agent-event-emitter.test.d.ts +5 -0
  79. package/dist/typescript/src/events/__tests__/agent-event-emitter.test.d.ts.map +1 -0
  80. package/dist/typescript/src/events/__tests__/clickEventTracker.test.d.ts +5 -0
  81. package/dist/typescript/src/events/__tests__/clickEventTracker.test.d.ts.map +1 -0
  82. package/dist/typescript/src/events/__tests__/embed.event.test.d.ts +5 -0
  83. package/dist/typescript/src/events/__tests__/embed.event.test.d.ts.map +1 -0
  84. package/dist/typescript/src/events/__tests__/embed.validators.test.d.ts +5 -0
  85. package/dist/typescript/src/events/__tests__/embed.validators.test.d.ts.map +1 -0
  86. package/dist/typescript/src/events/clickEventTracker.d.ts +70 -0
  87. package/dist/typescript/src/events/clickEventTracker.d.ts.map +1 -0
  88. package/dist/typescript/src/events/embed.event.d.ts.map +1 -1
  89. package/dist/typescript/src/hooks/EmbedButton.animations.d.ts +29 -6
  90. package/dist/typescript/src/hooks/EmbedButton.animations.d.ts.map +1 -1
  91. package/dist/typescript/src/hooks/EmbedButton.helpers.d.ts +60 -8
  92. package/dist/typescript/src/hooks/EmbedButton.helpers.d.ts.map +1 -1
  93. package/dist/typescript/src/hooks/EmbedButton.hooks.d.ts +4 -2
  94. package/dist/typescript/src/hooks/EmbedButton.hooks.d.ts.map +1 -1
  95. package/dist/typescript/src/hooks/types/voiceAgent.types.d.ts +2 -0
  96. package/dist/typescript/src/hooks/types/voiceAgent.types.d.ts.map +1 -1
  97. package/dist/typescript/src/hooks/voiceagent.d.ts.map +1 -1
  98. package/dist/typescript/src/index.d.ts +8 -9
  99. package/dist/typescript/src/index.d.ts.map +1 -1
  100. package/dist/typescript/src/utils/constant.d.ts +1 -1
  101. package/dist/typescript/src/utils/constant.d.ts.map +1 -1
  102. package/dist/typescript/src/utils/permision.d.ts.map +1 -1
  103. package/dist/typescript/src/utils/reanimated.helper.d.ts +2 -0
  104. package/dist/typescript/src/utils/reanimated.helper.d.ts.map +1 -1
  105. package/package.json +3 -8
  106. package/react-native.config.js +1 -0
  107. package/revrag-ai-embed-react-native.podspec +1 -0
  108. package/src/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
  109. package/src/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
  110. package/src/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
  111. package/src/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
@@ -5,17 +5,19 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.EmbedButton = EmbedButton;
7
7
  exports.default = void 0;
8
+ var _livekitClient = require("livekit-client");
8
9
  var _lottieReactNative = _interopRequireDefault(require("lottie-react-native"));
9
10
  var _react = require("react");
10
11
  var _reactNative = require("react-native");
11
12
  var _reactNativeGestureHandler = require("react-native-gesture-handler");
12
13
  var _reactNativeLinearGradient = _interopRequireDefault(require("react-native-linear-gradient"));
14
+ var _embedEvent = _interopRequireWildcard(require("../../events/embed.event.js"));
13
15
  var _voiceagent = require("../../hooks/voiceagent.js");
14
16
  var _EmbedButtonStyle = require("../styles/EmbedButton.style.js");
15
17
  var _EmbedAudioWave = require("./EmbedAudioWave.js");
16
18
  var _EmbedVoice = _interopRequireDefault(require("./EmbedVoice.js"));
17
- var _embedEvent = _interopRequireWildcard(require("../../events/embed.event.js"));
18
19
  var _EmbedButtonHelpers = require("../../hooks/EmbedButton.helpers.js");
20
+ var _Typewriter = _interopRequireDefault(require("../DynamicComponent/Typewriter.js"));
19
21
  var _EmbedButtonHooks = require("../../hooks/EmbedButton.hooks.js");
20
22
  var _EmbedButtonAnimations = require("../../hooks/EmbedButton.animations.js");
21
23
  var _jsxRuntime = require("react/jsx-runtime");
@@ -50,35 +52,57 @@ const defaultStyles = {
50
52
  };
51
53
 
52
54
  // ==================== MAIN COMPONENT ====================
55
+
53
56
  /**
54
57
  * EmbedButton - Main voice agent floating action button
55
58
  *
56
59
  * @example
57
60
  * ```tsx
58
61
  * <EmbedButton />
62
+ * <EmbedButton containerInset={{ right: 16, bottom: 24 }} />
59
63
  * ```
60
64
  */
61
- function EmbedButton() {
65
+ function EmbedButton({
66
+ containerInset
67
+ } = {}) {
62
68
  // ==================== VOICE AGENT STATE ====================
63
69
  const {
64
- initializeVoiceAgent,
65
70
  tokenDetails,
66
- endCall,
67
71
  isLoading,
68
72
  isMicMuted,
73
+ connectionState,
74
+ roomRef,
69
75
  muteMic,
76
+ endCall,
70
77
  unmuteMic,
71
- connectionState,
72
- roomRef
78
+ clearDataReceived,
79
+ dataTranscription: livekitData,
80
+ initializeVoiceAgent
73
81
  } = (0, _voiceagent.useVoiceAgent)();
74
82
 
75
83
  // ==================== LOCAL STATE ====================
76
84
  const [isOpen, setIsOpen] = (0, _react.useState)(false);
85
+ const [expandDirection, setExpandDirection] = (0, _react.useState)('right');
77
86
  const lottieRef = (0, _react.useRef)(null);
78
- const styles = (0, _react.useMemo)(() => (0, _EmbedButtonStyle.createEmbedButtonStyles)(defaultStyles), []);
87
+ const calculationScrollRef = (0, _react.useRef)(null);
88
+ const userScrolledUpRef = (0, _react.useRef)(false);
89
+ const SCROLL_END_THRESHOLD = 20;
90
+
91
+ // Reset "user scrolled up" when calculation content changes so new content auto-scrolls to bottom
92
+ (0, _react.useEffect)(() => {
93
+ if (livekitData?.type === 'calculation') {
94
+ userScrolledUpRef.current = false;
95
+ }
96
+ }, [livekitData?.list, livekitData?.type]);
79
97
 
80
98
  // ==================== CUSTOM HOOKS ====================
81
99
  const configData = (0, _EmbedButtonHooks.useConfigData)();
100
+ const styles = (0, _react.useMemo)(() => (0, _EmbedButtonStyle.createEmbedButtonStyles)({
101
+ ...defaultStyles,
102
+ ...(containerInset != null && {
103
+ containerInset
104
+ })
105
+ }, configData), [configData, containerInset]);
82
106
  const {
83
107
  callDuration,
84
108
  resetDuration
@@ -88,13 +112,14 @@ function EmbedButton() {
88
112
  handleEndCall,
89
113
  handleMicToggle
90
114
  } = (0, _EmbedButtonHooks.useCallManagement)({
91
- initializeVoiceAgent,
115
+ isOpen,
116
+ isMicMuted,
92
117
  endCall,
93
118
  muteMic,
119
+ setIsOpen,
94
120
  unmuteMic,
95
- isMicMuted,
96
121
  resetDuration,
97
- setIsOpen
122
+ initializeVoiceAgent
98
123
  });
99
124
  const {
100
125
  isAutoOpen,
@@ -115,86 +140,175 @@ function EmbedButton() {
115
140
  start,
116
141
  menuAnimation,
117
142
  buttonWidth,
118
- buttonScale
143
+ buttonScale,
144
+ buttonHeight,
145
+ inputSectionProgress
119
146
  } = animationValues;
120
- (0, _EmbedButtonAnimations.useButtonAnimations)(isOpen, menuAnimation, buttonWidth);
147
+ (0, _EmbedButtonAnimations.useButtonAnimations)(isOpen || livekitData && Object.keys(livekitData).length > 0, menuAnimation, buttonWidth, offset, start, expandDirection);
148
+ (0, _EmbedButtonAnimations.useInputSectionAnimations)(livekitData && Object.keys(livekitData).length > 0, inputSectionProgress, buttonHeight);
121
149
  (0, _EmbedButtonAnimations.useBreathingAnimation)(isOpen, isAutoOpen, buttonScale);
122
- const buttonAnimatedStyles = (0, _EmbedButtonAnimations.useButtonAnimatedStyles)(isOpen, offset, buttonWidth, isPressed, buttonScale);
123
- const popupAnimatedStyles = (0, _EmbedButtonAnimations.usePopupAnimatedStyles)(offset, isPressed);
124
- const panGesture = (0, _react.useMemo)(() => (0, _EmbedButtonAnimations.createPanGesture)(isPressed, offset, start, isOpen, setIsAutoOpen), [isPressed, offset, start, isOpen, setIsAutoOpen]);
150
+ const buttonAnimatedStyles = (0, _EmbedButtonAnimations.useButtonAnimatedStyles)(isOpen, offset, buttonWidth, isPressed, buttonScale, buttonHeight);
151
+ const expandedContentAnimatedStyles = (0, _EmbedButtonAnimations.useExpandedContentAnimatedStyles)(menuAnimation);
152
+ const popupAnimatedStyles = (0, _EmbedButtonAnimations.usePopupAnimatedStyles)(offset, isPressed, expandDirection);
153
+ const panGesture = (0, _react.useMemo)(() => (0, _EmbedButtonAnimations.createPanGesture)(isPressed, offset, start, isOpen, setIsAutoOpen, setExpandDirection), [isPressed, offset, start, isOpen, setIsAutoOpen]);
125
154
 
126
155
  // ==================== AGENT EVENT EMISSIONS ====================
127
156
  // Emit agent connected/disconnected events based on connection state
157
+ // Track previous connection state to properly detect disconnection
158
+ const prevConnectionStateRef = (0, _react.useRef)(connectionState);
159
+ const lastEmittedEventRef = (0, _react.useRef)(null);
128
160
  (0, _react.useEffect)(() => {
129
- const emitConnectionEvent = async () => {
130
- if (connectionState === 'connected') {
131
- await _embedEvent.default.event.emit(_embedEvent.AgentEvent.AGENT_CONNECTED, {
132
- timestamp: new Date().toISOString(),
133
- metadata: {
134
- callDuration: 0
135
- }
136
- });
137
- } else if (connectionState === 'disconnected' && callDuration > 0) {
138
- // Only emit disconnected if we were previously connected
139
- await _embedEvent.default.event.emit(_embedEvent.AgentEvent.AGENT_DISCONNECTED, {
140
- timestamp: new Date().toISOString(),
141
- metadata: {
142
- callDuration
143
- }
144
- });
161
+ const prevState = prevConnectionStateRef.current;
162
+
163
+ // Check if we should emit connected event
164
+ if (connectionState === _livekitClient.ConnectionState.Connected && prevState !== _livekitClient.ConnectionState.Connected) {
165
+ // Prevent duplicate connected events
166
+ if (lastEmittedEventRef.current?.type === 'connected' && lastEmittedEventRef.current?.state === connectionState) {
167
+ return;
145
168
  }
146
- };
147
- emitConnectionEvent().catch(error => {
148
- console.error('Error emitting connection event:', error);
149
- });
150
- }, [connectionState]);
151
169
 
152
- // Emit popup visibility events when isAutoOpen changes
170
+ // Update refs IMMEDIATELY (synchronously) before async emit
171
+ prevConnectionStateRef.current = connectionState;
172
+ lastEmittedEventRef.current = {
173
+ type: 'connected',
174
+ state: connectionState
175
+ };
176
+
177
+ // Emit connected when entering Connected state
178
+ _embedEvent.default.event.emit(_embedEvent.AgentEvent.AGENT_CONNECTED, {
179
+ timestamp: new Date().toISOString(),
180
+ metadata: {
181
+ callDuration: 0
182
+ }
183
+ }).catch(error => {
184
+ console.error('Error emitting connected event:', error);
185
+ });
186
+
187
+ // Send analytics to backend when agent conversation has started (connected)
188
+ _embedEvent.default.Event(_embedEvent.EventKeys.ANALYTICS_DATA, {
189
+ event_name: 'agent_conversation_started'
190
+ }).catch(error => {
191
+ console.error('Error sending agent_conversation_started analytics:', error);
192
+ });
193
+ } else if (prevState === _livekitClient.ConnectionState.Connected && connectionState !== _livekitClient.ConnectionState.Connected) {
194
+ // Prevent duplicate disconnected events
195
+ if (lastEmittedEventRef.current?.type === 'disconnected') {
196
+ return;
197
+ }
198
+
199
+ // Update refs IMMEDIATELY (synchronously) before async emit
200
+ prevConnectionStateRef.current = connectionState;
201
+ lastEmittedEventRef.current = {
202
+ type: 'disconnected',
203
+ state: connectionState
204
+ };
205
+
206
+ // Emit disconnected when LEAVING Connected state (to Connecting or Disconnected)
207
+ // This catches the transition: Connected -> Connecting -> Disconnected
208
+ _embedEvent.default.event.emit(_embedEvent.AgentEvent.AGENT_DISCONNECTED, {
209
+ timestamp: new Date().toISOString(),
210
+ metadata: {
211
+ callDuration
212
+ }
213
+ }).catch(error => {
214
+ console.error('Error emitting disconnected event:', error);
215
+ });
216
+ } else {
217
+ // Update previous state for other transitions
218
+ prevConnectionStateRef.current = connectionState;
219
+ }
220
+ }, [connectionState, callDuration]); // Include callDuration to get fresh value
221
+
222
+ // Emit popup_message_visible when the popup is actually shown (isAutoOpen && !isOpen)
153
223
  (0, _react.useEffect)(() => {
224
+ const popupVisible = isAutoOpen && !isOpen;
225
+ if (!popupVisible) return;
154
226
  const emitPopupEvent = async () => {
155
- await _embedEvent.default.event.emit(_embedEvent.AgentEvent.POPUP_MESSAGE_VISIBLE, {
156
- value: isAutoOpen,
227
+ await _embedEvent.default.Event(_embedEvent.EventKeys.ANALYTICS_DATA, {
228
+ event_name: 'popup_message_visible',
157
229
  metadata: {
158
- trigger: isAutoOpen ? 'auto_inactivity' : 'manual_dismiss'
230
+ value: true,
231
+ trigger: 'auto_inactivity'
159
232
  }
160
233
  });
161
234
  };
162
235
  emitPopupEvent().catch(error => {
163
236
  console.error('Error emitting popup visibility event:', error);
164
237
  });
165
- }, [isAutoOpen]);
238
+ }, [isAutoOpen, isOpen]);
239
+
240
+ // Emit gen_tool_triggered analytics when livekit data is first received
241
+ const prevLivekitDataRef = (0, _react.useRef)(false);
242
+ (0, _react.useEffect)(() => {
243
+ const isLivekitData = livekitData && Object.keys(livekitData).length > 0;
244
+ if (isLivekitData && !prevLivekitDataRef.current) {
245
+ prevLivekitDataRef.current = true;
246
+ _embedEvent.default.Event(_embedEvent.EventKeys.ANALYTICS_DATA, {
247
+ event_name: 'gen_tool_triggered',
248
+ metadata: {
249
+ source: 'livekit_data'
250
+ }
251
+ }).catch(error => {
252
+ console.error('Error sending gen_tool_triggered analytics:', error);
253
+ });
254
+ }
255
+ if (!isLivekitData) {
256
+ prevLivekitDataRef.current = false;
257
+ }
258
+ }, [livekitData]);
166
259
 
167
260
  // ==================== HANDLERS ====================
168
- const handleButtonPress = () => {
169
- setIsOpen(!isOpen);
261
+ const handleButtonPress = (0, _react.useCallback)(async () => {
262
+ const eventName = isOpen ? 'agent_tap_to_close' : 'agent_tap_to_open';
263
+ try {
264
+ await _embedEvent.default.Event(_embedEvent.EventKeys.ANALYTICS_DATA, {
265
+ event_name: eventName,
266
+ metadata: {
267
+ button_pressed: 'button_pressed'
268
+ }
269
+ });
270
+ } catch (error) {
271
+ console.error('Error sending button_pressed analytics:', error);
272
+ }
273
+ setIsOpen(prev => !prev);
170
274
  setIsAutoOpen(false);
171
- };
172
- const handleConnected = () => {
173
- // Hook for handling successful connection
174
- };
275
+ }, [isOpen, setIsAutoOpen]);
276
+ const handleConnected = (0, _react.useCallback)(() => {
277
+ // Reserved for connection success side effects (e.g. analytics)
278
+ }, []);
175
279
 
176
280
  // ==================== COMPUTED VALUES ====================
177
281
  const lottieSource = (0, _react.useMemo)(() => ({
178
- uri: configData?.icon_animation || _EmbedButtonHelpers.ICON_URLS.AMPLIFY_ANIMATION
179
- }), [configData?.icon_animation]);
282
+ uri: configData?.agentAvatar?.avatarUrl || _EmbedButtonHelpers.ICON_URLS.AMPLIFY_ANIMATION
283
+ }), [configData?.agentAvatar?.avatarUrl]);
284
+ const micIconSource = (0, _react.useMemo)(() => ({
285
+ uri: isMicMuted ? _EmbedButtonHelpers.ICON_URLS.MIC_OFF : _EmbedButtonHelpers.ICON_URLS.MIC_ON
286
+ }), [isMicMuted]);
180
287
  const statusText = (0, _react.useMemo)(() => {
181
288
  if (isLoading) return 'Connecting...';
182
289
  if (tokenDetails?.token) return (0, _EmbedButtonHelpers.formatDuration)(callDuration);
183
- return configData?.agent_type || 'Onboarding Agent';
184
- }, [isLoading, tokenDetails?.token, callDuration, configData?.agent_type]);
185
- const gradientColors = configData?.gradient || _EmbedButtonHelpers.DEFAULT_GRADIENT_COLORS;
186
- const agentName = configData?.agent_name || 'Your AI Agent';
187
- const popupText = configData?.popup_description || 'Any doubts? Ask agent now';
188
- const connectButtonText = configData?.connect_button_title || 'Start Call';
290
+ return configData?.agentTextContent?.agentType ?? 'Onboarding Agent';
291
+ }, [isLoading, tokenDetails?.token, callDuration, configData?.agentTextContent?.agentType]);
292
+ const gradientColors = configData?.colorPalette?.grad1 != null && configData?.colorPalette?.grad2 != null ? [configData.colorPalette.grad1, configData.colorPalette.grad2] : configData?.colorPalette?.grad1 != null && configData?.colorPalette?.grad2 != null ? [configData.colorPalette.grad1, configData.colorPalette.grad2] : _EmbedButtonHelpers.DEFAULT_GRADIENT_COLORS;
293
+ const agentName = configData?.agentTextContent?.agentName ?? 'Your AI Agent';
294
+ const popupText = configData?.collapsedView?.tooltipMessage ?? 'Any doubts? Ask agent now';
295
+ const connectButtonText = configData?.agentTextContent?.buttonText ?? 'Start Call';
296
+ const isLivekitData = livekitData && Object.keys(livekitData).length > 0;
297
+ const gradientStyle = (0, _react.useMemo)(() => [styles.linearGradient, isLivekitData ? styles.linearGradientColumn : isOpen ? styles.expandedLinearGradient : styles.collapsedLinearGradient], [isOpen, isLivekitData, styles]);
298
+ const isConnected = !!tokenDetails?.token;
189
299
 
190
300
  // ==================== EARLY RETURNS ====================
191
301
  if (!configData) return null;
192
302
 
193
303
  // ==================== RENDER ====================
194
304
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
195
- style: styles.container,
305
+ style: [styles.container, isLivekitData && {
306
+ bottom: _EmbedButtonHelpers.FOOTER_SAFE_INSET
307
+ }],
196
308
  children: [isAutoOpen && !isOpen && /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmbedButtonAnimations.Animated.View, {
197
309
  style: [popupAnimatedStyles, styles.popupContainer],
310
+ accessibilityLabel: popupText,
311
+ accessibilityLiveRegion: "polite",
198
312
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
199
313
  style: styles.popupText,
200
314
  children: popupText
@@ -203,7 +317,7 @@ function EmbedButton() {
203
317
  gesture: panGesture,
204
318
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmbedButtonAnimations.Animated.View, {
205
319
  pointerEvents: "auto",
206
- style: [styles.button, buttonAnimatedStyles, styles.buttonContent],
320
+ style: [styles.button, buttonAnimatedStyles, isLivekitData ? styles.expandedButtonWhite : styles.buttonContent],
207
321
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeLinearGradient.default, {
208
322
  colors: gradientColors,
209
323
  start: {
@@ -214,7 +328,7 @@ function EmbedButton() {
214
328
  x: 1,
215
329
  y: 0
216
330
  },
217
- style: [styles.linearGradient, isOpen ? styles.expandedLinearGradient : styles.collapsedLinearGradient],
331
+ style: gradientStyle,
218
332
  angle: 0,
219
333
  angleCenter: {
220
334
  x: 0.5,
@@ -226,67 +340,202 @@ function EmbedButton() {
226
340
  onDisconnected: handleEndCall,
227
341
  roomRef: roomRef,
228
342
  onConnected: handleConnected
229
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
230
- onPress: handleButtonPress,
231
- style: styles.pressable,
232
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_lottieReactNative.default, {
233
- ref: lottieRef,
234
- source: lottieSource,
235
- autoPlay: true,
236
- loop: true,
237
- style: styles.iconImage,
238
- enableMergePathsAndroidForKitKatAndAbove: true,
239
- enableSafeModeAndroid: true
240
- })
241
- }), isOpen && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
242
- style: styles.expandedContentContainer,
343
+ }), isLivekitData ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
344
+ style: styles.expandedCallViewWrapper,
243
345
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
244
- style: styles.leftContentSection,
245
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
246
- style: [styles.agentNameText, styles.leftAlignedText],
247
- children: agentName
248
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
249
- style: [styles.leftAlignedText, styles.statusText],
250
- children: statusText
251
- })]
252
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
253
- style: styles.middleContentSection,
254
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmbedAudioWave.WaveformVisualizer, {
255
- roomRef: roomRef
256
- })
257
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
258
- style: styles.rightContentSection,
259
- children: [!tokenDetails?.token && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
260
- style: styles.buttonContainer,
261
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
262
- onPress: handleStartCall,
263
- style: styles.startCallButton,
264
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
265
- style: styles.startCallText,
266
- children: connectButtonText
267
- })
346
+ style: styles.callContentArea,
347
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
348
+ onPress: () => clearDataReceived(),
349
+ style: styles.closeButton,
350
+ accessibilityLabel: "Close",
351
+ accessibilityRole: "button",
352
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
353
+ source: {
354
+ uri: _EmbedButtonHelpers.ICON_URLS.CLOSE_ICON
355
+ },
356
+ style: styles.popupCloseIcon
268
357
  })
269
- }), tokenDetails?.token && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
270
- style: styles.buttonContainer,
271
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
272
- style: styles.muteButton,
273
- onPress: handleMicToggle,
274
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
275
- source: {
276
- uri: isMicMuted ? _EmbedButtonHelpers.ICON_URLS.MIC_OFF : _EmbedButtonHelpers.ICON_URLS.MIC_ON
358
+ }), livekitData.type === 'calculation' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
359
+ style: styles.callContentTextContainer,
360
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.ScrollView, {
361
+ ref: calculationScrollRef,
362
+ style: styles.callContentScrollView,
363
+ contentContainerStyle: styles.callContentScrollViewContent,
364
+ showsVerticalScrollIndicator: true,
365
+ bounces: false,
366
+ nestedScrollEnabled: true,
367
+ onScroll: e => {
368
+ const {
369
+ contentOffset,
370
+ contentSize,
371
+ layoutMeasurement
372
+ } = e.nativeEvent;
373
+ const isAtBottom = contentOffset.y + layoutMeasurement.height >= contentSize.height - SCROLL_END_THRESHOLD;
374
+ userScrolledUpRef.current = !isAtBottom;
375
+ },
376
+ onContentSizeChange: () => {
377
+ if (!userScrolledUpRef.current) {
378
+ calculationScrollRef.current?.scrollToEnd({
379
+ animated: true
380
+ });
381
+ }
382
+ },
383
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typewriter.default, {
384
+ lines: Array.isArray(livekitData.list) ? livekitData.list : [],
385
+ typingSpeed: 50,
386
+ textStyle: styles.callContentText,
387
+ showCursor: false,
388
+ onViewClose: flag => {
389
+ if (flag) {
390
+ clearDataReceived();
391
+ }
277
392
  },
278
- style: styles.buttonImage
393
+ viewCloseDelay: livekitData.delay || 15000
279
394
  })
280
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
281
- onPress: handleEndCall,
282
- style: styles.endCallButton,
283
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
284
- source: {
285
- uri: _EmbedButtonHelpers.ICON_URLS.END_CALL
286
- },
287
- style: styles.buttonImage
395
+ })
396
+ })]
397
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
398
+ style: styles.expandedContentContainer,
399
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
400
+ onPress: handleButtonPress,
401
+ style: styles.pressable,
402
+ children: configData?.agentAvatar?.avatarType === 'image' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
403
+ source: {
404
+ uri: configData?.agentAvatar?.avatarUrl
405
+ },
406
+ style: styles.iconImage
407
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_lottieReactNative.default, {
408
+ ref: lottieRef,
409
+ source: lottieSource,
410
+ autoPlay: true,
411
+ loop: true,
412
+ style: styles.iconImage,
413
+ enableMergePathsAndroidForKitKatAndAbove: true,
414
+ enableSafeModeAndroid: true
415
+ })
416
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
417
+ style: styles.leftContentSection,
418
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
419
+ style: [styles.agentNameText, styles.leftAlignedText],
420
+ numberOfLines: 1,
421
+ ellipsizeMode: "tail",
422
+ children: agentName
423
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
424
+ style: [styles.leftAlignedText, styles.statusText],
425
+ numberOfLines: 1,
426
+ ellipsizeMode: "tail",
427
+ children: statusText
428
+ })]
429
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
430
+ style: styles.middleContentSection,
431
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmbedAudioWave.WaveformVisualizer, {
432
+ roomRef: roomRef
433
+ })
434
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
435
+ style: [styles.rightContentSection, styles.rightContentSectionPadded],
436
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
437
+ style: styles.buttonContainer,
438
+ children: !isConnected ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
439
+ onPress: handleStartCall,
440
+ style: styles.startCallButton,
441
+ accessibilityLabel: `Start call - ${connectButtonText}`,
442
+ accessibilityRole: "button",
443
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
444
+ style: styles.startCallText,
445
+ children: connectButtonText
446
+ })
447
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
448
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
449
+ style: styles.muteButton,
450
+ onPress: handleMicToggle,
451
+ accessibilityLabel: isMicMuted ? 'Unmute microphone' : 'Mute microphone',
452
+ accessibilityRole: "button",
453
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
454
+ source: micIconSource,
455
+ style: styles.buttonImage
456
+ })
457
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
458
+ onPress: handleEndCall,
459
+ style: styles.endCallButton,
460
+ accessibilityLabel: "End call",
461
+ accessibilityRole: "button",
462
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
463
+ source: {
464
+ uri: _EmbedButtonHelpers.ICON_URLS.END_CALL
465
+ },
466
+ style: styles.buttonImage
467
+ })
468
+ })]
288
469
  })
470
+ })
471
+ })]
472
+ })]
473
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
474
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
475
+ onPress: handleButtonPress,
476
+ style: styles.pressable,
477
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_lottieReactNative.default, {
478
+ ref: lottieRef,
479
+ source: lottieSource,
480
+ autoPlay: true,
481
+ loop: true,
482
+ style: styles.iconImage,
483
+ enableMergePathsAndroidForKitKatAndAbove: true,
484
+ enableSafeModeAndroid: true
485
+ })
486
+ }), isOpen && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_EmbedButtonAnimations.Animated.View, {
487
+ style: [styles.expandedContentContainer, expandedContentAnimatedStyles],
488
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
489
+ style: styles.leftContentSection,
490
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
491
+ style: [styles.agentNameText, styles.leftAlignedText],
492
+ children: agentName
493
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
494
+ style: [styles.leftAlignedText, styles.statusText],
495
+ children: statusText
289
496
  })]
497
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
498
+ style: styles.middleContentSection,
499
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmbedAudioWave.WaveformVisualizer, {
500
+ roomRef: roomRef
501
+ })
502
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
503
+ style: styles.rightContentSection,
504
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
505
+ style: styles.buttonContainer,
506
+ children: !isConnected ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
507
+ onPress: handleStartCall,
508
+ style: styles.startCallButton,
509
+ accessibilityLabel: `Start call - ${connectButtonText}`,
510
+ accessibilityRole: "button",
511
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
512
+ style: styles.startCallText,
513
+ children: connectButtonText
514
+ })
515
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
516
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
517
+ style: styles.muteButton,
518
+ onPress: handleMicToggle,
519
+ accessibilityLabel: isMicMuted ? 'Unmute microphone' : 'Mute microphone',
520
+ accessibilityRole: "button",
521
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
522
+ source: micIconSource,
523
+ style: styles.buttonImage
524
+ })
525
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
526
+ onPress: handleEndCall,
527
+ style: styles.endCallButton,
528
+ accessibilityLabel: "End call",
529
+ accessibilityRole: "button",
530
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
531
+ source: {
532
+ uri: _EmbedButtonHelpers.ICON_URLS.END_CALL
533
+ },
534
+ style: styles.buttonImage
535
+ })
536
+ })]
537
+ })
538
+ })
290
539
  })]
291
540
  })]
292
541
  })]