@sagepilot-ai/react-native-sdk 0.2.2 → 0.2.4

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.
@@ -1,34 +1,3 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- SagepilotChat: () => SagepilotChat,
24
- SagepilotChatError: () => SagepilotChatError,
25
- SagepilotChatProvider: () => SagepilotChatProvider,
26
- createAsyncStorageCacheStorage: () => createAsyncStorageCacheStorage,
27
- createKeychainTokenStorage: () => createKeychainTokenStorage,
28
- useSagepilotChat: () => useSagepilotChat
29
- });
30
- module.exports = __toCommonJS(index_exports);
31
-
32
1
  // src/core/errors/SagepilotChatError.ts
33
2
  var SagepilotChatError = class extends Error {
34
3
  constructor(code, message, options = {}) {
@@ -46,7 +15,7 @@ var SagepilotChatError = class extends Error {
46
15
 
47
16
  // src/core/config/constants.ts
48
17
  var SDK_NAME = "@sagepilot-ai/react-native-sdk";
49
- var SDK_VERSION = "0.2.0";
18
+ var SDK_VERSION = "0.2.4";
50
19
  var DEFAULT_HOST = "https://app.sagepilot.ai";
51
20
  var DEFAULT_WIDGET_HOST = "https://app.sagepilot.ai";
52
21
  var CUSTOMER_API_PREFIX = "/customer-api/v1";
@@ -495,6 +464,18 @@ function normalizeIdentity(identity) {
495
464
  user_hash: identity.userHash ?? identity.user_hash
496
465
  };
497
466
  }
467
+ function readStringField(input, key) {
468
+ const value = input[key];
469
+ return typeof value === "string" && value.trim() ? value : void 0;
470
+ }
471
+ function normalizeOptionalString(value) {
472
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
473
+ }
474
+ function readRecordField(input, key) {
475
+ const value = input[key];
476
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
477
+ return value;
478
+ }
498
479
  function toPublicSessionState(session) {
499
480
  return {
500
481
  session_id: session.session_id,
@@ -528,6 +509,7 @@ var SagepilotReactNativeChat = class {
528
509
  this.unreadPollTimer = null;
529
510
  this.stateCallbacks = /* @__PURE__ */ new Set();
530
511
  this.identifyCallbacks = /* @__PURE__ */ new Set();
512
+ this.conversationCreatedCallbacks = /* @__PURE__ */ new Set();
531
513
  this.unreadCallbacks = /* @__PURE__ */ new Set();
532
514
  this.readyCallbacks = /* @__PURE__ */ new Set();
533
515
  this.presentCallbacks = /* @__PURE__ */ new Set();
@@ -732,9 +714,17 @@ var SagepilotReactNativeChat = class {
732
714
  this.hostedChatView = { screen: "messages" };
733
715
  return this.showHostedChat();
734
716
  }
735
- presentMessageComposer(message) {
717
+ presentMessageComposer(message, options) {
736
718
  this.requireConfigured();
737
- this.hostedChatView = { screen: "composer", message };
719
+ const chatId = normalizeOptionalString(options?.chatId);
720
+ this.hostedChatView = {
721
+ screen: "composer",
722
+ message,
723
+ mode: options?.mode ?? "auto",
724
+ chatId,
725
+ metadata: options?.metadata,
726
+ onConversationCreated: options?.onConversationCreated
727
+ };
738
728
  return this.showHostedChat();
739
729
  }
740
730
  dismiss() {
@@ -783,6 +773,13 @@ var SagepilotReactNativeChat = class {
783
773
  this.dismissCallbacks.delete(callback);
784
774
  };
785
775
  }
776
+ onConversationCreated(callback) {
777
+ if (typeof callback !== "function") return () => void 0;
778
+ this.conversationCreatedCallbacks.add(callback);
779
+ return () => {
780
+ this.conversationCreatedCallbacks.delete(callback);
781
+ };
782
+ }
786
783
  onError(callback) {
787
784
  if (typeof callback !== "function") return () => void 0;
788
785
  this.errorCallbacks.add(callback);
@@ -834,7 +831,12 @@ var SagepilotReactNativeChat = class {
834
831
  url.searchParams.set("jwt", this.legacyWidgetJwt);
835
832
  }
836
833
  if (this.hostedChatView.screen === "composer") {
837
- url.searchParams.set("new", "true");
834
+ if (this.hostedChatView.chatId) {
835
+ url.searchParams.set("chat_id", this.hostedChatView.chatId);
836
+ }
837
+ if (this.hostedChatView.mode === "new" && !this.hostedChatView.chatId) {
838
+ url.searchParams.set("new", "true");
839
+ }
838
840
  if (this.hostedChatView.message) {
839
841
  url.searchParams.set("topic", this.hostedChatView.message);
840
842
  }
@@ -860,13 +862,19 @@ var SagepilotReactNativeChat = class {
860
862
  "})();"
861
863
  ].join("\n");
862
864
  }
865
+ getActiveHostedChatId() {
866
+ if (this.hostedChatView.screen === "composer" && this.hostedChatView.chatId) {
867
+ return this.hostedChatView.chatId;
868
+ }
869
+ return this.session?.conversation_id ?? void 0;
870
+ }
863
871
  getHostedIdentityMessage() {
864
872
  if (!this.legacyWidgetJwt) return null;
865
873
  return {
866
874
  type: "identity_update",
867
875
  data: {
868
876
  jwt: this.legacyWidgetJwt,
869
- chat_id: this.session?.conversation_id ?? void 0
877
+ chat_id: this.getActiveHostedChatId()
870
878
  }
871
879
  };
872
880
  }
@@ -885,17 +893,62 @@ var SagepilotReactNativeChat = class {
885
893
  }
886
894
  return true;
887
895
  }
896
+ if (message.type === "sagepilot:conversation_created") {
897
+ this.handleConversationCreated(message);
898
+ return true;
899
+ }
888
900
  if (message.type === "sagepilot:error") {
889
901
  this.emitError(message);
890
902
  return true;
891
903
  }
892
904
  return true;
893
905
  }
906
+ handleConversationCreated(message) {
907
+ const chatId = readStringField(message, "chat_id") ?? readStringField(message, "conversation_id");
908
+ if (!chatId) return;
909
+ void this.persistConversationId(chatId).catch((error) => this.emitError(error));
910
+ const bridgeMetadata = readRecordField(message, "metadata");
911
+ const composerMetadata = this.hostedChatView.screen === "composer" ? this.hostedChatView.metadata : void 0;
912
+ const metadata = {
913
+ ...composerMetadata ?? {},
914
+ ...bridgeMetadata ?? {}
915
+ };
916
+ const workspaceId = readStringField(message, "workspace_id") ?? this.workspaceId;
917
+ const channelId = readStringField(message, "channel_id") ?? this.channelId;
918
+ const sessionId = readStringField(message, "session_id") ?? this.session?.session_id;
919
+ const customerId = readStringField(message, "customer_id");
920
+ const messageId = readStringField(message, "message_id");
921
+ const createdAt = readStringField(message, "created_at");
922
+ const event = {
923
+ chat_id: chatId,
924
+ ...workspaceId ? { workspace_id: workspaceId } : {},
925
+ ...channelId ? { channel_id: channelId } : {},
926
+ ...sessionId ? { session_id: sessionId } : {},
927
+ ...customerId ? { customer_id: customerId } : {},
928
+ ...messageId ? { message_id: messageId } : {},
929
+ ...createdAt ? { created_at: createdAt } : {},
930
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
931
+ };
932
+ if (this.hostedChatView.screen === "composer") {
933
+ this.hostedChatView.onConversationCreated?.(event);
934
+ }
935
+ this.conversationCreatedCallbacks.forEach((callback) => callback(event));
936
+ }
937
+ async persistConversationId(conversationId) {
938
+ if (!this.session || !this.sessionManager) return;
939
+ if (this.session.conversation_id === conversationId) return;
940
+ this.session = await this.sessionManager.setSession({
941
+ ...this.session,
942
+ conversation_id: conversationId
943
+ });
944
+ this.emitState();
945
+ }
894
946
  destroy() {
895
947
  this.stopUnreadPolling();
896
948
  this.resetRuntimeState();
897
949
  this.emitState();
898
950
  this.identifyCallbacks.clear();
951
+ this.conversationCreatedCallbacks.clear();
899
952
  this.unreadCallbacks.clear();
900
953
  this.readyCallbacks.clear();
901
954
  this.presentCallbacks.clear();
@@ -1058,13 +1111,18 @@ var SagepilotChat = {
1058
1111
  logout: () => internalSagepilotChat.logout(),
1059
1112
  getIdentityState: () => internalSagepilotChat.getIdentityState(),
1060
1113
  onIdentify: (callback) => internalSagepilotChat.onIdentify(callback),
1114
+ onConversationCreated: (callback) => {
1115
+ return internalSagepilotChat.onConversationCreated(callback);
1116
+ },
1061
1117
  getUnreadCount: () => internalSagepilotChat.getUnreadCount(),
1062
1118
  onUnreadChange: (callback) => internalSagepilotChat.onUnreadChange(callback),
1063
1119
  startUnreadPolling: (intervalMs) => internalSagepilotChat.startUnreadPolling(intervalMs),
1064
1120
  stopUnreadPolling: () => internalSagepilotChat.stopUnreadPolling(),
1065
1121
  present: () => internalSagepilotChat.present(),
1066
1122
  presentMessages: () => internalSagepilotChat.presentMessages(),
1067
- presentMessageComposer: (message) => internalSagepilotChat.presentMessageComposer(message),
1123
+ presentMessageComposer: (message, options) => {
1124
+ return internalSagepilotChat.presentMessageComposer(message, options);
1125
+ },
1068
1126
  dismiss: () => internalSagepilotChat.dismiss(),
1069
1127
  hide: () => internalSagepilotChat.hide(),
1070
1128
  toggle: () => internalSagepilotChat.toggle(),
@@ -1090,9 +1148,19 @@ function createAsyncStorageCacheStorage(asyncStorage) {
1090
1148
  }
1091
1149
 
1092
1150
  // src/ui/SagepilotChatProvider.ts
1093
- var import_react = require("react");
1094
- var import_react_native = require("react-native");
1095
- var import_react_native_webview = require("react-native-webview");
1151
+ import { createElement, useCallback, useEffect, useRef, useState } from "react";
1152
+ import {
1153
+ ActivityIndicator,
1154
+ KeyboardAvoidingView,
1155
+ Modal,
1156
+ Platform,
1157
+ Pressable,
1158
+ SafeAreaView,
1159
+ StyleSheet,
1160
+ Text,
1161
+ View
1162
+ } from "react-native";
1163
+ import { WebView } from "react-native-webview";
1096
1164
 
1097
1165
  // src/core/webview/mobileBridge.ts
1098
1166
  function isHostedBridgeMessage(value) {
@@ -1173,6 +1241,28 @@ var mobileWebViewBridgeScript = `
1173
1241
  } catch (error) {}
1174
1242
  }, true);
1175
1243
 
1244
+ document.addEventListener("focusin", function (event) {
1245
+ try {
1246
+ var target = event.target && event.target.closest
1247
+ ? event.target
1248
+ : event.target && event.target.parentElement;
1249
+ if (target && target.closest && target.closest("input, textarea, [contenteditable='true']")) {
1250
+ sendToReactNative({ type: "sagepilot:keyboard_focus" });
1251
+ }
1252
+ } catch (error) {}
1253
+ }, true);
1254
+
1255
+ document.addEventListener("focusout", function (event) {
1256
+ try {
1257
+ var target = event.target && event.target.closest
1258
+ ? event.target
1259
+ : event.target && event.target.parentElement;
1260
+ if (target && target.closest && target.closest("input, textarea, [contenteditable='true']")) {
1261
+ sendToReactNative({ type: "sagepilot:keyboard_blur" });
1262
+ }
1263
+ } catch (error) {}
1264
+ }, true);
1265
+
1176
1266
  ensureViewport();
1177
1267
  injectMobileStyles();
1178
1268
  sendToReactNative({ type: "sagepilot:ready" });
@@ -1180,6 +1270,10 @@ var mobileWebViewBridgeScript = `
1180
1270
  })();
1181
1271
  `;
1182
1272
 
1273
+ // src/specs/SagepilotInsetsViewNativeComponent.ts
1274
+ import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNativeComponent";
1275
+ var SagepilotInsetsViewNativeComponent_default = codegenNativeComponent("SagepilotInsetsView");
1276
+
1183
1277
  // src/ui/SagepilotChatProvider.ts
1184
1278
  function readPresentationState() {
1185
1279
  return {
@@ -1222,30 +1316,68 @@ function readUrlOrigin(url) {
1222
1316
  var hostedChatWebViewProps = {
1223
1317
  allowFileAccess: true,
1224
1318
  allowFileAccessFromFileURLs: true,
1319
+ ...Platform.OS === "ios" ? {
1320
+ automaticallyAdjustContentInsets: false,
1321
+ contentInsetAdjustmentBehavior: "never",
1322
+ hideKeyboardAccessoryView: true
1323
+ } : null,
1324
+ bounces: false,
1225
1325
  domStorageEnabled: true,
1226
1326
  javaScriptEnabled: true,
1327
+ overScrollMode: "never",
1328
+ // The hosted widget owns feed scrolling internally; outer WebView scrolling lets iOS focus-scroll the page over the keyboard.
1329
+ scrollEnabled: false,
1227
1330
  setSupportMultipleWindows: false,
1228
1331
  sharedCookiesEnabled: true,
1229
1332
  thirdPartyCookiesEnabled: true
1230
1333
  };
1334
+ var AndroidInsetsView = Platform.OS === "android" ? SagepilotInsetsViewNativeComponent_default : View;
1335
+ var emptyAndroidInsets = { top: 0, bottom: 0 };
1231
1336
  function SagepilotChatProvider({
1232
1337
  children,
1233
1338
  closeLabel = "Close",
1234
1339
  loadingLabel = "Loading chat"
1235
1340
  }) {
1236
- const [state, setState] = (0, import_react.useState)(readPresentationState);
1237
- const webFrameRef = (0, import_react.useRef)(null);
1238
- const nativeWebViewRef = (0, import_react.useRef)(null);
1239
- (0, import_react.useEffect)(() => {
1341
+ const [state, setState] = useState(readPresentationState);
1342
+ const [androidModalInsets, setAndroidModalInsets] = useState(emptyAndroidInsets);
1343
+ const webFrameRef = useRef(null);
1344
+ const nativeWebViewRef = useRef(null);
1345
+ useEffect(() => {
1240
1346
  return internalSagepilotChat.onStateChange(() => {
1241
1347
  setState(readPresentationState());
1242
1348
  });
1243
1349
  }, []);
1350
+ const handleAndroidInsetsChange = useCallback((event) => {
1351
+ const nextBottomInset = event.nativeEvent?.bottom;
1352
+ const nextTopInset = event.nativeEvent?.top;
1353
+ if (typeof nextBottomInset !== "number" || typeof nextTopInset !== "number" || !Number.isFinite(nextBottomInset) || !Number.isFinite(nextTopInset)) return;
1354
+ setAndroidModalInsets({
1355
+ top: Math.max(0, nextTopInset),
1356
+ bottom: Math.max(0, nextBottomInset)
1357
+ });
1358
+ }, []);
1244
1359
  const showCloseButton = state.presentation?.showCloseButton ?? false;
1245
1360
  const presentationStyle = state.presentation?.style ?? "sheet";
1246
1361
  const isFullScreenModal = presentationStyle === "fullScreen";
1247
1362
  const animationType = presentationStyle === "fullScreen" || presentationStyle === "push" ? "slide" : "fade";
1248
- const ModalContainer = import_react_native.Platform.OS === "ios" && isFullScreenModal ? import_react_native.SafeAreaView : import_react_native.View;
1363
+ const ModalContainer = Platform.OS === "ios" && isFullScreenModal ? SafeAreaView : View;
1364
+ const NativeModalContainer = Platform.OS === "android" ? AndroidInsetsView : ModalContainer;
1365
+ const ChatContentContainer = Platform.OS === "ios" ? KeyboardAvoidingView : View;
1366
+ const nativeModalContainerProps = Platform.OS === "android" ? { style: styles.container, onInsetsChange: handleAndroidInsetsChange } : { style: styles.container };
1367
+ const chatContentContainerProps = Platform.OS === "ios" ? {
1368
+ behavior: "padding",
1369
+ enabled: true,
1370
+ keyboardVerticalOffset: 0,
1371
+ style: styles.modalContent
1372
+ } : {
1373
+ style: [
1374
+ styles.modalContent,
1375
+ Platform.OS === "android" ? {
1376
+ paddingTop: androidModalInsets.top,
1377
+ paddingBottom: androidModalInsets.bottom
1378
+ } : null
1379
+ ].filter(Boolean)
1380
+ };
1249
1381
  const handleWebViewMessage = (event) => {
1250
1382
  internalSagepilotChat.handleHostedBridgeMessage(parseHostedBridgeMessage(event.nativeEvent?.data));
1251
1383
  };
@@ -1260,8 +1392,8 @@ function SagepilotChatProvider({
1260
1392
  if (!script || !nativeWebViewRef.current) return;
1261
1393
  nativeWebViewRef.current.injectJavaScript(script);
1262
1394
  };
1263
- (0, import_react.useEffect)(() => {
1264
- if (import_react_native.Platform.OS !== "web" || typeof window === "undefined") return;
1395
+ useEffect(() => {
1396
+ if (Platform.OS !== "web" || typeof window === "undefined") return;
1265
1397
  const trustedWidgetOrigin = readUrlOrigin(state.conversationUrl);
1266
1398
  if (!trustedWidgetOrigin) return;
1267
1399
  const handleWindowMessage = (event) => {
@@ -1271,41 +1403,41 @@ function SagepilotChatProvider({
1271
1403
  window.addEventListener("message", handleWindowMessage);
1272
1404
  return () => window.removeEventListener("message", handleWindowMessage);
1273
1405
  }, [state.conversationUrl]);
1274
- (0, import_react.useEffect)(() => {
1275
- if (import_react_native.Platform.OS !== "web" || !state.isPresented) return;
1406
+ useEffect(() => {
1407
+ if (Platform.OS !== "web" || !state.isPresented) return;
1276
1408
  postIdentityToWebFrame();
1277
1409
  }, [state.isPresented, state.conversationUrl, state.configured]);
1278
- (0, import_react.useEffect)(() => {
1279
- if (import_react_native.Platform.OS === "web" || !state.isPresented) return;
1410
+ useEffect(() => {
1411
+ if (Platform.OS === "web" || !state.isPresented) return;
1280
1412
  postIdentityToNativeWebView();
1281
1413
  }, [state.isPresented, state.conversationUrl, state.configured]);
1282
- if (import_react_native.Platform.OS === "web") {
1283
- return (0, import_react.createElement)(
1284
- import_react_native.View,
1414
+ if (Platform.OS === "web") {
1415
+ return createElement(
1416
+ View,
1285
1417
  { style: styles.root },
1286
1418
  children,
1287
- state.configured && !state.isPresented && state.shouldPreload && state.preloadUrl ? (0, import_react.createElement)("iframe", {
1419
+ state.configured && !state.isPresented && state.shouldPreload && state.preloadUrl ? createElement("iframe", {
1288
1420
  src: state.preloadUrl,
1289
1421
  style: styles.webPreloadFrame,
1290
1422
  title: "Sagepilot chat preload"
1291
1423
  }) : null,
1292
- state.configured && state.isPresented && state.conversationUrl ? (0, import_react.createElement)(
1293
- import_react_native.View,
1424
+ state.configured && state.isPresented && state.conversationUrl ? createElement(
1425
+ View,
1294
1426
  { style: styles.webOverlay },
1295
- (0, import_react.createElement)(
1296
- import_react_native.View,
1427
+ createElement(
1428
+ View,
1297
1429
  { style: styles.webPanel },
1298
- showCloseButton ? (0, import_react.createElement)(
1299
- import_react_native.Pressable,
1430
+ showCloseButton ? createElement(
1431
+ Pressable,
1300
1432
  {
1301
1433
  accessibilityRole: "button",
1302
1434
  accessibilityLabel: closeLabel,
1303
1435
  onPress: () => internalSagepilotChat.dismiss(),
1304
1436
  style: styles.webCloseButton
1305
1437
  },
1306
- (0, import_react.createElement)(import_react_native.Text, { style: styles.closeText }, closeLabel)
1438
+ createElement(Text, { style: styles.closeText }, closeLabel)
1307
1439
  ) : null,
1308
- (0, import_react.createElement)("iframe", {
1440
+ createElement("iframe", {
1309
1441
  ref: webFrameRef,
1310
1442
  src: state.conversationUrl,
1311
1443
  style: styles.webFrame,
@@ -1316,63 +1448,69 @@ function SagepilotChatProvider({
1316
1448
  ) : null
1317
1449
  );
1318
1450
  }
1319
- return (0, import_react.createElement)(
1320
- import_react_native.View,
1451
+ return createElement(
1452
+ View,
1321
1453
  { style: styles.root },
1322
1454
  children,
1323
- state.configured && !state.isPresented && state.shouldPreload && state.preloadUrl ? (0, import_react.createElement)(import_react_native_webview.WebView, {
1455
+ state.configured && !state.isPresented && state.shouldPreload && state.preloadUrl ? createElement(WebView, {
1324
1456
  ...hostedChatWebViewProps,
1325
1457
  source: { uri: state.preloadUrl },
1326
1458
  style: styles.preloadWebview,
1327
1459
  injectedJavaScriptBeforeContentLoaded: getInjectedWebViewScript(),
1328
1460
  onMessage: handleWebViewMessage
1329
1461
  }) : null,
1330
- (0, import_react.createElement)(
1331
- import_react_native.Modal,
1462
+ createElement(
1463
+ Modal,
1332
1464
  {
1333
1465
  visible: state.configured && state.isPresented,
1334
1466
  animationType,
1335
1467
  presentationStyle: isFullScreenModal ? "fullScreen" : "pageSheet",
1468
+ statusBarTranslucent: Platform.OS === "android",
1469
+ navigationBarTranslucent: Platform.OS === "android",
1336
1470
  onRequestClose: () => internalSagepilotChat.dismiss()
1337
1471
  },
1338
- (0, import_react.createElement)(
1339
- ModalContainer,
1340
- { style: styles.container },
1341
- showCloseButton ? (0, import_react.createElement)(
1342
- import_react_native.View,
1343
- { style: styles.header },
1344
- (0, import_react.createElement)(
1345
- import_react_native.Pressable,
1346
- {
1347
- accessibilityRole: "button",
1348
- accessibilityLabel: closeLabel,
1349
- onPress: () => internalSagepilotChat.dismiss(),
1350
- style: styles.closeButton
1351
- },
1352
- (0, import_react.createElement)(import_react_native.Text, { style: styles.closeText }, closeLabel)
1353
- )
1354
- ) : null,
1355
- state.conversationUrl ? (0, import_react.createElement)(import_react_native_webview.WebView, {
1356
- ...hostedChatWebViewProps,
1357
- ref: nativeWebViewRef,
1358
- source: { uri: state.conversationUrl },
1359
- style: styles.webview,
1360
- startInLoadingState: true,
1361
- injectedJavaScriptBeforeContentLoaded: getInjectedWebViewScript(),
1362
- onMessage: handleWebViewMessage,
1363
- onLoadEnd: postIdentityToNativeWebView,
1364
- renderLoading: () => (0, import_react.createElement)(
1365
- import_react_native.View,
1366
- { style: styles.loading },
1367
- (0, import_react.createElement)(import_react_native.ActivityIndicator, null),
1368
- (0, import_react.createElement)(import_react_native.Text, { style: styles.loadingText }, loadingLabel)
1369
- )
1370
- }) : null
1472
+ createElement(
1473
+ NativeModalContainer,
1474
+ nativeModalContainerProps,
1475
+ createElement(
1476
+ ChatContentContainer,
1477
+ chatContentContainerProps,
1478
+ showCloseButton ? createElement(
1479
+ View,
1480
+ { style: styles.header },
1481
+ createElement(
1482
+ Pressable,
1483
+ {
1484
+ accessibilityRole: "button",
1485
+ accessibilityLabel: closeLabel,
1486
+ onPress: () => internalSagepilotChat.dismiss(),
1487
+ style: styles.closeButton
1488
+ },
1489
+ createElement(Text, { style: styles.closeText }, closeLabel)
1490
+ )
1491
+ ) : null,
1492
+ state.conversationUrl ? createElement(WebView, {
1493
+ ...hostedChatWebViewProps,
1494
+ ref: nativeWebViewRef,
1495
+ source: { uri: state.conversationUrl },
1496
+ style: styles.webview,
1497
+ startInLoadingState: true,
1498
+ injectedJavaScriptBeforeContentLoaded: getInjectedWebViewScript(),
1499
+ onMessage: handleWebViewMessage,
1500
+ onLoadEnd: postIdentityToNativeWebView,
1501
+ renderLoading: () => createElement(
1502
+ View,
1503
+ { style: styles.loading },
1504
+ createElement(ActivityIndicator, null),
1505
+ createElement(Text, { style: styles.loadingText }, loadingLabel)
1506
+ )
1507
+ }) : null
1508
+ )
1371
1509
  )
1372
1510
  )
1373
1511
  );
1374
1512
  }
1375
- var styles = import_react_native.StyleSheet.create({
1513
+ var styles = StyleSheet.create({
1376
1514
  root: {
1377
1515
  flex: 1
1378
1516
  },
@@ -1380,6 +1518,11 @@ var styles = import_react_native.StyleSheet.create({
1380
1518
  flex: 1,
1381
1519
  backgroundColor: "#ffffff"
1382
1520
  },
1521
+ modalContent: {
1522
+ flex: 1,
1523
+ width: "100%",
1524
+ backgroundColor: "#ffffff"
1525
+ },
1383
1526
  header: {
1384
1527
  minHeight: 48,
1385
1528
  alignItems: "flex-end",
@@ -1453,7 +1596,7 @@ var styles = import_react_native.StyleSheet.create({
1453
1596
  borderStyle: "none"
1454
1597
  },
1455
1598
  loading: {
1456
- ...import_react_native.StyleSheet.absoluteFillObject,
1599
+ ...StyleSheet.absoluteFillObject,
1457
1600
  alignItems: "center",
1458
1601
  justifyContent: "center",
1459
1602
  backgroundColor: "#ffffff"
@@ -1466,7 +1609,7 @@ var styles = import_react_native.StyleSheet.create({
1466
1609
  });
1467
1610
 
1468
1611
  // src/hooks/useSagepilotChat.ts
1469
- var import_react2 = require("react");
1612
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
1470
1613
  function readState() {
1471
1614
  const state = SagepilotChat.getState();
1472
1615
  return {
@@ -1478,23 +1621,28 @@ function readState() {
1478
1621
  };
1479
1622
  }
1480
1623
  function useSagepilotChat() {
1481
- const [state, setState] = (0, import_react2.useState)(readState);
1482
- (0, import_react2.useEffect)(() => {
1624
+ const [state, setState] = useState2(readState);
1625
+ useEffect2(() => {
1483
1626
  return SagepilotChat.onStateChange(() => {
1484
1627
  setState(readState());
1485
1628
  });
1486
1629
  }, []);
1487
- const present = (0, import_react2.useCallback)(() => SagepilotChat.present(), []);
1488
- const presentMessages = (0, import_react2.useCallback)(() => SagepilotChat.presentMessages(), []);
1489
- const presentMessageComposer = (0, import_react2.useCallback)((message) => SagepilotChat.presentMessageComposer(message), []);
1490
- const dismiss = (0, import_react2.useCallback)(() => SagepilotChat.dismiss(), []);
1491
- const hide = (0, import_react2.useCallback)(() => SagepilotChat.hide(), []);
1492
- const toggle = (0, import_react2.useCallback)(() => SagepilotChat.toggle(), []);
1493
- const identify = (0, import_react2.useCallback)((identity) => {
1630
+ const present = useCallback2(() => SagepilotChat.present(), []);
1631
+ const presentMessages = useCallback2(() => SagepilotChat.presentMessages(), []);
1632
+ const presentMessageComposer = useCallback2((message, options) => {
1633
+ return SagepilotChat.presentMessageComposer(message, options);
1634
+ }, []);
1635
+ const dismiss = useCallback2(() => SagepilotChat.dismiss(), []);
1636
+ const hide = useCallback2(() => SagepilotChat.hide(), []);
1637
+ const toggle = useCallback2(() => SagepilotChat.toggle(), []);
1638
+ const identify = useCallback2((identity) => {
1494
1639
  return SagepilotChat.identify(identity);
1495
1640
  }, []);
1496
- const logout = (0, import_react2.useCallback)(() => SagepilotChat.logout(), []);
1497
- const getUnreadCount = (0, import_react2.useCallback)(() => SagepilotChat.getUnreadCount(), []);
1641
+ const logout = useCallback2(() => SagepilotChat.logout(), []);
1642
+ const getUnreadCount = useCallback2(() => SagepilotChat.getUnreadCount(), []);
1643
+ const onConversationCreated = useCallback2((callback) => {
1644
+ return SagepilotChat.onConversationCreated(callback);
1645
+ }, []);
1498
1646
  return {
1499
1647
  ...state,
1500
1648
  present,
@@ -1505,15 +1653,15 @@ function useSagepilotChat() {
1505
1653
  toggle,
1506
1654
  identify,
1507
1655
  logout,
1508
- getUnreadCount
1656
+ getUnreadCount,
1657
+ onConversationCreated
1509
1658
  };
1510
1659
  }
1511
- // Annotate the CommonJS export names for ESM import in node:
1512
- 0 && (module.exports = {
1660
+ export {
1513
1661
  SagepilotChat,
1514
1662
  SagepilotChatError,
1515
1663
  SagepilotChatProvider,
1516
1664
  createAsyncStorageCacheStorage,
1517
1665
  createKeychainTokenStorage,
1518
1666
  useSagepilotChat
1519
- });
1667
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagepilot-ai/react-native-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Sagepilot AI React Native chat SDK",
5
5
  "keywords": [
6
6
  "sagepilot",
@@ -11,28 +11,38 @@
11
11
  "sdk"
12
12
  ],
13
13
  "license": "MIT",
14
- "type": "module",
15
- "main": "./dist/index.cjs",
16
- "module": "./dist/index.js",
14
+ "main": "./dist/index.js",
15
+ "module": "./dist/index.mjs",
16
+ "react-native": "./dist/index.js",
17
17
  "types": "./dist/index.d.ts",
18
18
  "exports": {
19
19
  ".": {
20
20
  "types": "./dist/index.d.ts",
21
- "import": "./dist/index.js",
22
- "require": "./dist/index.cjs"
21
+ "import": "./dist/index.mjs",
22
+ "require": "./dist/index.js"
23
23
  }
24
24
  },
25
25
  "files": [
26
26
  "LICENSE.md",
27
- "android",
27
+ "android/build.gradle",
28
+ "android/src",
28
29
  "dist",
29
30
  "ios",
30
31
  "react-native.config.js",
32
+ "src/specs",
31
33
  "README.md"
32
34
  ],
35
+ "codegenConfig": {
36
+ "name": "SagepilotReactNativeSdkSpec",
37
+ "type": "components",
38
+ "jsSrcsDir": "./src/specs",
39
+ "android": {
40
+ "javaPackageName": "ai.sagepilot.reactnativesdk"
41
+ }
42
+ },
33
43
  "sideEffects": false,
34
44
  "scripts": {
35
- "build": "tsup src/index.ts --format esm,cjs --dts --clean --external react --external react-native --external react-native-webview",
45
+ "build": "tsup",
36
46
  "typecheck": "tsc --noEmit",
37
47
  "prepublishOnly": "npm run typecheck && npm run build"
38
48
  },