@worktual/react-native-ai-bot 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ export interface WorktualAIBotProps {
3
+ /** Your unique webchat ID provided by Worktual */
4
+ webchatId: string;
5
+ /** Called when the bot sends a close/end event (navigate back, dismiss modal, etc.) */
6
+ onClose: () => void;
7
+ /** Optional: custom base URL (defaults to Worktual production) */
8
+ baseUrl?: string;
9
+ /** Optional: loading screen title (default: "AI Assistant") */
10
+ loadingTitle?: string;
11
+ /** Optional: loading screen subtitle (default: "Loading your chat...") */
12
+ loadingSubtitle?: string;
13
+ /** Optional: primary colour for progress bar & spinner (default: "#575CFF") */
14
+ primaryColor?: string;
15
+ /** Optional: loading screen background colour (default: "#f8f9fb") */
16
+ loadingBackground?: string;
17
+ /** Optional: maximum time (ms) to wait before force-hiding loader (default: 6000) */
18
+ maxLoadTime?: number;
19
+ /** Optional: called when bot content is fully loaded */
20
+ onReady?: () => void;
21
+ /** Optional: called on every postMessage from the WebView */
22
+ onMessage?: (data: Record<string, unknown>) => void;
23
+ }
24
+ declare const WorktualAIBot: React.FC<WorktualAIBotProps>;
25
+ export default WorktualAIBot;
26
+ //# sourceMappingURL=WorktualAIBot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorktualAIBot.d.ts","sourceRoot":"","sources":["../src/WorktualAIBot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAiBxE,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,uFAAuF;IACvF,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrD;AA2CD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4J/C,CAAC;AA8CF,eAAe,aAAa,CAAC"}
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const react_1 = __importStar(require("react"));
37
+ const react_native_1 = require("react-native");
38
+ const react_native_webview_1 = require("react-native-webview");
39
+ const react_native_safe_area_context_1 = require("react-native-safe-area-context");
40
+ /* ────────────────────────────────────────────────────────
41
+ * Constants
42
+ * ──────────────────────────────────────────────────────── */
43
+ const DEFAULT_BASE_URL = "https://ccaas-storage.worktual.co.uk/chat/ailivebot.html";
44
+ const buildUrl = (baseUrl, webchatId) => {
45
+ const sep = baseUrl.includes("?") ? "&" : "?";
46
+ return `${baseUrl}${sep}webchatid=${webchatId}&isHeader=1`;
47
+ };
48
+ /** Injected JS – polls for chat content then posts webchat_ready */
49
+ const buildInjectedJS = (maxMs) => `
50
+ (function() {
51
+ var t = setInterval(function() {
52
+ var m = document.querySelectorAll(
53
+ '.message, .chat-message, .msg-content, [class*="message"]'
54
+ );
55
+ var i = document.querySelector('input[placeholder], textarea[placeholder]');
56
+ if (m.length > 0 || i) {
57
+ clearInterval(t);
58
+ window.ReactNativeWebView.postMessage(
59
+ JSON.stringify({ type: "webchat_ready" })
60
+ );
61
+ }
62
+ }, 200);
63
+ setTimeout(function() {
64
+ clearInterval(t);
65
+ window.ReactNativeWebView.postMessage(
66
+ JSON.stringify({ type: "webchat_ready" })
67
+ );
68
+ }, ${maxMs});
69
+ })();
70
+ true;
71
+ `;
72
+ /* ────────────────────────────────────────────────────────
73
+ * Component
74
+ * ──────────────────────────────────────────────────────── */
75
+ const WorktualAIBot = ({ webchatId, onClose, baseUrl = DEFAULT_BASE_URL, loadingTitle = "AI Assistant", loadingSubtitle = "Loading your chat...", primaryColor = "#575CFF", loadingBackground = "#f8f9fb", maxLoadTime = 6000, onReady, onMessage: onMessageProp, }) => {
76
+ const insets = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
77
+ const [showLoader, setShowLoader] = (0, react_1.useState)(true);
78
+ // Animations
79
+ const progressAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
80
+ const fadeAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
81
+ const dotAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
82
+ const url = buildUrl(baseUrl, webchatId);
83
+ const injectedJS = buildInjectedJS(maxLoadTime);
84
+ /* ── Animations ── */
85
+ (0, react_1.useEffect)(() => {
86
+ // Progress bar: fast to 70%, then slow to 90%
87
+ react_native_1.Animated.sequence([
88
+ react_native_1.Animated.timing(progressAnim, {
89
+ toValue: 0.7,
90
+ duration: 800,
91
+ useNativeDriver: false,
92
+ }),
93
+ react_native_1.Animated.timing(progressAnim, {
94
+ toValue: 0.9,
95
+ duration: 2500,
96
+ useNativeDriver: false,
97
+ }),
98
+ ]).start();
99
+ // Pulsing dots
100
+ react_native_1.Animated.loop(react_native_1.Animated.sequence([
101
+ react_native_1.Animated.timing(dotAnim, { toValue: 1, duration: 500, useNativeDriver: true }),
102
+ react_native_1.Animated.timing(dotAnim, { toValue: 0.3, duration: 500, useNativeDriver: true }),
103
+ ])).start();
104
+ }, []);
105
+ /* ── Hide loader ── */
106
+ const hideLoader = (0, react_1.useCallback)(() => {
107
+ if (!showLoader)
108
+ return;
109
+ // Complete progress bar
110
+ react_native_1.Animated.timing(progressAnim, {
111
+ toValue: 1,
112
+ duration: 150,
113
+ useNativeDriver: false,
114
+ }).start();
115
+ // Fade out
116
+ setTimeout(() => {
117
+ react_native_1.Animated.timing(fadeAnim, {
118
+ toValue: 0,
119
+ duration: 200,
120
+ useNativeDriver: true,
121
+ }).start(() => setShowLoader(false));
122
+ }, 150);
123
+ }, [showLoader]);
124
+ /* ── WebView message handler ── */
125
+ const handleMessage = (0, react_1.useCallback)((event) => {
126
+ try {
127
+ const data = JSON.parse(event.nativeEvent.data);
128
+ // Forward to client's onMessage if provided
129
+ onMessageProp === null || onMessageProp === void 0 ? void 0 : onMessageProp(data);
130
+ if ((data === null || data === void 0 ? void 0 : data.type) === "webchat_ready") {
131
+ hideLoader();
132
+ onReady === null || onReady === void 0 ? void 0 : onReady();
133
+ }
134
+ if ((data === null || data === void 0 ? void 0 : data.type) === "webchat_end") {
135
+ onClose();
136
+ }
137
+ }
138
+ catch (_) {
139
+ // Ignore non-JSON messages
140
+ }
141
+ }, [hideLoader, onClose, onReady, onMessageProp]);
142
+ /* ── Render ── */
143
+ const progressWidth = progressAnim.interpolate({
144
+ inputRange: [0, 1],
145
+ outputRange: ["0%", "100%"],
146
+ });
147
+ return (<react_native_1.View style={[styles.container, { paddingTop: insets.top }]}>
148
+ <react_native_1.StatusBar barStyle="dark-content" backgroundColor="#fff"/>
149
+
150
+ {/* WebView loads immediately behind the loader */}
151
+ <react_native_webview_1.WebView source={{ uri: url }} style={styles.webview} javaScriptEnabled domStorageEnabled allowsInlineMediaPlayback mediaPlaybackRequiresUserAction={false} onMessage={handleMessage} injectedJavaScript={injectedJS}
152
+ // Prevent white flash on Android
153
+ {...(react_native_1.Platform.OS === "android" && {
154
+ overScrollMode: "never",
155
+ setBuiltInZoomControls: false,
156
+ })}/>
157
+
158
+ {/* Loading overlay */}
159
+ {showLoader && (<react_native_1.Animated.View style={[
160
+ styles.loaderOverlay,
161
+ { opacity: fadeAnim, backgroundColor: loadingBackground },
162
+ ]}>
163
+ {/* Spinner */}
164
+ <react_native_1.ActivityIndicator size="large" color={primaryColor} style={styles.spinner}/>
165
+
166
+ {/* Title */}
167
+ <react_native_1.Text style={styles.loaderTitle}>{loadingTitle}</react_native_1.Text>
168
+
169
+ {/* Subtitle with pulsing opacity */}
170
+ <react_native_1.Animated.Text style={[styles.loaderSubtitle, { opacity: dotAnim }]}>
171
+ {loadingSubtitle}
172
+ </react_native_1.Animated.Text>
173
+
174
+ {/* Progress bar */}
175
+ <react_native_1.View style={styles.progressTrack}>
176
+ <react_native_1.Animated.View style={[
177
+ styles.progressBar,
178
+ { width: progressWidth, backgroundColor: primaryColor },
179
+ ]}/>
180
+ </react_native_1.View>
181
+ </react_native_1.Animated.View>)}
182
+ </react_native_1.View>);
183
+ };
184
+ /* ────────────────────────────────────────────────────────
185
+ * Styles
186
+ * ──────────────────────────────────────────────────────── */
187
+ const styles = react_native_1.StyleSheet.create({
188
+ container: {
189
+ flex: 1,
190
+ backgroundColor: "#fff",
191
+ },
192
+ webview: {
193
+ flex: 1,
194
+ },
195
+ loaderOverlay: Object.assign(Object.assign({}, react_native_1.StyleSheet.absoluteFillObject), { justifyContent: "center", alignItems: "center" }),
196
+ spinner: {
197
+ marginBottom: 20,
198
+ },
199
+ loaderTitle: {
200
+ fontSize: 18,
201
+ fontWeight: "600",
202
+ color: "#1a1a2e",
203
+ marginBottom: 6,
204
+ },
205
+ loaderSubtitle: {
206
+ fontSize: 14,
207
+ color: "#8e8ea0",
208
+ marginBottom: 28,
209
+ },
210
+ progressTrack: {
211
+ width: 200,
212
+ height: 4,
213
+ backgroundColor: "#e4e4e7",
214
+ borderRadius: 2,
215
+ overflow: "hidden",
216
+ },
217
+ progressBar: {
218
+ height: "100%",
219
+ borderRadius: 2,
220
+ },
221
+ });
222
+ exports.default = WorktualAIBot;
223
+ //# sourceMappingURL=WorktualAIBot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorktualAIBot.js","sourceRoot":"","sources":["../src/WorktualAIBot.tsx"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
1
  export { default as WorktualAIBot } from "./WorktualAIBot";
2
2
  export type { WorktualAIBotProps } from "./WorktualAIBot";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WorktualAIBot = void 0;
7
+ var WorktualAIBot_1 = require("./WorktualAIBot");
8
+ Object.defineProperty(exports, "WorktualAIBot", { enumerable: true, get: function () { return __importDefault(WorktualAIBot_1).default; } });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,iDAA2D;AAAlD,+HAAA,OAAO,OAAiB"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@worktual/react-native-ai-bot",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Worktual AI Bot - Embeddable AI chatbot for React Native apps",
5
- "main": "src/index.ts",
6
- "types": "src/index.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "prepublishOnly": "npm run build"
@@ -29,7 +29,7 @@
29
29
  "typescript": "^5.9.3"
30
30
  },
31
31
  "files": [
32
- "src/",
32
+ "dist/",
33
33
  "README.md"
34
34
  ]
35
35
  }
@@ -1,293 +0,0 @@
1
- import React, { useState, useEffect, useRef, useCallback } from "react";
2
- import {
3
- View,
4
- StyleSheet,
5
- Animated,
6
- Text,
7
- ActivityIndicator,
8
- StatusBar,
9
- Platform,
10
- } from "react-native";
11
- import { WebView, WebViewMessageEvent } from "react-native-webview";
12
- import { useSafeAreaInsets } from "react-native-safe-area-context";
13
-
14
- /* ────────────────────────────────────────────────────────
15
- * Public types
16
- * ──────────────────────────────────────────────────────── */
17
-
18
- export interface WorktualAIBotProps {
19
- /** Your unique webchat ID provided by Worktual */
20
- webchatId: string;
21
-
22
- /** Called when the bot sends a close/end event (navigate back, dismiss modal, etc.) */
23
- onClose: () => void;
24
-
25
- /** Optional: custom base URL (defaults to Worktual production) */
26
- baseUrl?: string;
27
-
28
- /** Optional: loading screen title (default: "AI Assistant") */
29
- loadingTitle?: string;
30
-
31
- /** Optional: loading screen subtitle (default: "Loading your chat...") */
32
- loadingSubtitle?: string;
33
-
34
- /** Optional: primary colour for progress bar & spinner (default: "#575CFF") */
35
- primaryColor?: string;
36
-
37
- /** Optional: loading screen background colour (default: "#f8f9fb") */
38
- loadingBackground?: string;
39
-
40
- /** Optional: maximum time (ms) to wait before force-hiding loader (default: 6000) */
41
- maxLoadTime?: number;
42
-
43
- /** Optional: called when bot content is fully loaded */
44
- onReady?: () => void;
45
-
46
- /** Optional: called on every postMessage from the WebView */
47
- onMessage?: (data: Record<string, unknown>) => void;
48
- }
49
-
50
- /* ────────────────────────────────────────────────────────
51
- * Constants
52
- * ──────────────────────────────────────────────────────── */
53
-
54
- const DEFAULT_BASE_URL =
55
- "https://ccaas-storage.worktual.co.uk/chat/ailivebot.html";
56
-
57
- const buildUrl = (baseUrl: string, webchatId: string): string => {
58
- const sep = baseUrl.includes("?") ? "&" : "?";
59
- return `${baseUrl}${sep}webchatid=${webchatId}&isHeader=1`;
60
- };
61
-
62
- /** Injected JS – polls for chat content then posts webchat_ready */
63
- const buildInjectedJS = (maxMs: number): string => `
64
- (function() {
65
- var t = setInterval(function() {
66
- var m = document.querySelectorAll(
67
- '.message, .chat-message, .msg-content, [class*="message"]'
68
- );
69
- var i = document.querySelector('input[placeholder], textarea[placeholder]');
70
- if (m.length > 0 || i) {
71
- clearInterval(t);
72
- window.ReactNativeWebView.postMessage(
73
- JSON.stringify({ type: "webchat_ready" })
74
- );
75
- }
76
- }, 200);
77
- setTimeout(function() {
78
- clearInterval(t);
79
- window.ReactNativeWebView.postMessage(
80
- JSON.stringify({ type: "webchat_ready" })
81
- );
82
- }, ${maxMs});
83
- })();
84
- true;
85
- `;
86
-
87
- /* ────────────────────────────────────────────────────────
88
- * Component
89
- * ──────────────────────────────────────────────────────── */
90
-
91
- const WorktualAIBot: React.FC<WorktualAIBotProps> = ({
92
- webchatId,
93
- onClose,
94
- baseUrl = DEFAULT_BASE_URL,
95
- loadingTitle = "AI Assistant",
96
- loadingSubtitle = "Loading your chat...",
97
- primaryColor = "#575CFF",
98
- loadingBackground = "#f8f9fb",
99
- maxLoadTime = 6000,
100
- onReady,
101
- onMessage: onMessageProp,
102
- }) => {
103
- const insets = useSafeAreaInsets();
104
- const [showLoader, setShowLoader] = useState(true);
105
-
106
- // Animations
107
- const progressAnim = useRef(new Animated.Value(0)).current;
108
- const fadeAnim = useRef(new Animated.Value(1)).current;
109
- const dotAnim = useRef(new Animated.Value(0)).current;
110
-
111
- const url = buildUrl(baseUrl, webchatId);
112
- const injectedJS = buildInjectedJS(maxLoadTime);
113
-
114
- /* ── Animations ── */
115
- useEffect(() => {
116
- // Progress bar: fast to 70%, then slow to 90%
117
- Animated.sequence([
118
- Animated.timing(progressAnim, {
119
- toValue: 0.7,
120
- duration: 800,
121
- useNativeDriver: false,
122
- }),
123
- Animated.timing(progressAnim, {
124
- toValue: 0.9,
125
- duration: 2500,
126
- useNativeDriver: false,
127
- }),
128
- ]).start();
129
-
130
- // Pulsing dots
131
- Animated.loop(
132
- Animated.sequence([
133
- Animated.timing(dotAnim, { toValue: 1, duration: 500, useNativeDriver: true }),
134
- Animated.timing(dotAnim, { toValue: 0.3, duration: 500, useNativeDriver: true }),
135
- ])
136
- ).start();
137
- }, []);
138
-
139
- /* ── Hide loader ── */
140
- const hideLoader = useCallback(() => {
141
- if (!showLoader) return;
142
- // Complete progress bar
143
- Animated.timing(progressAnim, {
144
- toValue: 1,
145
- duration: 150,
146
- useNativeDriver: false,
147
- }).start();
148
-
149
- // Fade out
150
- setTimeout(() => {
151
- Animated.timing(fadeAnim, {
152
- toValue: 0,
153
- duration: 200,
154
- useNativeDriver: true,
155
- }).start(() => setShowLoader(false));
156
- }, 150);
157
- }, [showLoader]);
158
-
159
- /* ── WebView message handler ── */
160
- const handleMessage = useCallback(
161
- (event: WebViewMessageEvent) => {
162
- try {
163
- const data = JSON.parse(event.nativeEvent.data);
164
-
165
- // Forward to client's onMessage if provided
166
- onMessageProp?.(data);
167
-
168
- if (data?.type === "webchat_ready") {
169
- hideLoader();
170
- onReady?.();
171
- }
172
- if (data?.type === "webchat_end") {
173
- onClose();
174
- }
175
- } catch (_) {
176
- // Ignore non-JSON messages
177
- }
178
- },
179
- [hideLoader, onClose, onReady, onMessageProp]
180
- );
181
-
182
- /* ── Render ── */
183
- const progressWidth = progressAnim.interpolate({
184
- inputRange: [0, 1],
185
- outputRange: ["0%", "100%"],
186
- });
187
-
188
- return (
189
- <View style={[styles.container, { paddingTop: insets.top }]}>
190
- <StatusBar barStyle="dark-content" backgroundColor="#fff" />
191
-
192
- {/* WebView loads immediately behind the loader */}
193
- <WebView
194
- source={{ uri: url }}
195
- style={styles.webview}
196
- javaScriptEnabled
197
- domStorageEnabled
198
- allowsInlineMediaPlayback
199
- mediaPlaybackRequiresUserAction={false}
200
- onMessage={handleMessage}
201
- injectedJavaScript={injectedJS}
202
- // Prevent white flash on Android
203
- {...(Platform.OS === "android" && {
204
- overScrollMode: "never" as const,
205
- setBuiltInZoomControls: false,
206
- })}
207
- />
208
-
209
- {/* Loading overlay */}
210
- {showLoader && (
211
- <Animated.View
212
- style={[
213
- styles.loaderOverlay,
214
- { opacity: fadeAnim, backgroundColor: loadingBackground },
215
- ]}
216
- >
217
- {/* Spinner */}
218
- <ActivityIndicator
219
- size="large"
220
- color={primaryColor}
221
- style={styles.spinner}
222
- />
223
-
224
- {/* Title */}
225
- <Text style={styles.loaderTitle}>{loadingTitle}</Text>
226
-
227
- {/* Subtitle with pulsing opacity */}
228
- <Animated.Text
229
- style={[styles.loaderSubtitle, { opacity: dotAnim }]}
230
- >
231
- {loadingSubtitle}
232
- </Animated.Text>
233
-
234
- {/* Progress bar */}
235
- <View style={styles.progressTrack}>
236
- <Animated.View
237
- style={[
238
- styles.progressBar,
239
- { width: progressWidth, backgroundColor: primaryColor },
240
- ]}
241
- />
242
- </View>
243
- </Animated.View>
244
- )}
245
- </View>
246
- );
247
- };
248
-
249
- /* ────────────────────────────────────────────────────────
250
- * Styles
251
- * ──────────────────────────────────────────────────────── */
252
-
253
- const styles = StyleSheet.create({
254
- container: {
255
- flex: 1,
256
- backgroundColor: "#fff",
257
- },
258
- webview: {
259
- flex: 1,
260
- },
261
- loaderOverlay: {
262
- ...StyleSheet.absoluteFillObject,
263
- justifyContent: "center",
264
- alignItems: "center",
265
- },
266
- spinner: {
267
- marginBottom: 20,
268
- },
269
- loaderTitle: {
270
- fontSize: 18,
271
- fontWeight: "600",
272
- color: "#1a1a2e",
273
- marginBottom: 6,
274
- },
275
- loaderSubtitle: {
276
- fontSize: 14,
277
- color: "#8e8ea0",
278
- marginBottom: 28,
279
- },
280
- progressTrack: {
281
- width: 200,
282
- height: 4,
283
- backgroundColor: "#e4e4e7",
284
- borderRadius: 2,
285
- overflow: "hidden",
286
- },
287
- progressBar: {
288
- height: "100%",
289
- borderRadius: 2,
290
- },
291
- });
292
-
293
- export default WorktualAIBot;