@robylon/react-native-sdk 2.0.21-staging.2 → 2.0.21-staging.3

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 (69) hide show
  1. package/lib/commonjs/Chatbotsdk.js +2 -2
  2. package/lib/commonjs/Chatbotsdk.js.map +1 -1
  3. package/lib/commonjs/FloatingButton/launchers/ImageLauncher.js +2 -0
  4. package/lib/commonjs/FloatingButton/launchers/ImageLauncher.js.map +1 -0
  5. package/lib/commonjs/FloatingButton/launchers/TextLauncher.js +2 -0
  6. package/lib/commonjs/FloatingButton/launchers/TextLauncher.js.map +1 -0
  7. package/lib/commonjs/FloatingButton/launchers/TextualImageLauncher.js +2 -0
  8. package/lib/commonjs/FloatingButton/launchers/TextualImageLauncher.js.map +1 -0
  9. package/lib/commonjs/FloatingButton.js +1 -1
  10. package/lib/commonjs/FloatingButton.js.map +1 -1
  11. package/lib/commonjs/constants/fontStyles.js +2 -0
  12. package/lib/commonjs/constants/fontStyles.js.map +1 -0
  13. package/lib/commonjs/openChatbot.js.map +1 -1
  14. package/lib/commonjs/utils/animations.js +2 -0
  15. package/lib/commonjs/utils/animations.js.map +1 -0
  16. package/lib/commonjs/utils/colorUtils.js +2 -0
  17. package/lib/commonjs/utils/colorUtils.js.map +1 -0
  18. package/lib/commonjs/versions/version.staging.js +1 -1
  19. package/lib/module/Chatbotsdk.js +2 -2
  20. package/lib/module/Chatbotsdk.js.map +1 -1
  21. package/lib/module/FloatingButton/launchers/ImageLauncher.js +2 -0
  22. package/lib/module/FloatingButton/launchers/ImageLauncher.js.map +1 -0
  23. package/lib/module/FloatingButton/launchers/TextLauncher.js +2 -0
  24. package/lib/module/FloatingButton/launchers/TextLauncher.js.map +1 -0
  25. package/lib/module/FloatingButton/launchers/TextualImageLauncher.js +2 -0
  26. package/lib/module/FloatingButton/launchers/TextualImageLauncher.js.map +1 -0
  27. package/lib/module/FloatingButton.js +1 -1
  28. package/lib/module/FloatingButton.js.map +1 -1
  29. package/lib/module/constants/fontStyles.js +2 -0
  30. package/lib/module/constants/fontStyles.js.map +1 -0
  31. package/lib/module/openChatbot.js +2 -1
  32. package/lib/module/utils/animations.js +2 -0
  33. package/lib/module/utils/animations.js.map +1 -0
  34. package/lib/module/utils/colorUtils.js +2 -0
  35. package/lib/module/utils/colorUtils.js.map +1 -0
  36. package/lib/module/versions/version.staging.js +1 -1
  37. package/lib/typescript/Chatbotsdk.d.ts.map +1 -1
  38. package/lib/typescript/FloatingButton/launchers/ImageLauncher.d.ts +10 -0
  39. package/lib/typescript/FloatingButton/launchers/ImageLauncher.d.ts.map +1 -0
  40. package/lib/typescript/FloatingButton/launchers/TextLauncher.d.ts +10 -0
  41. package/lib/typescript/FloatingButton/launchers/TextLauncher.d.ts.map +1 -0
  42. package/lib/typescript/FloatingButton/launchers/TextualImageLauncher.d.ts +10 -0
  43. package/lib/typescript/FloatingButton/launchers/TextualImageLauncher.d.ts.map +1 -0
  44. package/lib/typescript/FloatingButton.d.ts +2 -0
  45. package/lib/typescript/FloatingButton.d.ts.map +1 -1
  46. package/lib/typescript/constants/fontStyles.d.ts +3 -0
  47. package/lib/typescript/constants/fontStyles.d.ts.map +1 -0
  48. package/lib/typescript/utils/animations.d.ts +38 -0
  49. package/lib/typescript/utils/animations.d.ts.map +1 -0
  50. package/lib/typescript/utils/colorUtils.d.ts +2 -0
  51. package/lib/typescript/utils/colorUtils.d.ts.map +1 -0
  52. package/lib/typescript/versions/version.staging.d.ts +1 -1
  53. package/package.json +1 -1
  54. package/src/Chatbotsdk.tsx +42 -38
  55. package/src/FloatingButton/launchers/ImageLauncher.tsx +75 -0
  56. package/src/FloatingButton/launchers/TextLauncher.tsx +84 -0
  57. package/src/FloatingButton/launchers/TextualImageLauncher.tsx +133 -0
  58. package/src/FloatingButton.tsx +71 -62
  59. package/src/constants/fontStyles.ts +3 -0
  60. package/src/utils/animations.ts +120 -0
  61. package/src/utils/colorUtils.ts +35 -0
  62. package/src/versions/version.staging.ts +1 -1
  63. package/lib/commonjs/ChatbotWebview.js +0 -2
  64. package/lib/commonjs/ChatbotWebview.js.map +0 -1
  65. package/lib/module/ChatbotWebview.js +0 -2
  66. package/lib/module/ChatbotWebview.js.map +0 -1
  67. package/lib/typescript/ChatbotWebview.d.ts +0 -8
  68. package/lib/typescript/ChatbotWebview.d.ts.map +0 -1
  69. package/src/ChatbotWebview.tsx +0 -44
@@ -39,6 +39,7 @@ import {
39
39
  getStorageScript,
40
40
  createStorageMessage,
41
41
  } from "./utils/webViewStorage";
42
+ import { animateWebViewOpen, animateWebViewClose } from "./utils/animations";
42
43
 
43
44
  export interface ChatbotProps {
44
45
  api_key: string;
@@ -132,7 +133,6 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
132
133
  );
133
134
  const [loading, setLoading] = useState(true);
134
135
  const webViewRef = useRef<WebView>(null);
135
- const fadeAnim = useRef(new Animated.Value(0)).current;
136
136
  const isFirstLoadRef = useRef(true);
137
137
  const [toastVisible, setToastVisible] = useState(false);
138
138
  const [toastMessage, setToastMessage] = useState("");
@@ -140,9 +140,15 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
140
140
  const [isStorageReady, setIsStorageReady] = useState(false);
141
141
  const pendingStorageOps = useRef<Array<() => void>>([]);
142
142
  const memoryCache = useRef<Record<string, string>>({});
143
-
144
143
  const [systemInfo, setSystemInfo] = useState({ os: "", browser: "" });
145
144
 
145
+ // Initialize animated values
146
+ const animatedValues = useRef({
147
+ scale: new Animated.Value(1),
148
+ translateY: new Animated.Value(0),
149
+ opacity: new Animated.Value(1),
150
+ }).current;
151
+
146
152
  // Create chatbotConfig object for events
147
153
  const chatbotConfigForEvents = useMemo(
148
154
  () => ({
@@ -462,11 +468,7 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
462
468
  const openWebView = useCallback(() => {
463
469
  setIsWebViewVisible(true);
464
470
  if (enableAnimation) {
465
- Animated.timing(fadeAnim, {
466
- toValue: 1,
467
- duration: 250,
468
- useNativeDriver: true,
469
- }).start(() => {
471
+ animateWebViewOpen(animatedValues, () => {
470
472
  onOpen?.();
471
473
  emitEvent(ChatbotEventType.CHATBOT_OPENED);
472
474
  if (!isFirstLoadRef.current) {
@@ -474,7 +476,6 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
474
476
  }
475
477
  });
476
478
  } else {
477
- fadeAnim.setValue(1);
478
479
  requestAnimationFrame(() => {
479
480
  onOpen?.();
480
481
  emitEvent(ChatbotEventType.CHATBOT_OPENED);
@@ -483,7 +484,7 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
483
484
  }
484
485
  });
485
486
  }
486
- }, [enableAnimation, fadeAnim, onOpen, emitEvent]);
487
+ }, [enableAnimation, animatedValues, onOpen, emitEvent]);
487
488
 
488
489
  // Handle closing the chatbot
489
490
  const closeWebView = useCallback(() => {
@@ -496,23 +497,18 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
496
497
  );
497
498
  }
498
499
 
499
- const complete = () => {
500
+ if (enableAnimation) {
501
+ animateWebViewClose(animatedValues, () => {
502
+ setIsWebViewVisible(false);
503
+ onClose?.();
504
+ emitEvent(ChatbotEventType.CHATBOT_CLOSED);
505
+ });
506
+ } else {
500
507
  setIsWebViewVisible(false);
501
508
  onClose?.();
502
509
  emitEvent(ChatbotEventType.CHATBOT_CLOSED);
503
- };
504
-
505
- if (enableAnimation) {
506
- Animated.timing(fadeAnim, {
507
- toValue: 0,
508
- duration: 200,
509
- useNativeDriver: true,
510
- }).start(complete);
511
- } else {
512
- fadeAnim.setValue(0);
513
- requestAnimationFrame(complete);
514
510
  }
515
- }, [enableAnimation, fadeAnim, onClose, emitEvent]);
511
+ }, [enableAnimation, animatedValues, onClose, emitEvent]);
516
512
 
517
513
  // Emit button loaded event when component mounts
518
514
  useEffect(() => {
@@ -564,29 +560,28 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
564
560
  const bottomSpacing =
565
561
  chatbotConfig?.interface_properties?.bottom_spacing ?? 20;
566
562
 
567
- const mainContainerStyle = useMemo(() => {
568
- return {
569
- ...styles.mainContainer,
570
- [position.toLowerCase()]: `${sideSpacing ?? 20}px`,
571
- alignItems:
572
- position === "Right" ? "flex-end" : ("flex-start" as FlexAlignType),
573
- // Explicitly clear mobile-specific styles
574
- top: undefined,
575
- [position === "Right" ? "left" : "right"]: undefined,
576
- backgroundColor: "red",
577
- };
578
- }, [position, sideSpacing, styles.mainContainer]);
579
-
580
- console.log("MAINCONTAINERSTYLE", mainContainerStyle, position, sideSpacing);
563
+ // const mainContainerStyle = useMemo(() => {
564
+ // return {
565
+ // ...styles.mainContainer,
566
+ // [position.toLowerCase()]: `${sideSpacing ?? 20}px`,
567
+ // alignItems:
568
+ // position === "Right" ? "flex-end" : ("flex-start" as FlexAlignType),
569
+ // // Explicitly clear mobile-specific styles
570
+ // top: undefined,
571
+ // [position === "Right" ? "left" : "right"]: undefined,
572
+ // backgroundColor: "green",
573
+ // };
574
+ // }, [position, sideSpacing, styles.mainContainer]);
581
575
 
582
576
  return (
583
577
  <ErrorBoundary componentName="ChatbotSDK">
584
- <View style={mainContainerStyle}>
578
+ <View style={styles?.mainContainer}>
585
579
  {!loading && (
586
580
  <>
587
581
  <ErrorBoundary componentName="FloatingButton">
588
582
  {show_floating_button && api_key && chatbotConfig && (
589
583
  <FloatingButton
584
+ chatbotConfig={chatbotConfig}
590
585
  isWebViewVisible={isWebViewVisible}
591
586
  onPress={() => {
592
587
  emitEvent(ChatbotEventType.CHATBOT_BUTTON_CLICKED);
@@ -605,7 +600,16 @@ const Chatbot: React.FC<InternalChatbotProps> = ({
605
600
  pointerEvents={isWebViewVisible ? "auto" : "none"}
606
601
  >
607
602
  <Animated.View
608
- style={[styles.fullScreenContainer, { opacity: 1 }]}
603
+ style={[
604
+ styles.fullScreenContainer,
605
+ {
606
+ opacity: animatedValues.opacity,
607
+ transform: [
608
+ { scale: animatedValues.scale },
609
+ { translateY: animatedValues.translateY },
610
+ ],
611
+ },
612
+ ]}
609
613
  >
610
614
  <ErrorBoundary componentName="ChatbotWebView">
611
615
  <WebView
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import { Image, StyleSheet, TouchableOpacity, View } from "react-native";
3
+ import { ChatbotConfig } from "../../Chatbotsdk";
4
+ import { errorTracker } from "../../services/ErrorTrackingService";
5
+ import { ErrorTypes } from "../../constants/errorConstants";
6
+
7
+ interface ImageLauncherProps {
8
+ chatbotConfig: ChatbotConfig;
9
+ onPress: () => void;
10
+ isWebViewVisible: boolean;
11
+ }
12
+
13
+ const ImageLauncher: React.FC<ImageLauncherProps> = ({
14
+ chatbotConfig,
15
+ onPress,
16
+ isWebViewVisible,
17
+ }) => {
18
+ const handleImageError = () => {
19
+ errorTracker.trackError(
20
+ new Error("Failed to load launcher image"),
21
+ "ImageLauncher",
22
+ {
23
+ type: ErrorTypes.RUNTIME_ERROR,
24
+ context: { imageUrl: chatbotConfig?.images?.launcher_image_url?.url },
25
+ }
26
+ );
27
+ };
28
+
29
+ return (
30
+ <TouchableOpacity
31
+ style={[
32
+ styles.button,
33
+ {
34
+ backgroundColor: isWebViewVisible
35
+ ? "transparent"
36
+ : chatbotConfig.brand_colour,
37
+ },
38
+ isWebViewVisible && styles.disabledButton,
39
+ ]}
40
+ onPress={isWebViewVisible ? undefined : onPress}
41
+ activeOpacity={isWebViewVisible ? 1 : 0.7}
42
+ >
43
+ <Image
44
+ source={{ uri: chatbotConfig?.images?.launcher_image_url?.url }}
45
+ style={styles.buttonImage}
46
+ onError={handleImageError}
47
+ />
48
+ </TouchableOpacity>
49
+ );
50
+ };
51
+
52
+ const styles = StyleSheet.create({
53
+ button: {
54
+ borderRadius: 24,
55
+ width: 48,
56
+ height: 48,
57
+ justifyContent: "center",
58
+ alignItems: "center",
59
+ elevation: 5,
60
+ shadowColor: "#000",
61
+ shadowOffset: { width: 0, height: 2 },
62
+ shadowOpacity: 0.25,
63
+ shadowRadius: 3.84,
64
+ },
65
+ buttonImage: {
66
+ width: 48,
67
+ height: 48,
68
+ borderRadius: 24,
69
+ },
70
+ disabledButton: {
71
+ backgroundColor: "rgba(0, 0, 0, 0)",
72
+ },
73
+ });
74
+
75
+ export default ImageLauncher;
@@ -0,0 +1,84 @@
1
+ import React from "react";
2
+ import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
3
+ import { ChatbotConfig } from "../../Chatbotsdk";
4
+ import { getBestFontColor } from "../../utils/colorUtils";
5
+
6
+ interface TextLauncherProps {
7
+ chatbotConfig: ChatbotConfig;
8
+ onPress: () => void;
9
+ isWebViewVisible: boolean;
10
+ }
11
+
12
+ const TextLauncher: React.FC<TextLauncherProps> = ({
13
+ chatbotConfig,
14
+ onPress,
15
+ isWebViewVisible,
16
+ }) => {
17
+ console.log("TEXT_LAUNCHER", {
18
+ brand_colour: chatbotConfig?.brand_colour,
19
+ isWebViewVisible,
20
+ });
21
+
22
+ const containerStyle = {
23
+ ...styles.container,
24
+ backgroundColor: isWebViewVisible
25
+ ? "transparent"
26
+ : chatbotConfig?.brand_colour || "#007AFF",
27
+ };
28
+
29
+ const buttonTextStyle = {
30
+ ...styles.buttonText,
31
+ color: getBestFontColor(chatbotConfig?.brand_colour || "#ffffff"),
32
+ };
33
+
34
+ return (
35
+ <View style={[containerStyle, isWebViewVisible && styles.disabledButton]}>
36
+ <TouchableOpacity
37
+ style={[styles.button]}
38
+ onPress={isWebViewVisible ? undefined : onPress}
39
+ activeOpacity={isWebViewVisible ? 1 : 0.7}
40
+ >
41
+ <View style={styles.textContainer}>
42
+ <Text style={buttonTextStyle} numberOfLines={1}>
43
+ {chatbotConfig?.launcher_properties?.text || "Chat"}
44
+ </Text>
45
+ </View>
46
+ </TouchableOpacity>
47
+ </View>
48
+ );
49
+ };
50
+
51
+ const styles = StyleSheet.create({
52
+ container: {
53
+ maxWidth: 160,
54
+ minWidth: 120,
55
+ height: 40,
56
+ borderRadius: 9999,
57
+ shadowColor: "#000",
58
+ shadowOffset: { width: 0, height: 0 },
59
+ shadowOpacity: 0.24,
60
+ shadowRadius: 16,
61
+ elevation: 5,
62
+ },
63
+ button: {
64
+ flex: 1,
65
+ paddingHorizontal: 20,
66
+ paddingVertical: 9,
67
+ justifyContent: "center",
68
+ alignItems: "center",
69
+ },
70
+ textContainer: {
71
+ flex: 1,
72
+ minWidth: 0,
73
+ },
74
+ buttonText: {
75
+ fontSize: 14,
76
+ fontWeight: "600",
77
+ textAlign: "center",
78
+ },
79
+ disabledButton: {
80
+ backgroundColor: "rgba(0, 0, 0, 0)",
81
+ },
82
+ });
83
+
84
+ export default TextLauncher;
@@ -0,0 +1,133 @@
1
+ import React from "react";
2
+ import { StyleSheet, Text, TouchableOpacity, View, Image } from "react-native";
3
+ import { ChatbotConfig } from "../../Chatbotsdk";
4
+ import { errorTracker } from "../../services/ErrorTrackingService";
5
+ import { ErrorTypes } from "../../constants/errorConstants";
6
+ import { getBestFontColor } from "../../utils/colorUtils";
7
+ import { FONT_FAMILY, FONT_LINE_HEIGHT } from "../../constants/fontStyles";
8
+
9
+ interface TextualImageLauncherProps {
10
+ chatbotConfig: ChatbotConfig;
11
+ onPress: () => void;
12
+ isWebViewVisible: boolean;
13
+ }
14
+
15
+ const TextualImageLauncher: React.FC<TextualImageLauncherProps> = ({
16
+ chatbotConfig,
17
+ onPress,
18
+ isWebViewVisible,
19
+ }) => {
20
+ console.log("TEXTUALIMAGE_LAUNCHER_DEBUG", {
21
+ brand_colour: chatbotConfig?.brand_colour,
22
+ text: chatbotConfig?.launcher_properties?.text,
23
+ isWebViewVisible,
24
+ });
25
+
26
+ const containerStyle = {
27
+ ...styles.container,
28
+ backgroundColor: isWebViewVisible
29
+ ? "transparent"
30
+ : chatbotConfig?.brand_colour || "#007AFF",
31
+ };
32
+
33
+ const handleImageError = () => {
34
+ errorTracker.trackError(
35
+ new Error("Failed to load launcher image"),
36
+ "TextualImageLauncher",
37
+ {
38
+ type: ErrorTypes.RUNTIME_ERROR,
39
+ context: { imageUrl: chatbotConfig?.images?.launcher_image_url?.url },
40
+ }
41
+ );
42
+ };
43
+
44
+ const buttonTextStyle = {
45
+ ...styles.buttonText,
46
+ color: getBestFontColor(chatbotConfig?.brand_colour || "#ffffff"),
47
+ };
48
+
49
+ console.log("TEXTUALIMAGE_LAUNCHER_TEXT_STYLE", {
50
+ brand_colour: chatbotConfig?.brand_colour,
51
+ text_color: buttonTextStyle.color,
52
+ text: chatbotConfig?.launcher_properties?.text,
53
+ });
54
+
55
+ return (
56
+ <View style={[containerStyle, isWebViewVisible && styles.disabledButton]}>
57
+ <TouchableOpacity
58
+ style={styles.button}
59
+ onPress={isWebViewVisible ? undefined : onPress}
60
+ activeOpacity={isWebViewVisible ? 1 : 0.7}
61
+ >
62
+ <View style={styles.contentContainer}>
63
+ <View style={styles.textContainer}>
64
+ <Text
65
+ style={buttonTextStyle}
66
+ numberOfLines={1}
67
+ ellipsizeMode="tail"
68
+ >
69
+ {chatbotConfig?.launcher_properties?.text || "Chat"}
70
+ </Text>
71
+ </View>
72
+ <View style={styles.imageContainer}>
73
+ <Image
74
+ source={{ uri: chatbotConfig?.images?.launcher_image_url?.url }}
75
+ style={styles.buttonImage}
76
+ onError={handleImageError}
77
+ />
78
+ </View>
79
+ </View>
80
+ </TouchableOpacity>
81
+ </View>
82
+ );
83
+ };
84
+
85
+ const styles = StyleSheet.create({
86
+ container: {
87
+ minWidth: 140,
88
+ maxWidth: 208,
89
+ height: 40,
90
+ borderRadius: 9999,
91
+ shadowColor: "#000",
92
+ shadowOffset: { width: 0, height: 0 },
93
+ shadowOpacity: 0.24,
94
+ shadowRadius: 16,
95
+ elevation: 5,
96
+ },
97
+ button: {
98
+ flex: 1,
99
+ height: "100%",
100
+ },
101
+ contentContainer: {
102
+ flex: 1,
103
+ flexDirection: "row",
104
+ alignItems: "center",
105
+ paddingLeft: 20,
106
+ height: "100%",
107
+ },
108
+ textContainer: {
109
+ flexShrink: 1,
110
+ flexGrow: 0,
111
+ marginRight: 8,
112
+ },
113
+ buttonText: {
114
+ fontSize: 14,
115
+ fontWeight: "600",
116
+ },
117
+ imageContainer: {
118
+ width: 40,
119
+ height: 40,
120
+ borderRadius: 9999,
121
+ overflow: "hidden",
122
+ },
123
+ buttonImage: {
124
+ width: "100%",
125
+ height: "100%",
126
+ resizeMode: "cover",
127
+ },
128
+ disabledButton: {
129
+ backgroundColor: "rgba(0, 0, 0, 0)",
130
+ },
131
+ });
132
+
133
+ export default TextualImageLauncher;
@@ -1,88 +1,97 @@
1
- import React from "react";
2
- import { TouchableOpacity, StyleSheet, Text, Image, View } from "react-native";
3
- import { errorTracker } from "./services/ErrorTrackingService";
4
- import { ErrorTypes } from "./constants/errorConstants";
1
+ import React, { useMemo, useEffect, useRef } from "react";
2
+ import { View, StyleSheet, FlexAlignType, Animated } from "react-native";
3
+ import { ChatbotConfig, LauncherType } from "./Chatbotsdk";
4
+ import ImageLauncher from "./FloatingButton/launchers/ImageLauncher";
5
+ import TextLauncher from "./FloatingButton/launchers/TextLauncher";
6
+ import TextualImageLauncher from "./FloatingButton/launchers/TextualImageLauncher";
7
+ import { animateButtonScale } from "./utils/animations";
5
8
 
6
9
  interface FloatingButtonProps {
7
10
  onPress: () => void;
8
- brandColor?: string; // For dynamic branding
9
- imageUrl?: string; // For brand logo or icon
11
+ brandColor?: string;
12
+ imageUrl?: string;
10
13
  isWebViewVisible: boolean;
14
+ chatbotConfig: ChatbotConfig;
11
15
  }
12
16
 
13
17
  const FloatingButton: React.FC<FloatingButtonProps> = ({
14
18
  onPress,
15
- brandColor = "#007AFF", // Default color
16
- imageUrl,
17
19
  isWebViewVisible,
20
+ chatbotConfig,
18
21
  }) => {
19
- const handleImageError = () => {
20
- errorTracker.trackError(
21
- new Error("Failed to load button image"),
22
- "FloatingButton",
23
- {
24
- type: ErrorTypes.RUNTIME_ERROR,
25
- context: { imageUrl },
26
- }
27
- );
22
+ const buttonScale = useRef(new Animated.Value(1)).current;
23
+
24
+ useEffect(() => {
25
+ animateButtonScale(buttonScale, isWebViewVisible);
26
+ }, [isWebViewVisible, buttonScale]);
27
+
28
+ console.log("FLOATING_BUTTON_CONFIG", {
29
+ config: chatbotConfig,
30
+ brand_colour: chatbotConfig?.brand_colour,
31
+ launcher_type: chatbotConfig?.launcher_type,
32
+ });
33
+
34
+ const position = chatbotConfig?.interface_properties?.position || "Right";
35
+ const sideSpacing = chatbotConfig?.interface_properties?.side_spacing ?? 20;
36
+ const bottomSpacing =
37
+ chatbotConfig?.interface_properties?.bottom_spacing ?? 20;
38
+
39
+ const buttonContainerStyle = useMemo(() => {
40
+ return {
41
+ ...styles.container,
42
+ [position.toLowerCase()]: sideSpacing ?? 20,
43
+ alignItems:
44
+ position === "Right" ? "flex-end" : ("flex-start" as FlexAlignType),
45
+ bottom: bottomSpacing ?? 20,
46
+ transform: [{ scale: buttonScale }],
47
+ };
48
+ }, [position, sideSpacing, bottomSpacing, buttonScale]);
49
+
50
+ const renderLauncher = () => {
51
+ switch (chatbotConfig?.launcher_type) {
52
+ case LauncherType.TEXT:
53
+ return (
54
+ <TextLauncher
55
+ chatbotConfig={chatbotConfig}
56
+ onPress={onPress}
57
+ isWebViewVisible={isWebViewVisible}
58
+ />
59
+ );
60
+ case LauncherType.TEXTUAL_IMAGE:
61
+ return (
62
+ <TextualImageLauncher
63
+ chatbotConfig={chatbotConfig}
64
+ onPress={onPress}
65
+ isWebViewVisible={isWebViewVisible}
66
+ />
67
+ );
68
+ case LauncherType.IMAGE:
69
+ default:
70
+ return (
71
+ <ImageLauncher
72
+ chatbotConfig={chatbotConfig}
73
+ onPress={onPress}
74
+ isWebViewVisible={isWebViewVisible}
75
+ />
76
+ );
77
+ }
28
78
  };
29
79
 
30
80
  return (
31
- <View
32
- style={styles.container}
81
+ <Animated.View
82
+ style={buttonContainerStyle}
33
83
  pointerEvents={isWebViewVisible ? "none" : "auto"}
34
84
  >
35
- <TouchableOpacity
36
- style={[
37
- styles.button,
38
- { backgroundColor: isWebViewVisible ? "transparent" : brandColor }, // Set transparent to visually disable
39
- isWebViewVisible && styles.disabledButton, // Add a disabled style
40
- ]}
41
- onPress={isWebViewVisible ? undefined : onPress} // Disable interaction
42
- activeOpacity={isWebViewVisible ? 1 : 0.7} // Prevent touch feedback when disabled
43
- >
44
- {imageUrl && !isWebViewVisible ? (
45
- <Image source={{ uri: imageUrl }} style={styles.buttonImage} />
46
- ) : (
47
- <Text style={styles.buttonText}>Chat</Text>
48
- )}
49
- </TouchableOpacity>
50
- </View>
85
+ {renderLauncher()}
86
+ </Animated.View>
51
87
  );
52
88
  };
53
89
 
54
90
  const styles = StyleSheet.create({
55
91
  container: {
56
92
  position: "absolute",
57
- bottom: 20,
58
- right: 20,
59
93
  zIndex: 998,
60
94
  },
61
- button: {
62
- borderRadius: 24,
63
- width: 48,
64
- height: 48,
65
- justifyContent: "center",
66
- alignItems: "center",
67
- elevation: 5,
68
- shadowColor: "#000",
69
- shadowOffset: { width: 0, height: 2 },
70
- shadowOpacity: 0.25,
71
- shadowRadius: 3.84,
72
- },
73
- buttonText: {
74
- color: "white",
75
- fontSize: 16,
76
- fontWeight: "bold",
77
- },
78
- buttonImage: {
79
- width: 48,
80
- height: 48,
81
- borderRadius: 24,
82
- },
83
- disabledButton: {
84
- backgroundColor: "rgba(0, 0, 0, 0)", // Fully transparent to disable visuals
85
- },
86
95
  });
87
96
 
88
97
  export default FloatingButton;
@@ -0,0 +1,3 @@
1
+ export const FONT_FAMILY =
2
+ "system-ui, Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'";
3
+ export const FONT_LINE_HEIGHT = 21;