@paymanai/payman-ask-sdk 4.0.19 → 4.0.21
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.
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +149 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +150 -27
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +265 -120
- package/dist/index.native.js.map +1 -1
- package/dist/styles.css +3 -2
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.native.js
CHANGED
|
@@ -731,7 +731,8 @@ function buildRequestBody(config, userMessage, sessionId, options) {
|
|
|
731
731
|
sessionAttributes,
|
|
732
732
|
analysisMode: options?.analysisMode,
|
|
733
733
|
locale: resolveLocale(config.locale),
|
|
734
|
-
timezone: resolveTimezone(config.timezone)
|
|
734
|
+
timezone: resolveTimezone(config.timezone),
|
|
735
|
+
...options?.attachments?.length ? { attachments: options.attachments } : {}
|
|
735
736
|
};
|
|
736
737
|
}
|
|
737
738
|
function resolveLocale(configured) {
|
|
@@ -776,6 +777,7 @@ function buildResolveImagesUrl(config) {
|
|
|
776
777
|
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
777
778
|
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
778
779
|
}
|
|
780
|
+
var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
|
|
779
781
|
function buildRequestHeaders(config) {
|
|
780
782
|
const headers = {
|
|
781
783
|
...config.api.headers
|
|
@@ -783,6 +785,9 @@ function buildRequestHeaders(config) {
|
|
|
783
785
|
if (config.api.authToken) {
|
|
784
786
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
785
787
|
}
|
|
788
|
+
if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
|
|
789
|
+
headers[NGROK_SKIP_BROWSER_WARNING] = "true";
|
|
790
|
+
}
|
|
786
791
|
return headers;
|
|
787
792
|
}
|
|
788
793
|
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
@@ -1063,6 +1068,81 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1063
1068
|
currentMessage: currentMessage || "Thinking..."
|
|
1064
1069
|
};
|
|
1065
1070
|
}
|
|
1071
|
+
var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
|
|
1072
|
+
function fileExtension(filename) {
|
|
1073
|
+
const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
|
|
1074
|
+
return ext && ext.length > 0 ? ext : "bin";
|
|
1075
|
+
}
|
|
1076
|
+
function resolveMimeType(file) {
|
|
1077
|
+
if (file.type && file.type.trim().length > 0) return file.type;
|
|
1078
|
+
const ext = fileExtension(file.name);
|
|
1079
|
+
const byExt = {
|
|
1080
|
+
pdf: "application/pdf",
|
|
1081
|
+
png: "image/png",
|
|
1082
|
+
jpg: "image/jpeg",
|
|
1083
|
+
jpeg: "image/jpeg",
|
|
1084
|
+
gif: "image/gif",
|
|
1085
|
+
webp: "image/webp"
|
|
1086
|
+
};
|
|
1087
|
+
return byExt[ext] ?? "application/octet-stream";
|
|
1088
|
+
}
|
|
1089
|
+
function buildSignedUrlEndpoint(config, ext) {
|
|
1090
|
+
const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
|
|
1091
|
+
const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
|
|
1092
|
+
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
1093
|
+
}
|
|
1094
|
+
async function requestSignedUrl(config, ext, signal) {
|
|
1095
|
+
const url = buildSignedUrlEndpoint(config, ext);
|
|
1096
|
+
const headers = buildRequestHeaders(config);
|
|
1097
|
+
const response = await fetch(url, {
|
|
1098
|
+
method: "GET",
|
|
1099
|
+
headers,
|
|
1100
|
+
signal
|
|
1101
|
+
});
|
|
1102
|
+
if (!response.ok) {
|
|
1103
|
+
const errorText = await response.text().catch(() => "");
|
|
1104
|
+
throw new Error(
|
|
1105
|
+
errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
const data = await response.json();
|
|
1109
|
+
if (!data.key || !data.url) {
|
|
1110
|
+
throw new Error("Signed URL response missing key or url");
|
|
1111
|
+
}
|
|
1112
|
+
return { key: data.key, url: data.url };
|
|
1113
|
+
}
|
|
1114
|
+
async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
|
|
1115
|
+
const response = await fetch(signedUrl, {
|
|
1116
|
+
method: "PUT",
|
|
1117
|
+
headers: {
|
|
1118
|
+
"Content-Type": mimeType,
|
|
1119
|
+
"x-ms-blob-type": "BlockBlob"
|
|
1120
|
+
},
|
|
1121
|
+
body: file,
|
|
1122
|
+
signal
|
|
1123
|
+
});
|
|
1124
|
+
if (!response.ok) {
|
|
1125
|
+
const errorText = await response.text().catch(() => "");
|
|
1126
|
+
throw new Error(
|
|
1127
|
+
errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
async function uploadAttachment(config, file, signal) {
|
|
1132
|
+
const ext = fileExtension(file.name);
|
|
1133
|
+
const mimeType = resolveMimeType(file);
|
|
1134
|
+
const { key, url } = await requestSignedUrl(config, ext, signal);
|
|
1135
|
+
await uploadToSignedUrl(url, file, mimeType, signal);
|
|
1136
|
+
return {
|
|
1137
|
+
tempKey: key,
|
|
1138
|
+
filename: file.name,
|
|
1139
|
+
mimeType
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
async function uploadAttachments(config, files, signal) {
|
|
1143
|
+
const uploads = files.map((file) => uploadAttachment(config, file, signal));
|
|
1144
|
+
return Promise.all(uploads);
|
|
1145
|
+
}
|
|
1066
1146
|
var UserActionStaleError = class extends Error {
|
|
1067
1147
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1068
1148
|
super(message);
|
|
@@ -1099,9 +1179,6 @@ async function cancelUserAction(config, userActionId) {
|
|
|
1099
1179
|
async function resendUserAction(config, userActionId) {
|
|
1100
1180
|
return sendUserActionRequest(config, userActionId, "resend");
|
|
1101
1181
|
}
|
|
1102
|
-
async function expireUserAction(config, userActionId) {
|
|
1103
|
-
return sendUserActionRequest(config, userActionId, "expired");
|
|
1104
|
-
}
|
|
1105
1182
|
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
1106
1183
|
function upsertPrompt(prompts, req) {
|
|
1107
1184
|
const active = { ...req, status: "pending" };
|
|
@@ -1130,12 +1207,32 @@ function getStoredOrInitialMessages(config) {
|
|
|
1130
1207
|
function getSessionIdFromMessages(messages) {
|
|
1131
1208
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1132
1209
|
}
|
|
1210
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
|
|
1211
|
+
function attachmentKindFromFile(file) {
|
|
1212
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
1213
|
+
if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
|
|
1214
|
+
return "file";
|
|
1215
|
+
}
|
|
1216
|
+
function buildMessageAttachments(files) {
|
|
1217
|
+
return files.map((file, index) => {
|
|
1218
|
+
const kind = attachmentKindFromFile(file);
|
|
1219
|
+
return {
|
|
1220
|
+
id: `att-${Date.now()}-${index}`,
|
|
1221
|
+
filename: file.name,
|
|
1222
|
+
mimeType: file.type || "application/octet-stream",
|
|
1223
|
+
// Blob URL for all local files so PDFs/docs stay previewable after send.
|
|
1224
|
+
previewUrl: URL.createObjectURL(file),
|
|
1225
|
+
kind
|
|
1226
|
+
};
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1133
1229
|
function useChatV2(config, callbacks = {}) {
|
|
1134
1230
|
const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
|
|
1135
1231
|
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
|
|
1136
1232
|
if (!config.userId) return false;
|
|
1137
1233
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1138
1234
|
});
|
|
1235
|
+
const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
|
|
1139
1236
|
const sessionIdRef = react.useRef(
|
|
1140
1237
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1141
1238
|
);
|
|
@@ -1210,21 +1307,45 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1210
1307
|
);
|
|
1211
1308
|
const sendMessage = react.useCallback(
|
|
1212
1309
|
async (userMessage, options) => {
|
|
1213
|
-
|
|
1310
|
+
const trimmedMessage = userMessage.trim();
|
|
1311
|
+
const files = options?.files ?? [];
|
|
1312
|
+
const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
|
|
1313
|
+
if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
|
|
1314
|
+
let streamAttachments = options?.attachments;
|
|
1315
|
+
if (!streamAttachments && files.length > 0) {
|
|
1316
|
+
setIsUploadingAttachments(true);
|
|
1317
|
+
try {
|
|
1318
|
+
streamAttachments = await uploadAttachments(configRef.current, files);
|
|
1319
|
+
} catch (error) {
|
|
1320
|
+
if (error.name !== "AbortError") {
|
|
1321
|
+
callbacksRef.current.onError?.(error);
|
|
1322
|
+
}
|
|
1323
|
+
throw error;
|
|
1324
|
+
} finally {
|
|
1325
|
+
setIsUploadingAttachments(false);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1214
1328
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1215
1329
|
sessionIdRef.current = generateId();
|
|
1216
1330
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1217
1331
|
}
|
|
1332
|
+
const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
|
|
1333
|
+
id: `att-${Date.now()}-${index}`,
|
|
1334
|
+
filename: attachment.filename,
|
|
1335
|
+
mimeType: attachment.mimeType,
|
|
1336
|
+
kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
|
|
1337
|
+
})) : void 0;
|
|
1218
1338
|
const userMessageId = `user-${Date.now()}`;
|
|
1219
1339
|
const userMsg = {
|
|
1220
1340
|
id: userMessageId,
|
|
1221
1341
|
sessionId: sessionIdRef.current,
|
|
1222
1342
|
role: "user",
|
|
1223
|
-
content:
|
|
1224
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1343
|
+
content: trimmedMessage,
|
|
1344
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1345
|
+
attachments: messageAttachments
|
|
1225
1346
|
};
|
|
1226
1347
|
setMessages((prev) => [...prev, userMsg]);
|
|
1227
|
-
callbacksRef.current.onMessageSent?.(
|
|
1348
|
+
callbacksRef.current.onMessageSent?.(trimmedMessage);
|
|
1228
1349
|
setIsWaitingForResponse(true);
|
|
1229
1350
|
callbacksRef.current.onStreamStart?.();
|
|
1230
1351
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1251,11 +1372,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1251
1372
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1252
1373
|
}
|
|
1253
1374
|
const newSessionId = await startStream(
|
|
1254
|
-
|
|
1375
|
+
trimmedMessage,
|
|
1255
1376
|
streamingId,
|
|
1256
1377
|
sessionIdRef.current,
|
|
1257
1378
|
abortController,
|
|
1258
|
-
|
|
1379
|
+
{
|
|
1380
|
+
analysisMode: options?.analysisMode,
|
|
1381
|
+
attachments: streamAttachments
|
|
1382
|
+
}
|
|
1259
1383
|
);
|
|
1260
1384
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1261
1385
|
if (finalStreamUserId) {
|
|
@@ -1393,19 +1517,6 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1393
1517
|
},
|
|
1394
1518
|
[setPromptStatus]
|
|
1395
1519
|
);
|
|
1396
|
-
const expireUserAction2 = react.useCallback(
|
|
1397
|
-
async (userActionId) => {
|
|
1398
|
-
setPromptStatus(userActionId, "expired");
|
|
1399
|
-
try {
|
|
1400
|
-
await expireUserAction(configRef.current, userActionId);
|
|
1401
|
-
} catch (error) {
|
|
1402
|
-
if (error instanceof UserActionStaleError) return;
|
|
1403
|
-
callbacksRef.current.onError?.(error);
|
|
1404
|
-
throw error;
|
|
1405
|
-
}
|
|
1406
|
-
},
|
|
1407
|
-
[setPromptStatus]
|
|
1408
|
-
);
|
|
1409
1520
|
const dismissNotification = react.useCallback((id) => {
|
|
1410
1521
|
setUserActionState((prev) => ({
|
|
1411
1522
|
...prev,
|
|
@@ -1446,6 +1557,18 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1446
1557
|
setMessages(config.initialMessages);
|
|
1447
1558
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1448
1559
|
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1560
|
+
const hydratedSessionIdRef = react.useRef(void 0);
|
|
1561
|
+
react.useEffect(() => {
|
|
1562
|
+
if (config.userId) return;
|
|
1563
|
+
if (!config.initialMessages?.length) return;
|
|
1564
|
+
const sessionId = config.initialSessionId;
|
|
1565
|
+
if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
hydratedSessionIdRef.current = sessionId;
|
|
1569
|
+
setMessages(config.initialMessages);
|
|
1570
|
+
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
|
|
1571
|
+
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1449
1572
|
react.useEffect(() => {
|
|
1450
1573
|
const prevUserId = prevUserIdRef.current;
|
|
1451
1574
|
prevUserIdRef.current = config.userId;
|
|
@@ -1480,12 +1603,12 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1480
1603
|
getSessionId,
|
|
1481
1604
|
getMessages,
|
|
1482
1605
|
isWaitingForResponse,
|
|
1606
|
+
isUploadingAttachments,
|
|
1483
1607
|
sessionId: sessionIdRef.current,
|
|
1484
1608
|
userActionState,
|
|
1485
1609
|
submitUserAction: submitUserAction2,
|
|
1486
1610
|
cancelUserAction: cancelUserAction2,
|
|
1487
1611
|
resendUserAction: resendUserAction2,
|
|
1488
|
-
expireUserAction: expireUserAction2,
|
|
1489
1612
|
dismissNotification
|
|
1490
1613
|
};
|
|
1491
1614
|
}
|
|
@@ -2803,6 +2926,7 @@ function UserActionSheet({
|
|
|
2803
2926
|
react.useEffect(() => {
|
|
2804
2927
|
minimizeRef.current = onMinimize;
|
|
2805
2928
|
});
|
|
2929
|
+
const [mounted, setMounted] = react.useState(open);
|
|
2806
2930
|
const [kbHeight, setKbHeight] = react.useState(0);
|
|
2807
2931
|
react.useEffect(() => {
|
|
2808
2932
|
const showEvt = reactNative.Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
|
|
@@ -2816,16 +2940,24 @@ function UserActionSheet({
|
|
|
2816
2940
|
}, []);
|
|
2817
2941
|
react.useEffect(() => {
|
|
2818
2942
|
if (open) {
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2943
|
+
setMounted(true);
|
|
2944
|
+
translateY.setValue(screenH);
|
|
2945
|
+
backdrop.setValue(0);
|
|
2946
|
+
const id = requestAnimationFrame(() => {
|
|
2947
|
+
reactNative.Animated.parallel([
|
|
2948
|
+
reactNative.Animated.spring(translateY, { toValue: 0, useNativeDriver: true, damping: 30, stiffness: 360, mass: 0.85 }),
|
|
2949
|
+
reactNative.Animated.timing(backdrop, { toValue: 1, duration: 190, useNativeDriver: true })
|
|
2950
|
+
]).start();
|
|
2951
|
+
});
|
|
2952
|
+
return () => cancelAnimationFrame(id);
|
|
2828
2953
|
}
|
|
2954
|
+
reactNative.Animated.parallel([
|
|
2955
|
+
reactNative.Animated.timing(translateY, { toValue: screenH, duration: 230, easing: reactNative.Easing.in(reactNative.Easing.cubic), useNativeDriver: true }),
|
|
2956
|
+
reactNative.Animated.timing(backdrop, { toValue: 0, duration: 180, useNativeDriver: true })
|
|
2957
|
+
]).start(({ finished }) => {
|
|
2958
|
+
if (finished) setMounted(false);
|
|
2959
|
+
});
|
|
2960
|
+
return void 0;
|
|
2829
2961
|
}, [open, translateY, backdrop, screenH]);
|
|
2830
2962
|
const pan = react.useRef(
|
|
2831
2963
|
reactNative.PanResponder.create({
|
|
@@ -2843,66 +2975,77 @@ function UserActionSheet({
|
|
|
2843
2975
|
})
|
|
2844
2976
|
).current;
|
|
2845
2977
|
const a = active ?? shown;
|
|
2846
|
-
if (!a) return
|
|
2978
|
+
if (!mounted || !a) return null;
|
|
2847
2979
|
const isVerification = a.kind === "verification";
|
|
2848
2980
|
const title = isVerification ? "Verification required" : "Action required";
|
|
2849
2981
|
const subtitle = isVerification ? "Confirm the one-time code to continue" : "Review the details and confirm to continue";
|
|
2850
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
{
|
|
2862
|
-
style: [
|
|
2863
|
-
sht.sheet,
|
|
2982
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2983
|
+
reactNative.Modal,
|
|
2984
|
+
{
|
|
2985
|
+
visible: mounted,
|
|
2986
|
+
transparent: true,
|
|
2987
|
+
animationType: "none",
|
|
2988
|
+
statusBarTranslucent: true,
|
|
2989
|
+
onRequestClose: () => minimizeRef.current(),
|
|
2990
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: reactNative.StyleSheet.absoluteFill, pointerEvents: open ? "auto" : "none", children: [
|
|
2991
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2992
|
+
reactNative.Animated.View,
|
|
2864
2993
|
{
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
// Cap to the space above the keyboard (and a top margin) so the
|
|
2868
|
-
// header stays visible and the footer sits above the keyboard;
|
|
2869
|
-
// the field area scrolls within whatever's left.
|
|
2870
|
-
maxHeight: Math.min(screenH * 0.9, screenH - kbHeight - 72),
|
|
2871
|
-
paddingBottom: kbHeight > 0 ? 16 : Math.max(insetBottom, 16) + 6,
|
|
2872
|
-
transform: [{ translateY }]
|
|
2994
|
+
pointerEvents: "none",
|
|
2995
|
+
style: [sht.backdrop, { backgroundColor: pal.overlay, opacity: backdrop }]
|
|
2873
2996
|
}
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2997
|
+
),
|
|
2998
|
+
open ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: reactNative.StyleSheet.absoluteFill, onPress: () => minimizeRef.current(), accessibilityLabel: "Dismiss" }) : null,
|
|
2999
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [sht.kav, { paddingBottom: kbHeight }], pointerEvents: "box-none", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3000
|
+
reactNative.Animated.View,
|
|
3001
|
+
{
|
|
3002
|
+
style: [
|
|
3003
|
+
sht.sheet,
|
|
3004
|
+
{
|
|
3005
|
+
backgroundColor: pal.sheetBg,
|
|
3006
|
+
borderColor: pal.border,
|
|
3007
|
+
// Cap to the space above the keyboard (and a top margin) so the
|
|
3008
|
+
// header stays visible and the footer sits above the keyboard;
|
|
3009
|
+
// the field area scrolls within whatever's left.
|
|
3010
|
+
maxHeight: Math.min(screenH * 0.9, screenH - kbHeight - 72),
|
|
3011
|
+
paddingBottom: kbHeight > 0 ? 16 : Math.max(insetBottom, 16) + 6,
|
|
3012
|
+
transform: [{ translateY }]
|
|
3013
|
+
}
|
|
3014
|
+
],
|
|
3015
|
+
children: [
|
|
3016
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ...pan.panHandlers, style: sht.handleZone, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [sht.grabber, { backgroundColor: pal.grabber }] }) }),
|
|
3017
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: sht.header, children: [
|
|
3018
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [sht.iconCircle, { backgroundColor: accent + (isDark ? "26" : "14") }], children: isVerification ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ShieldCheck, { size: 19, color: accent, strokeWidth: 2.1 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Pencil, { size: 17, color: accent, strokeWidth: 2.1 }) }),
|
|
3019
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: sht.headerText, children: [
|
|
3020
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [sht.title, { color: pal.text }], numberOfLines: 1, children: title }),
|
|
3021
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [sht.subtitle, { color: pal.muted }], numberOfLines: 1, children: subtitle })
|
|
3022
|
+
] }),
|
|
3023
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetTimerPill, { prompt: a, accent, isDark }),
|
|
3024
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: () => minimizeRef.current(), hitSlop: 10, style: [sht.closeBtn, { backgroundColor: pal.fieldBg }], children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 15, color: pal.muted, strokeWidth: 2.3 }) })
|
|
3025
|
+
] }),
|
|
3026
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [sht.headerRule, { backgroundColor: pal.border }] }),
|
|
3027
|
+
a.status === "stale" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: sht.simpleBody, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [ub.desc, { color: pal.muted }], children: "This request is no longer available." }) }) : expired ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: sht.simpleBody, children: [
|
|
3028
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [ub.desc, { color: pal.muted }], children: isVerification ? "This verification request expired." : "This request expired." }),
|
|
3029
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: ub.actions, children: /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { label: "Close", onPress: () => void onCancel(a.userActionId), accent }) })
|
|
3030
|
+
] }) : isVerification ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3031
|
+
VerificationBody,
|
|
3032
|
+
{
|
|
3033
|
+
prompt: a,
|
|
3034
|
+
expired,
|
|
3035
|
+
pal,
|
|
3036
|
+
accent,
|
|
3037
|
+
onSubmit,
|
|
3038
|
+
onCancel,
|
|
3039
|
+
onResend
|
|
3040
|
+
},
|
|
3041
|
+
a.userActionId
|
|
3042
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(FormBody, { prompt: a, pal, accent, isDark, onSubmit, onCancel }, a.userActionId)
|
|
3043
|
+
]
|
|
3044
|
+
}
|
|
3045
|
+
) })
|
|
3046
|
+
] })
|
|
3047
|
+
}
|
|
3048
|
+
);
|
|
2906
3049
|
}
|
|
2907
3050
|
function UserActionReopenCard({
|
|
2908
3051
|
active,
|
|
@@ -2962,35 +3105,35 @@ var ub = reactNative.StyleSheet.create({
|
|
|
2962
3105
|
// forms (no scroll), shrinks and scrolls only when the form exceeds the sheet.
|
|
2963
3106
|
fieldsScroll: { flexShrink: 1 },
|
|
2964
3107
|
fieldsContent: { paddingBottom: 6 },
|
|
2965
|
-
messageBlock: { marginBottom:
|
|
2966
|
-
desc: { fontSize: 14
|
|
2967
|
-
form: { gap:
|
|
2968
|
-
field: { gap:
|
|
2969
|
-
label: { fontSize:
|
|
2970
|
-
hint: { fontSize: 12
|
|
3108
|
+
messageBlock: { marginBottom: 14, marginTop: 0 },
|
|
3109
|
+
desc: { fontSize: 14, lineHeight: 20, marginBottom: 14 },
|
|
3110
|
+
form: { gap: 14 },
|
|
3111
|
+
field: { gap: 6 },
|
|
3112
|
+
label: { fontSize: 13.5, fontWeight: "600", letterSpacing: -0.1 },
|
|
3113
|
+
hint: { fontSize: 12, lineHeight: 16 },
|
|
2971
3114
|
input: {
|
|
2972
3115
|
borderWidth: 1,
|
|
2973
3116
|
borderRadius: 12,
|
|
2974
3117
|
paddingHorizontal: 14,
|
|
2975
|
-
paddingVertical:
|
|
3118
|
+
paddingVertical: 12,
|
|
2976
3119
|
fontSize: 16
|
|
2977
3120
|
},
|
|
2978
|
-
error: { color: "#ef4444", fontSize: 12
|
|
3121
|
+
error: { color: "#ef4444", fontSize: 12, marginTop: 2 },
|
|
2979
3122
|
switchRow: { flexDirection: "row", alignItems: "center", gap: 12 },
|
|
2980
3123
|
// Selectable option "boxes" for oneOf / enum single-select fields.
|
|
2981
|
-
optionList: { gap:
|
|
3124
|
+
optionList: { gap: 9 },
|
|
2982
3125
|
optionRow: {
|
|
2983
3126
|
flexDirection: "row",
|
|
2984
3127
|
alignItems: "center",
|
|
2985
3128
|
gap: 12,
|
|
2986
3129
|
borderWidth: 1.5,
|
|
2987
|
-
borderRadius:
|
|
3130
|
+
borderRadius: 13,
|
|
2988
3131
|
paddingHorizontal: 14,
|
|
2989
|
-
paddingVertical:
|
|
3132
|
+
paddingVertical: 13
|
|
2990
3133
|
},
|
|
2991
3134
|
radio: {
|
|
2992
|
-
width:
|
|
2993
|
-
height:
|
|
3135
|
+
width: 19,
|
|
3136
|
+
height: 19,
|
|
2994
3137
|
borderRadius: 10,
|
|
2995
3138
|
borderWidth: 2,
|
|
2996
3139
|
alignItems: "center",
|
|
@@ -2999,10 +3142,10 @@ var ub = reactNative.StyleSheet.create({
|
|
|
2999
3142
|
radioDot: { width: 10, height: 10, borderRadius: 5 },
|
|
3000
3143
|
optionLabel: { flex: 1, fontSize: 15, letterSpacing: -0.1 },
|
|
3001
3144
|
// Pinned footer (outside the fields scroll) — always visible.
|
|
3002
|
-
actions: { paddingTop:
|
|
3003
|
-
primaryBtn: { minHeight:
|
|
3145
|
+
actions: { paddingTop: 14, gap: 12 },
|
|
3146
|
+
primaryBtn: { minHeight: 50, borderRadius: 14, borderWidth: 1, paddingVertical: 14, alignItems: "center", justifyContent: "center" },
|
|
3004
3147
|
primaryBtnText: { color: "#fff", fontSize: 15.5, fontWeight: "600", letterSpacing: -0.1 },
|
|
3005
|
-
linkRow: { flexDirection: "row", justifyContent: "center", gap: 24 },
|
|
3148
|
+
linkRow: { flexDirection: "row", justifyContent: "center", gap: 24, paddingTop: 2 },
|
|
3006
3149
|
link: { fontSize: 14, fontWeight: "500" },
|
|
3007
3150
|
linkDanger: { color: "#dc2626" },
|
|
3008
3151
|
codeRow: { flexDirection: "row", justifyContent: "center", gap: 9, position: "relative" },
|
|
@@ -3035,34 +3178,36 @@ var sht = reactNative.StyleSheet.create({
|
|
|
3035
3178
|
backdrop: { ...reactNative.StyleSheet.absoluteFillObject },
|
|
3036
3179
|
kav: { flex: 1, justifyContent: "flex-end" },
|
|
3037
3180
|
sheet: {
|
|
3038
|
-
borderTopLeftRadius:
|
|
3039
|
-
borderTopRightRadius:
|
|
3181
|
+
borderTopLeftRadius: 26,
|
|
3182
|
+
borderTopRightRadius: 26,
|
|
3040
3183
|
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
3041
3184
|
borderBottomWidth: 0,
|
|
3042
|
-
paddingHorizontal:
|
|
3043
|
-
paddingTop:
|
|
3185
|
+
paddingHorizontal: 20,
|
|
3186
|
+
paddingTop: 4,
|
|
3044
3187
|
maxWidth: 640,
|
|
3045
3188
|
width: "100%",
|
|
3046
3189
|
alignSelf: "center",
|
|
3047
3190
|
...reactNative.Platform.select({
|
|
3048
3191
|
ios: {
|
|
3049
3192
|
shadowColor: "#000",
|
|
3050
|
-
shadowOffset: { width: 0, height: -
|
|
3051
|
-
shadowOpacity: 0.
|
|
3052
|
-
shadowRadius:
|
|
3193
|
+
shadowOffset: { width: 0, height: -8 },
|
|
3194
|
+
shadowOpacity: 0.22,
|
|
3195
|
+
shadowRadius: 28
|
|
3053
3196
|
},
|
|
3054
3197
|
android: { elevation: 24 }
|
|
3055
3198
|
})
|
|
3056
3199
|
},
|
|
3057
|
-
handleZone: { alignItems: "center",
|
|
3058
|
-
grabber: { width:
|
|
3059
|
-
header: { flexDirection: "row", alignItems: "center", gap:
|
|
3060
|
-
iconCircle: { width:
|
|
3061
|
-
headerText: { flex: 1, gap:
|
|
3062
|
-
title: { fontSize:
|
|
3063
|
-
subtitle: { fontSize:
|
|
3064
|
-
|
|
3065
|
-
|
|
3200
|
+
handleZone: { alignItems: "center", paddingTop: 9, paddingBottom: 8 },
|
|
3201
|
+
grabber: { width: 38, height: 5, borderRadius: 3 },
|
|
3202
|
+
header: { flexDirection: "row", alignItems: "center", gap: 11, marginTop: 0, marginBottom: 14 },
|
|
3203
|
+
iconCircle: { width: 36, height: 36, borderRadius: 12, alignItems: "center", justifyContent: "center" },
|
|
3204
|
+
headerText: { flex: 1, gap: 1 },
|
|
3205
|
+
title: { fontSize: 17, fontWeight: "700", letterSpacing: -0.3 },
|
|
3206
|
+
subtitle: { fontSize: 12.5, letterSpacing: -0.1 },
|
|
3207
|
+
// Hairline rule under the header so the title cluster reads as its own zone.
|
|
3208
|
+
headerRule: { height: reactNative.StyleSheet.hairlineWidth, marginBottom: 16, marginHorizontal: -20 },
|
|
3209
|
+
timer: { borderWidth: 1, borderRadius: 999, paddingHorizontal: 10, paddingVertical: 4.5, minWidth: 44, alignItems: "center" },
|
|
3210
|
+
closeBtn: { width: 29, height: 29, borderRadius: 14.5, alignItems: "center", justifyContent: "center" },
|
|
3066
3211
|
// Short, non-scrolling bodies (stale / expired notices).
|
|
3067
3212
|
simpleBody: { paddingBottom: 8 }
|
|
3068
3213
|
});
|