@comergehq/studio 0.1.7 → 0.1.9
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.js +703 -611
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +459 -367
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/ChatComposer.tsx +3 -1
- package/src/components/chat/ChatMessageList.tsx +29 -10
- package/src/components/chat/ChatPage.tsx +25 -30
- package/src/components/comments/AppCommentsSheet.tsx +6 -1
- package/src/components/comments/useIosKeyboardSnapFix.ts +11 -3
- package/src/components/studio-sheet/StudioBottomSheet.tsx +25 -10
- package/src/studio/hooks/useApp.ts +10 -4
- package/src/studio/hooks/useForegroundSignal.ts +37 -0
- package/src/studio/hooks/useThreadMessages.ts +25 -5
- package/src/studio/ui/ChatPanel.tsx +9 -3
- package/src/studio/ui/StudioOverlay.tsx +8 -4
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
// src/studio/ComergeStudio.tsx
|
|
9
|
-
import * as
|
|
9
|
+
import * as React39 from "react";
|
|
10
10
|
import { Platform as RNPlatform, View as View45 } from "react-native";
|
|
11
11
|
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
|
12
12
|
|
|
@@ -363,7 +363,7 @@ function StudioBootstrap({ children, fallback, renderError, apiKey }) {
|
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
// src/studio/hooks/useApp.ts
|
|
366
|
-
import * as
|
|
366
|
+
import * as React3 from "react";
|
|
367
367
|
|
|
368
368
|
// src/core/services/http/index.ts
|
|
369
369
|
import axios2 from "axios";
|
|
@@ -662,13 +662,40 @@ var AppsRepositoryImpl = class extends BaseRepository {
|
|
|
662
662
|
};
|
|
663
663
|
var appsRepository = new AppsRepositoryImpl(appsRemoteDataSource);
|
|
664
664
|
|
|
665
|
+
// src/studio/hooks/useForegroundSignal.ts
|
|
666
|
+
import * as React2 from "react";
|
|
667
|
+
import { AppState } from "react-native";
|
|
668
|
+
function useForegroundSignal(enabled = true) {
|
|
669
|
+
const [signal, setSignal] = React2.useState(0);
|
|
670
|
+
const lastStateRef = React2.useRef(AppState.currentState);
|
|
671
|
+
React2.useEffect(() => {
|
|
672
|
+
if (!enabled) return;
|
|
673
|
+
const sub = AppState.addEventListener("change", (nextState) => {
|
|
674
|
+
var _a, _b;
|
|
675
|
+
const prevState = lastStateRef.current;
|
|
676
|
+
lastStateRef.current = nextState;
|
|
677
|
+
const didResume = (prevState === "background" || prevState === "inactive") && nextState === "active";
|
|
678
|
+
if (!didResume) return;
|
|
679
|
+
try {
|
|
680
|
+
const supabase = getSupabaseClient();
|
|
681
|
+
(_b = (_a = supabase == null ? void 0 : supabase.realtime) == null ? void 0 : _a.connect) == null ? void 0 : _b.call(_a);
|
|
682
|
+
} catch {
|
|
683
|
+
}
|
|
684
|
+
setSignal((s) => s + 1);
|
|
685
|
+
});
|
|
686
|
+
return () => sub.remove();
|
|
687
|
+
}, [enabled]);
|
|
688
|
+
return signal;
|
|
689
|
+
}
|
|
690
|
+
|
|
665
691
|
// src/studio/hooks/useApp.ts
|
|
666
692
|
function useApp(appId, options) {
|
|
667
693
|
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
668
|
-
const [app, setApp] =
|
|
669
|
-
const [loading, setLoading] =
|
|
670
|
-
const [error, setError] =
|
|
671
|
-
const
|
|
694
|
+
const [app, setApp] = React3.useState(null);
|
|
695
|
+
const [loading, setLoading] = React3.useState(false);
|
|
696
|
+
const [error, setError] = React3.useState(null);
|
|
697
|
+
const foregroundSignal = useForegroundSignal(enabled && Boolean(appId));
|
|
698
|
+
const mergeApp = React3.useCallback((prev, next) => {
|
|
672
699
|
const merged = {
|
|
673
700
|
...prev ?? {},
|
|
674
701
|
...next,
|
|
@@ -677,7 +704,7 @@ function useApp(appId, options) {
|
|
|
677
704
|
};
|
|
678
705
|
return merged;
|
|
679
706
|
}, []);
|
|
680
|
-
const fetchOnce =
|
|
707
|
+
const fetchOnce = React3.useCallback(async () => {
|
|
681
708
|
if (!enabled) return;
|
|
682
709
|
if (!appId) return;
|
|
683
710
|
setLoading(true);
|
|
@@ -692,34 +719,37 @@ function useApp(appId, options) {
|
|
|
692
719
|
setLoading(false);
|
|
693
720
|
}
|
|
694
721
|
}, [appId, enabled]);
|
|
695
|
-
|
|
722
|
+
React3.useEffect(() => {
|
|
696
723
|
if (!enabled) return;
|
|
697
724
|
void fetchOnce();
|
|
698
725
|
}, [enabled, fetchOnce]);
|
|
699
|
-
|
|
726
|
+
React3.useEffect(() => {
|
|
700
727
|
if (!enabled) return;
|
|
701
728
|
if (!appId) return;
|
|
702
729
|
const unsubscribe = appsRepository.subscribeApp(appId, {
|
|
703
730
|
onInsert: (a) => {
|
|
704
|
-
console.log("[useApp] onInsert", a);
|
|
705
731
|
setApp((prev) => mergeApp(prev, a));
|
|
706
732
|
},
|
|
707
733
|
onUpdate: (a) => {
|
|
708
|
-
console.log("[useApp] onUpdate", a);
|
|
709
734
|
setApp((prev) => mergeApp(prev, a));
|
|
710
735
|
},
|
|
711
736
|
onDelete: () => {
|
|
712
|
-
console.log("[useApp] onDelete");
|
|
713
737
|
setApp(null);
|
|
714
738
|
}
|
|
715
739
|
});
|
|
716
740
|
return unsubscribe;
|
|
717
|
-
}, [appId, enabled, mergeApp]);
|
|
741
|
+
}, [appId, enabled, mergeApp, foregroundSignal]);
|
|
742
|
+
React3.useEffect(() => {
|
|
743
|
+
if (!enabled) return;
|
|
744
|
+
if (!appId) return;
|
|
745
|
+
if (foregroundSignal <= 0) return;
|
|
746
|
+
void fetchOnce();
|
|
747
|
+
}, [appId, enabled, fetchOnce, foregroundSignal]);
|
|
718
748
|
return { app, loading, error, refetch: fetchOnce };
|
|
719
749
|
}
|
|
720
750
|
|
|
721
751
|
// src/studio/hooks/useThreadMessages.ts
|
|
722
|
-
import * as
|
|
752
|
+
import * as React4 from "react";
|
|
723
753
|
|
|
724
754
|
// src/data/messages/remote.ts
|
|
725
755
|
var MessagesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -820,44 +850,59 @@ function mapMessageToChatMessage(m) {
|
|
|
820
850
|
};
|
|
821
851
|
}
|
|
822
852
|
function useThreadMessages(threadId) {
|
|
823
|
-
const [raw, setRaw] =
|
|
824
|
-
const [loading, setLoading] =
|
|
825
|
-
const [error, setError] =
|
|
826
|
-
const
|
|
853
|
+
const [raw, setRaw] = React4.useState([]);
|
|
854
|
+
const [loading, setLoading] = React4.useState(false);
|
|
855
|
+
const [error, setError] = React4.useState(null);
|
|
856
|
+
const activeRequestIdRef = React4.useRef(0);
|
|
857
|
+
const foregroundSignal = useForegroundSignal(Boolean(threadId));
|
|
858
|
+
const upsertSorted = React4.useCallback((prev, m) => {
|
|
859
|
+
const next = prev.some((x) => x.id === m.id) ? prev.map((x) => x.id === m.id ? m : x) : [...prev, m];
|
|
860
|
+
next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
861
|
+
return next;
|
|
862
|
+
}, []);
|
|
863
|
+
const refetch = React4.useCallback(async () => {
|
|
827
864
|
if (!threadId) {
|
|
828
865
|
setRaw([]);
|
|
829
866
|
return;
|
|
830
867
|
}
|
|
868
|
+
const requestId = ++activeRequestIdRef.current;
|
|
831
869
|
setLoading(true);
|
|
832
870
|
setError(null);
|
|
833
871
|
try {
|
|
834
872
|
const list = await messagesRepository.list(threadId);
|
|
835
|
-
|
|
873
|
+
if (activeRequestIdRef.current !== requestId) return;
|
|
874
|
+
setRaw([...list].sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt))));
|
|
836
875
|
} catch (e) {
|
|
876
|
+
if (activeRequestIdRef.current !== requestId) return;
|
|
837
877
|
setError(e instanceof Error ? e : new Error(String(e)));
|
|
838
878
|
setRaw([]);
|
|
839
879
|
} finally {
|
|
840
|
-
setLoading(false);
|
|
880
|
+
if (activeRequestIdRef.current === requestId) setLoading(false);
|
|
841
881
|
}
|
|
842
882
|
}, [threadId]);
|
|
843
|
-
|
|
883
|
+
React4.useEffect(() => {
|
|
844
884
|
void refetch();
|
|
845
885
|
}, [refetch]);
|
|
846
|
-
|
|
886
|
+
React4.useEffect(() => {
|
|
847
887
|
if (!threadId) return;
|
|
848
888
|
const unsubscribe = messagesRepository.subscribeThread(threadId, {
|
|
849
|
-
onInsert: (m) => setRaw((prev) =>
|
|
850
|
-
onUpdate: (m) => setRaw((prev) => prev
|
|
889
|
+
onInsert: (m) => setRaw((prev) => upsertSorted(prev, m)),
|
|
890
|
+
onUpdate: (m) => setRaw((prev) => upsertSorted(prev, m)),
|
|
851
891
|
onDelete: (m) => setRaw((prev) => prev.filter((x) => x.id !== m.id))
|
|
852
892
|
});
|
|
853
893
|
return unsubscribe;
|
|
854
|
-
}, [threadId]);
|
|
855
|
-
|
|
894
|
+
}, [threadId, upsertSorted, foregroundSignal]);
|
|
895
|
+
React4.useEffect(() => {
|
|
896
|
+
if (!threadId) return;
|
|
897
|
+
if (foregroundSignal <= 0) return;
|
|
898
|
+
void refetch();
|
|
899
|
+
}, [foregroundSignal, refetch, threadId]);
|
|
900
|
+
const messages = React4.useMemo(() => raw.map(mapMessageToChatMessage), [raw]);
|
|
856
901
|
return { raw, messages, loading, error, refetch };
|
|
857
902
|
}
|
|
858
903
|
|
|
859
904
|
// src/studio/hooks/useBundleManager.ts
|
|
860
|
-
import * as
|
|
905
|
+
import * as React5 from "react";
|
|
861
906
|
import * as FileSystem from "expo-file-system/legacy";
|
|
862
907
|
|
|
863
908
|
// src/data/apps/bundles/remote.ts
|
|
@@ -1030,19 +1075,19 @@ function useBundleManager({
|
|
|
1030
1075
|
platform,
|
|
1031
1076
|
canRequestLatest = true
|
|
1032
1077
|
}) {
|
|
1033
|
-
const [bundlePath, setBundlePath] =
|
|
1034
|
-
const [renderToken, setRenderToken] =
|
|
1035
|
-
const [loading, setLoading] =
|
|
1036
|
-
const [statusLabel, setStatusLabel] =
|
|
1037
|
-
const [error, setError] =
|
|
1038
|
-
const [isTesting, setIsTesting] =
|
|
1039
|
-
const baseRef =
|
|
1078
|
+
const [bundlePath, setBundlePath] = React5.useState(null);
|
|
1079
|
+
const [renderToken, setRenderToken] = React5.useState(0);
|
|
1080
|
+
const [loading, setLoading] = React5.useState(false);
|
|
1081
|
+
const [statusLabel, setStatusLabel] = React5.useState(null);
|
|
1082
|
+
const [error, setError] = React5.useState(null);
|
|
1083
|
+
const [isTesting, setIsTesting] = React5.useState(false);
|
|
1084
|
+
const baseRef = React5.useRef(base);
|
|
1040
1085
|
baseRef.current = base;
|
|
1041
|
-
const baseOpIdRef =
|
|
1042
|
-
const testOpIdRef =
|
|
1043
|
-
const activeLoadModeRef =
|
|
1044
|
-
const canRequestLatestRef =
|
|
1045
|
-
|
|
1086
|
+
const baseOpIdRef = React5.useRef(0);
|
|
1087
|
+
const testOpIdRef = React5.useRef(0);
|
|
1088
|
+
const activeLoadModeRef = React5.useRef(null);
|
|
1089
|
+
const canRequestLatestRef = React5.useRef(canRequestLatest);
|
|
1090
|
+
React5.useEffect(() => {
|
|
1046
1091
|
canRequestLatestRef.current = canRequestLatest;
|
|
1047
1092
|
if (!canRequestLatest) {
|
|
1048
1093
|
baseOpIdRef.current += 1;
|
|
@@ -1053,11 +1098,11 @@ function useBundleManager({
|
|
|
1053
1098
|
}
|
|
1054
1099
|
}
|
|
1055
1100
|
}, [canRequestLatest]);
|
|
1056
|
-
const lastBaseBundlePathRef =
|
|
1057
|
-
const lastBaseFingerprintRef =
|
|
1058
|
-
const initialHydratedBaseFromDiskRef =
|
|
1059
|
-
const hasCompletedFirstNetworkBaseLoadRef =
|
|
1060
|
-
const hydrateBaseFromDisk =
|
|
1101
|
+
const lastBaseBundlePathRef = React5.useRef(null);
|
|
1102
|
+
const lastBaseFingerprintRef = React5.useRef(null);
|
|
1103
|
+
const initialHydratedBaseFromDiskRef = React5.useRef(false);
|
|
1104
|
+
const hasCompletedFirstNetworkBaseLoadRef = React5.useRef(false);
|
|
1105
|
+
const hydrateBaseFromDisk = React5.useCallback(
|
|
1061
1106
|
async (appId, reason) => {
|
|
1062
1107
|
try {
|
|
1063
1108
|
const dir = bundlesCacheDir();
|
|
@@ -1082,13 +1127,13 @@ function useBundleManager({
|
|
|
1082
1127
|
},
|
|
1083
1128
|
[platform]
|
|
1084
1129
|
);
|
|
1085
|
-
|
|
1130
|
+
React5.useEffect(() => {
|
|
1086
1131
|
if (!base.appId) return;
|
|
1087
1132
|
initialHydratedBaseFromDiskRef.current = false;
|
|
1088
1133
|
hasCompletedFirstNetworkBaseLoadRef.current = false;
|
|
1089
1134
|
void hydrateBaseFromDisk(base.appId, "initial");
|
|
1090
1135
|
}, [base.appId, platform, hydrateBaseFromDisk]);
|
|
1091
|
-
const activateCachedBase =
|
|
1136
|
+
const activateCachedBase = React5.useCallback(
|
|
1092
1137
|
async (appId) => {
|
|
1093
1138
|
setIsTesting(false);
|
|
1094
1139
|
setStatusLabel(null);
|
|
@@ -1102,7 +1147,7 @@ function useBundleManager({
|
|
|
1102
1147
|
},
|
|
1103
1148
|
[hydrateBaseFromDisk]
|
|
1104
1149
|
);
|
|
1105
|
-
const load =
|
|
1150
|
+
const load = React5.useCallback(async (src, mode) => {
|
|
1106
1151
|
if (!src.appId) return;
|
|
1107
1152
|
const canRequestLatest2 = canRequestLatestRef.current;
|
|
1108
1153
|
if (mode === "base" && !canRequestLatest2) {
|
|
@@ -1157,13 +1202,13 @@ function useBundleManager({
|
|
|
1157
1202
|
if (activeLoadModeRef.current === mode) activeLoadModeRef.current = null;
|
|
1158
1203
|
}
|
|
1159
1204
|
}, [activateCachedBase, platform]);
|
|
1160
|
-
const loadBase =
|
|
1205
|
+
const loadBase = React5.useCallback(async () => {
|
|
1161
1206
|
await load(baseRef.current, "base");
|
|
1162
1207
|
}, [load]);
|
|
1163
|
-
const loadTest =
|
|
1208
|
+
const loadTest = React5.useCallback(async (src) => {
|
|
1164
1209
|
await load(src, "test");
|
|
1165
1210
|
}, [load]);
|
|
1166
|
-
const restoreBase =
|
|
1211
|
+
const restoreBase = React5.useCallback(async () => {
|
|
1167
1212
|
const src = baseRef.current;
|
|
1168
1213
|
if (!src.appId) return;
|
|
1169
1214
|
await activateCachedBase(src.appId);
|
|
@@ -1171,7 +1216,7 @@ function useBundleManager({
|
|
|
1171
1216
|
await load(src, "base");
|
|
1172
1217
|
}
|
|
1173
1218
|
}, [activateCachedBase, load]);
|
|
1174
|
-
|
|
1219
|
+
React5.useEffect(() => {
|
|
1175
1220
|
if (!canRequestLatest) return;
|
|
1176
1221
|
void loadBase();
|
|
1177
1222
|
}, [base.appId, base.commitId, platform, canRequestLatest, loadBase]);
|
|
@@ -1179,7 +1224,7 @@ function useBundleManager({
|
|
|
1179
1224
|
}
|
|
1180
1225
|
|
|
1181
1226
|
// src/studio/hooks/useMergeRequests.ts
|
|
1182
|
-
import * as
|
|
1227
|
+
import * as React6 from "react";
|
|
1183
1228
|
|
|
1184
1229
|
// src/data/merge-requests/remote.ts
|
|
1185
1230
|
var MergeRequestsRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -1325,12 +1370,12 @@ function toUiStatus(status) {
|
|
|
1325
1370
|
}
|
|
1326
1371
|
function useMergeRequests(params) {
|
|
1327
1372
|
const { appId } = params;
|
|
1328
|
-
const [incoming, setIncoming] =
|
|
1329
|
-
const [outgoing, setOutgoing] =
|
|
1330
|
-
const [loading, setLoading] =
|
|
1331
|
-
const [error, setError] =
|
|
1332
|
-
const [creatorStatsById, setCreatorStatsById] =
|
|
1333
|
-
const pollUntilMerged =
|
|
1373
|
+
const [incoming, setIncoming] = React6.useState([]);
|
|
1374
|
+
const [outgoing, setOutgoing] = React6.useState([]);
|
|
1375
|
+
const [loading, setLoading] = React6.useState(false);
|
|
1376
|
+
const [error, setError] = React6.useState(null);
|
|
1377
|
+
const [creatorStatsById, setCreatorStatsById] = React6.useState({});
|
|
1378
|
+
const pollUntilMerged = React6.useCallback(async (mrId) => {
|
|
1334
1379
|
const startedAt = Date.now();
|
|
1335
1380
|
const timeoutMs = 2 * 60 * 1e3;
|
|
1336
1381
|
for (; ; ) {
|
|
@@ -1340,7 +1385,7 @@ function useMergeRequests(params) {
|
|
|
1340
1385
|
await new Promise((r) => setTimeout(r, 1500));
|
|
1341
1386
|
}
|
|
1342
1387
|
}, []);
|
|
1343
|
-
const refresh =
|
|
1388
|
+
const refresh = React6.useCallback(async () => {
|
|
1344
1389
|
if (!appId) {
|
|
1345
1390
|
setIncoming([]);
|
|
1346
1391
|
setOutgoing([]);
|
|
@@ -1379,27 +1424,27 @@ function useMergeRequests(params) {
|
|
|
1379
1424
|
setLoading(false);
|
|
1380
1425
|
}
|
|
1381
1426
|
}, [appId]);
|
|
1382
|
-
|
|
1427
|
+
React6.useEffect(() => {
|
|
1383
1428
|
void refresh();
|
|
1384
1429
|
}, [refresh]);
|
|
1385
|
-
const openMergeRequest =
|
|
1430
|
+
const openMergeRequest = React6.useCallback(async (sourceAppId) => {
|
|
1386
1431
|
const mr = await mergeRequestsRepository.open({ sourceAppId });
|
|
1387
1432
|
await refresh();
|
|
1388
1433
|
return mr;
|
|
1389
1434
|
}, [refresh]);
|
|
1390
|
-
const approve =
|
|
1435
|
+
const approve = React6.useCallback(async (mrId) => {
|
|
1391
1436
|
const mr = await mergeRequestsRepository.update(mrId, { status: "approved" });
|
|
1392
1437
|
await refresh();
|
|
1393
1438
|
const merged = await pollUntilMerged(mrId);
|
|
1394
1439
|
await refresh();
|
|
1395
1440
|
return merged ?? mr;
|
|
1396
1441
|
}, [pollUntilMerged, refresh]);
|
|
1397
|
-
const reject =
|
|
1442
|
+
const reject = React6.useCallback(async (mrId) => {
|
|
1398
1443
|
const mr = await mergeRequestsRepository.update(mrId, { status: "rejected" });
|
|
1399
1444
|
await refresh();
|
|
1400
1445
|
return mr;
|
|
1401
1446
|
}, [refresh]);
|
|
1402
|
-
const toSummary =
|
|
1447
|
+
const toSummary = React6.useCallback((mr) => {
|
|
1403
1448
|
const stats = creatorStatsById[mr.createdBy];
|
|
1404
1449
|
return {
|
|
1405
1450
|
id: mr.id,
|
|
@@ -1415,7 +1460,7 @@ function useMergeRequests(params) {
|
|
|
1415
1460
|
updatedAt: mr.updatedAt
|
|
1416
1461
|
};
|
|
1417
1462
|
}, [creatorStatsById]);
|
|
1418
|
-
const byId =
|
|
1463
|
+
const byId = React6.useMemo(() => {
|
|
1419
1464
|
const all = [...incoming, ...outgoing];
|
|
1420
1465
|
const map = {};
|
|
1421
1466
|
for (const mr of all) map[mr.id] = mr;
|
|
@@ -1433,7 +1478,7 @@ function useMergeRequests(params) {
|
|
|
1433
1478
|
}
|
|
1434
1479
|
|
|
1435
1480
|
// src/studio/hooks/useAttachmentUpload.ts
|
|
1436
|
-
import * as
|
|
1481
|
+
import * as React7 from "react";
|
|
1437
1482
|
|
|
1438
1483
|
// src/data/attachment/remote.ts
|
|
1439
1484
|
var AttachmentRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -1474,9 +1519,9 @@ var attachmentRepository = new AttachmentRepositoryImpl(
|
|
|
1474
1519
|
|
|
1475
1520
|
// src/studio/hooks/useAttachmentUpload.ts
|
|
1476
1521
|
function useAttachmentUpload() {
|
|
1477
|
-
const [uploading, setUploading] =
|
|
1478
|
-
const [error, setError] =
|
|
1479
|
-
const uploadBase64Images =
|
|
1522
|
+
const [uploading, setUploading] = React7.useState(false);
|
|
1523
|
+
const [error, setError] = React7.useState(null);
|
|
1524
|
+
const uploadBase64Images = React7.useCallback(async ({ threadId, appId, dataUrls }) => {
|
|
1480
1525
|
if (!threadId || !appId) return [];
|
|
1481
1526
|
if (!dataUrls || dataUrls.length === 0) return [];
|
|
1482
1527
|
setUploading(true);
|
|
@@ -1510,7 +1555,7 @@ function useAttachmentUpload() {
|
|
|
1510
1555
|
}
|
|
1511
1556
|
|
|
1512
1557
|
// src/studio/hooks/useStudioActions.ts
|
|
1513
|
-
import * as
|
|
1558
|
+
import * as React8 from "react";
|
|
1514
1559
|
|
|
1515
1560
|
// src/data/agent/remote.ts
|
|
1516
1561
|
var AgentRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -1549,12 +1594,12 @@ function useStudioActions({
|
|
|
1549
1594
|
onForkedApp,
|
|
1550
1595
|
uploadAttachments
|
|
1551
1596
|
}) {
|
|
1552
|
-
const [forking, setForking] =
|
|
1553
|
-
const [sending, setSending] =
|
|
1554
|
-
const [error, setError] =
|
|
1597
|
+
const [forking, setForking] = React8.useState(false);
|
|
1598
|
+
const [sending, setSending] = React8.useState(false);
|
|
1599
|
+
const [error, setError] = React8.useState(null);
|
|
1555
1600
|
const isOwner = Boolean(userId && (app == null ? void 0 : app.createdBy) && userId === app.createdBy);
|
|
1556
1601
|
const shouldForkOnEdit = Boolean(userId && app && app.createdBy !== userId);
|
|
1557
|
-
const sendEdit =
|
|
1602
|
+
const sendEdit = React8.useCallback(
|
|
1558
1603
|
async ({ prompt, attachments }) => {
|
|
1559
1604
|
if (!userId || !app) return;
|
|
1560
1605
|
if (!prompt.trim()) return;
|
|
@@ -1636,12 +1681,12 @@ function RuntimeRenderer({ appKey, bundlePath, renderToken, style }) {
|
|
|
1636
1681
|
}
|
|
1637
1682
|
|
|
1638
1683
|
// src/studio/ui/StudioOverlay.tsx
|
|
1639
|
-
import * as
|
|
1640
|
-
import { Keyboard as Keyboard5, Platform as
|
|
1684
|
+
import * as React38 from "react";
|
|
1685
|
+
import { Keyboard as Keyboard5, Platform as Platform8, View as View44, useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
1641
1686
|
|
|
1642
1687
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
1643
|
-
import * as
|
|
1644
|
-
import {
|
|
1688
|
+
import * as React9 from "react";
|
|
1689
|
+
import { AppState as AppState2, Keyboard, View as View4 } from "react-native";
|
|
1645
1690
|
import BottomSheet from "@gorhom/bottom-sheet";
|
|
1646
1691
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
1647
1692
|
|
|
@@ -1708,19 +1753,31 @@ function StudioBottomSheet({
|
|
|
1708
1753
|
}) {
|
|
1709
1754
|
const theme = useTheme();
|
|
1710
1755
|
const insets = useSafeAreaInsets();
|
|
1711
|
-
const internalSheetRef =
|
|
1756
|
+
const internalSheetRef = React9.useRef(null);
|
|
1712
1757
|
const resolvedSheetRef = sheetRef ?? internalSheetRef;
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1758
|
+
const currentIndexRef = React9.useRef(open ? snapPoints.length - 1 : -1);
|
|
1759
|
+
const lastAppStateRef = React9.useRef(AppState2.currentState);
|
|
1760
|
+
React9.useEffect(() => {
|
|
1761
|
+
const sub = AppState2.addEventListener("change", (state) => {
|
|
1762
|
+
const prev = lastAppStateRef.current;
|
|
1763
|
+
lastAppStateRef.current = state;
|
|
1764
|
+
if (state === "background" || state === "inactive") {
|
|
1765
|
+
Keyboard.dismiss();
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
if (state !== "active") return;
|
|
1716
1769
|
const sheet = resolvedSheetRef.current;
|
|
1717
|
-
if (!sheet
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1770
|
+
if (!sheet) return;
|
|
1771
|
+
const idx = currentIndexRef.current;
|
|
1772
|
+
if (open && idx >= 0) {
|
|
1773
|
+
Keyboard.dismiss();
|
|
1774
|
+
requestAnimationFrame(() => sheet.snapToIndex(idx));
|
|
1775
|
+
setTimeout(() => sheet.snapToIndex(idx), 120);
|
|
1776
|
+
}
|
|
1720
1777
|
});
|
|
1721
1778
|
return () => sub.remove();
|
|
1722
|
-
}, [open, resolvedSheetRef
|
|
1723
|
-
|
|
1779
|
+
}, [open, resolvedSheetRef]);
|
|
1780
|
+
React9.useEffect(() => {
|
|
1724
1781
|
const sheet = resolvedSheetRef.current;
|
|
1725
1782
|
if (!sheet) return;
|
|
1726
1783
|
if (open) {
|
|
@@ -1729,8 +1786,9 @@ function StudioBottomSheet({
|
|
|
1729
1786
|
sheet.close();
|
|
1730
1787
|
}
|
|
1731
1788
|
}, [open, resolvedSheetRef, snapPoints.length]);
|
|
1732
|
-
const handleChange =
|
|
1789
|
+
const handleChange = React9.useCallback(
|
|
1733
1790
|
(index) => {
|
|
1791
|
+
currentIndexRef.current = index;
|
|
1734
1792
|
onOpenChange == null ? void 0 : onOpenChange(index >= 0);
|
|
1735
1793
|
},
|
|
1736
1794
|
[onOpenChange]
|
|
@@ -1742,7 +1800,7 @@ function StudioBottomSheet({
|
|
|
1742
1800
|
index: open ? snapPoints.length - 1 : -1,
|
|
1743
1801
|
snapPoints,
|
|
1744
1802
|
enablePanDownToClose: true,
|
|
1745
|
-
keyboardBehavior: "
|
|
1803
|
+
keyboardBehavior: "interactive",
|
|
1746
1804
|
keyboardBlurBehavior: "restore",
|
|
1747
1805
|
android_keyboardInputMode: "adjustResize",
|
|
1748
1806
|
backgroundComponent: (props) => /* @__PURE__ */ jsx5(StudioSheetBackground, { ...props, renderBackground: background == null ? void 0 : background.renderBackground }),
|
|
@@ -1757,12 +1815,12 @@ function StudioBottomSheet({
|
|
|
1757
1815
|
}
|
|
1758
1816
|
|
|
1759
1817
|
// src/components/studio-sheet/StudioSheetPager.tsx
|
|
1760
|
-
import * as
|
|
1818
|
+
import * as React10 from "react";
|
|
1761
1819
|
import { Animated } from "react-native";
|
|
1762
1820
|
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1763
1821
|
function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
1764
|
-
const anim =
|
|
1765
|
-
|
|
1822
|
+
const anim = React10.useRef(new Animated.Value(activePage === "chat" ? 1 : 0)).current;
|
|
1823
|
+
React10.useEffect(() => {
|
|
1766
1824
|
Animated.spring(anim, {
|
|
1767
1825
|
toValue: activePage === "chat" ? 1 : 0,
|
|
1768
1826
|
useNativeDriver: true,
|
|
@@ -1811,7 +1869,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
|
1811
1869
|
}
|
|
1812
1870
|
|
|
1813
1871
|
// src/components/floating-draggable-button/FloatingDraggableButton.tsx
|
|
1814
|
-
import { useCallback as useCallback8, useEffect as
|
|
1872
|
+
import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef6 } from "react";
|
|
1815
1873
|
import {
|
|
1816
1874
|
PanResponder,
|
|
1817
1875
|
Pressable,
|
|
@@ -1890,8 +1948,8 @@ function FloatingDraggableButton({
|
|
|
1890
1948
|
const theme = useTheme();
|
|
1891
1949
|
const { width, height } = useWindowDimensions();
|
|
1892
1950
|
const isDanger = variant === "danger";
|
|
1893
|
-
const onPressRef =
|
|
1894
|
-
|
|
1951
|
+
const onPressRef = useRef6(onPress);
|
|
1952
|
+
useEffect9(() => {
|
|
1895
1953
|
onPressRef.current = onPress;
|
|
1896
1954
|
}, [onPress]);
|
|
1897
1955
|
const fallbackBgColor = useMemo3(() => {
|
|
@@ -1905,8 +1963,8 @@ function FloatingDraggableButton({
|
|
|
1905
1963
|
const rotation = useSharedValue(ENTER_ROTATION_FROM_DEG);
|
|
1906
1964
|
const opacity = useSharedValue(1);
|
|
1907
1965
|
const borderPulse = useSharedValue(0);
|
|
1908
|
-
const startPos =
|
|
1909
|
-
const isAnimatingOut =
|
|
1966
|
+
const startPos = useRef6({ x: 0, y: 0 });
|
|
1967
|
+
const isAnimatingOut = useRef6(false);
|
|
1910
1968
|
const animateToHidden = useCallback8(
|
|
1911
1969
|
(options) => {
|
|
1912
1970
|
translateX.value = withSpring(getHiddenTranslateX(size), SPRING_POSITION);
|
|
@@ -1942,7 +2000,7 @@ function FloatingDraggableButton({
|
|
|
1942
2000
|
}
|
|
1943
2001
|
});
|
|
1944
2002
|
}, [animateToHidden]);
|
|
1945
|
-
|
|
2003
|
+
useEffect9(() => {
|
|
1946
2004
|
if (isLoading) {
|
|
1947
2005
|
borderPulse.value = withRepeat(
|
|
1948
2006
|
withSequence(
|
|
@@ -1968,7 +2026,7 @@ function FloatingDraggableButton({
|
|
|
1968
2026
|
rotation.value = withSpring(0, SPRING_ROTATION_IN);
|
|
1969
2027
|
opacity.value = withTiming(1, TIMING_OPACITY_IN);
|
|
1970
2028
|
}, [height, offset.bottom, offset.left, opacity, rotation, scale, size, translateX, translateY]);
|
|
1971
|
-
|
|
2029
|
+
useEffect9(() => {
|
|
1972
2030
|
const timer = setTimeout(() => {
|
|
1973
2031
|
if (visible) {
|
|
1974
2032
|
animateIn();
|
|
@@ -1976,7 +2034,7 @@ function FloatingDraggableButton({
|
|
|
1976
2034
|
}, 100);
|
|
1977
2035
|
return () => clearTimeout(timer);
|
|
1978
2036
|
}, []);
|
|
1979
|
-
|
|
2037
|
+
useEffect9(() => {
|
|
1980
2038
|
if (visible && isAnimatingOut.current) {
|
|
1981
2039
|
animateIn();
|
|
1982
2040
|
} else if (!visible && !isAnimatingOut.current) {
|
|
@@ -1984,13 +2042,13 @@ function FloatingDraggableButton({
|
|
|
1984
2042
|
isAnimatingOut.current = true;
|
|
1985
2043
|
}
|
|
1986
2044
|
}, [visible, animateIn, animateToHidden]);
|
|
1987
|
-
|
|
2045
|
+
useEffect9(() => {
|
|
1988
2046
|
if (forceShowTrigger > 0 && visible) {
|
|
1989
2047
|
isAnimatingOut.current = false;
|
|
1990
2048
|
animateIn();
|
|
1991
2049
|
}
|
|
1992
2050
|
}, [forceShowTrigger, visible, animateIn]);
|
|
1993
|
-
const panResponder =
|
|
2051
|
+
const panResponder = useRef6(
|
|
1994
2052
|
PanResponder.create({
|
|
1995
2053
|
onStartShouldSetPanResponder: () => true,
|
|
1996
2054
|
onMoveShouldSetPanResponder: () => true,
|
|
@@ -2107,7 +2165,7 @@ var styles = StyleSheet.create({
|
|
|
2107
2165
|
});
|
|
2108
2166
|
|
|
2109
2167
|
// src/components/overlays/EdgeGlowFrame.tsx
|
|
2110
|
-
import * as
|
|
2168
|
+
import * as React11 from "react";
|
|
2111
2169
|
import { Animated as Animated3, View as View6 } from "react-native";
|
|
2112
2170
|
import { LinearGradient } from "expo-linear-gradient";
|
|
2113
2171
|
|
|
@@ -2150,8 +2208,8 @@ function EdgeGlowFrame({
|
|
|
2150
2208
|
}) {
|
|
2151
2209
|
const theme = useTheme();
|
|
2152
2210
|
const alpha = Math.max(0, Math.min(1, intensity));
|
|
2153
|
-
const anim =
|
|
2154
|
-
|
|
2211
|
+
const anim = React11.useRef(new Animated3.Value(visible ? 1 : 0)).current;
|
|
2212
|
+
React11.useEffect(() => {
|
|
2155
2213
|
Animated3.timing(anim, {
|
|
2156
2214
|
toValue: visible ? 1 : 0,
|
|
2157
2215
|
duration: 300,
|
|
@@ -2202,12 +2260,12 @@ function EdgeGlowFrame({
|
|
|
2202
2260
|
}
|
|
2203
2261
|
|
|
2204
2262
|
// src/components/draw/DrawModeOverlay.tsx
|
|
2205
|
-
import * as
|
|
2263
|
+
import * as React14 from "react";
|
|
2206
2264
|
import { StyleSheet as StyleSheet3, View as View10 } from "react-native";
|
|
2207
2265
|
import { captureRef } from "react-native-view-shot";
|
|
2208
2266
|
|
|
2209
2267
|
// src/components/draw/DrawSurface.tsx
|
|
2210
|
-
import * as
|
|
2268
|
+
import * as React12 from "react";
|
|
2211
2269
|
import { PanResponder as PanResponder2, StyleSheet as StyleSheet2, View as View7 } from "react-native";
|
|
2212
2270
|
import Svg, { Path } from "react-native-svg";
|
|
2213
2271
|
|
|
@@ -2239,25 +2297,25 @@ function DrawSurface({
|
|
|
2239
2297
|
style,
|
|
2240
2298
|
minDistance = 1
|
|
2241
2299
|
}) {
|
|
2242
|
-
const [renderTick, setRenderTick] =
|
|
2243
|
-
const currentPointsRef =
|
|
2244
|
-
const rafRef =
|
|
2245
|
-
const triggerRender =
|
|
2300
|
+
const [renderTick, setRenderTick] = React12.useState(0);
|
|
2301
|
+
const currentPointsRef = React12.useRef([]);
|
|
2302
|
+
const rafRef = React12.useRef(null);
|
|
2303
|
+
const triggerRender = React12.useCallback(() => {
|
|
2246
2304
|
if (rafRef.current !== null) return;
|
|
2247
2305
|
rafRef.current = requestAnimationFrame(() => {
|
|
2248
2306
|
rafRef.current = null;
|
|
2249
2307
|
setRenderTick((n) => n + 1);
|
|
2250
2308
|
});
|
|
2251
2309
|
}, []);
|
|
2252
|
-
|
|
2310
|
+
React12.useEffect(() => () => {
|
|
2253
2311
|
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
|
2254
2312
|
}, []);
|
|
2255
|
-
const onStart =
|
|
2313
|
+
const onStart = React12.useCallback((e) => {
|
|
2256
2314
|
const { locationX, locationY } = e.nativeEvent;
|
|
2257
2315
|
currentPointsRef.current = [{ x: locationX, y: locationY }];
|
|
2258
2316
|
triggerRender();
|
|
2259
2317
|
}, [triggerRender]);
|
|
2260
|
-
const onMove =
|
|
2318
|
+
const onMove = React12.useCallback((e, _g) => {
|
|
2261
2319
|
const { locationX, locationY } = e.nativeEvent;
|
|
2262
2320
|
const pts = currentPointsRef.current;
|
|
2263
2321
|
if (pts.length > 0) {
|
|
@@ -2270,7 +2328,7 @@ function DrawSurface({
|
|
|
2270
2328
|
currentPointsRef.current = [...pts, { x: locationX, y: locationY }];
|
|
2271
2329
|
triggerRender();
|
|
2272
2330
|
}, [minDistance, triggerRender]);
|
|
2273
|
-
const onEnd =
|
|
2331
|
+
const onEnd = React12.useCallback(() => {
|
|
2274
2332
|
const points = currentPointsRef.current;
|
|
2275
2333
|
if (points.length > 0) {
|
|
2276
2334
|
onAddStroke({ points, color, width: strokeWidth });
|
|
@@ -2278,7 +2336,7 @@ function DrawSurface({
|
|
|
2278
2336
|
currentPointsRef.current = [];
|
|
2279
2337
|
triggerRender();
|
|
2280
2338
|
}, [color, onAddStroke, strokeWidth, triggerRender]);
|
|
2281
|
-
const panResponder =
|
|
2339
|
+
const panResponder = React12.useMemo(
|
|
2282
2340
|
() => PanResponder2.create({
|
|
2283
2341
|
onStartShouldSetPanResponder: () => true,
|
|
2284
2342
|
onMoveShouldSetPanResponder: () => true,
|
|
@@ -2328,7 +2386,7 @@ var styles2 = StyleSheet2.create({
|
|
|
2328
2386
|
});
|
|
2329
2387
|
|
|
2330
2388
|
// src/components/draw/DrawToolbar.tsx
|
|
2331
|
-
import * as
|
|
2389
|
+
import * as React13 from "react";
|
|
2332
2390
|
import {
|
|
2333
2391
|
ActivityIndicator,
|
|
2334
2392
|
Animated as Animated4,
|
|
@@ -2425,11 +2483,11 @@ function DrawToolbar({
|
|
|
2425
2483
|
}) {
|
|
2426
2484
|
const insets = useSafeAreaInsets2();
|
|
2427
2485
|
const { width: screenWidth, height: screenHeight } = useWindowDimensions2();
|
|
2428
|
-
const [expanded, setExpanded] =
|
|
2429
|
-
const pos =
|
|
2430
|
-
const start =
|
|
2431
|
-
const currentPos =
|
|
2432
|
-
|
|
2486
|
+
const [expanded, setExpanded] = React13.useState(false);
|
|
2487
|
+
const pos = React13.useRef(new Animated4.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
|
|
2488
|
+
const start = React13.useRef({ x: 0, y: 0 });
|
|
2489
|
+
const currentPos = React13.useRef({ x: 0, y: 0 });
|
|
2490
|
+
React13.useEffect(() => {
|
|
2433
2491
|
if (hidden) return;
|
|
2434
2492
|
Animated4.spring(pos.y, {
|
|
2435
2493
|
toValue: insets.top + 60,
|
|
@@ -2439,7 +2497,7 @@ function DrawToolbar({
|
|
|
2439
2497
|
mass: 0.8
|
|
2440
2498
|
}).start();
|
|
2441
2499
|
}, [hidden, insets.top, pos.y]);
|
|
2442
|
-
|
|
2500
|
+
React13.useEffect(() => {
|
|
2443
2501
|
const id = pos.addListener((v) => {
|
|
2444
2502
|
currentPos.current = { x: v.x ?? 0, y: v.y ?? 0 };
|
|
2445
2503
|
});
|
|
@@ -2447,7 +2505,7 @@ function DrawToolbar({
|
|
|
2447
2505
|
pos.removeListener(id);
|
|
2448
2506
|
};
|
|
2449
2507
|
}, [pos]);
|
|
2450
|
-
const clamp2 =
|
|
2508
|
+
const clamp2 = React13.useCallback(
|
|
2451
2509
|
(x, y) => {
|
|
2452
2510
|
const minX = 10;
|
|
2453
2511
|
const maxX = Math.max(10, screenWidth - 230);
|
|
@@ -2457,7 +2515,7 @@ function DrawToolbar({
|
|
|
2457
2515
|
},
|
|
2458
2516
|
[insets.top, screenHeight, screenWidth]
|
|
2459
2517
|
);
|
|
2460
|
-
const panResponder =
|
|
2518
|
+
const panResponder = React13.useMemo(
|
|
2461
2519
|
() => PanResponder3.create({
|
|
2462
2520
|
onStartShouldSetPanResponder: () => false,
|
|
2463
2521
|
onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 5 || Math.abs(g.dy) > 5,
|
|
@@ -2485,7 +2543,7 @@ function DrawToolbar({
|
|
|
2485
2543
|
children
|
|
2486
2544
|
}) {
|
|
2487
2545
|
const isDisabled = Boolean(disabled) || Boolean(capturingDisabled);
|
|
2488
|
-
const [pressed, setPressed] =
|
|
2546
|
+
const [pressed, setPressed] = React13.useState(false);
|
|
2489
2547
|
return /* @__PURE__ */ jsx11(
|
|
2490
2548
|
View9,
|
|
2491
2549
|
{
|
|
@@ -2623,7 +2681,7 @@ function DrawModeOverlay({
|
|
|
2623
2681
|
renderDragHandle
|
|
2624
2682
|
}) {
|
|
2625
2683
|
const theme = useTheme();
|
|
2626
|
-
const defaultPalette =
|
|
2684
|
+
const defaultPalette = React14.useMemo(
|
|
2627
2685
|
() => [
|
|
2628
2686
|
"#EF4444",
|
|
2629
2687
|
// Red
|
|
@@ -2641,11 +2699,11 @@ function DrawModeOverlay({
|
|
|
2641
2699
|
[]
|
|
2642
2700
|
);
|
|
2643
2701
|
const colors = palette && palette.length > 0 ? palette : defaultPalette;
|
|
2644
|
-
const [selectedColor, setSelectedColor] =
|
|
2645
|
-
const [strokes, setStrokes] =
|
|
2646
|
-
const [capturing, setCapturing] =
|
|
2647
|
-
const [hideUi, setHideUi] =
|
|
2648
|
-
|
|
2702
|
+
const [selectedColor, setSelectedColor] = React14.useState(colors[0] ?? "#EF4444");
|
|
2703
|
+
const [strokes, setStrokes] = React14.useState([]);
|
|
2704
|
+
const [capturing, setCapturing] = React14.useState(false);
|
|
2705
|
+
const [hideUi, setHideUi] = React14.useState(false);
|
|
2706
|
+
React14.useEffect(() => {
|
|
2649
2707
|
if (!visible) return;
|
|
2650
2708
|
setStrokes([]);
|
|
2651
2709
|
setSelectedColor(colors[0] ?? "#EF4444");
|
|
@@ -2653,14 +2711,14 @@ function DrawModeOverlay({
|
|
|
2653
2711
|
setHideUi(false);
|
|
2654
2712
|
}, [colors, visible]);
|
|
2655
2713
|
const canUndo = strokes.length > 0;
|
|
2656
|
-
const handleUndo =
|
|
2714
|
+
const handleUndo = React14.useCallback(() => {
|
|
2657
2715
|
setStrokes((prev) => prev.slice(0, -1));
|
|
2658
2716
|
}, []);
|
|
2659
|
-
const handleCancel =
|
|
2717
|
+
const handleCancel = React14.useCallback(() => {
|
|
2660
2718
|
setStrokes([]);
|
|
2661
2719
|
onCancel();
|
|
2662
2720
|
}, [onCancel]);
|
|
2663
|
-
const handleDone =
|
|
2721
|
+
const handleDone = React14.useCallback(async () => {
|
|
2664
2722
|
if (!captureTargetRef.current || capturing) return;
|
|
2665
2723
|
try {
|
|
2666
2724
|
setCapturing(true);
|
|
@@ -2720,7 +2778,7 @@ var styles3 = StyleSheet3.create({
|
|
|
2720
2778
|
});
|
|
2721
2779
|
|
|
2722
2780
|
// src/components/comments/AppCommentsSheet.tsx
|
|
2723
|
-
import * as
|
|
2781
|
+
import * as React21 from "react";
|
|
2724
2782
|
import { ActivityIndicator as ActivityIndicator3, Keyboard as Keyboard3, Platform as Platform4, Pressable as Pressable5, View as View14 } from "react-native";
|
|
2725
2783
|
import {
|
|
2726
2784
|
BottomSheetBackdrop,
|
|
@@ -2732,7 +2790,7 @@ import { LiquidGlassView as LiquidGlassView4, isLiquidGlassSupported as isLiquid
|
|
|
2732
2790
|
import { Play as Play2 } from "lucide-react-native";
|
|
2733
2791
|
|
|
2734
2792
|
// src/components/chat/ChatComposer.tsx
|
|
2735
|
-
import * as
|
|
2793
|
+
import * as React16 from "react";
|
|
2736
2794
|
import {
|
|
2737
2795
|
ActivityIndicator as ActivityIndicator2,
|
|
2738
2796
|
Animated as Animated5,
|
|
@@ -2746,11 +2804,11 @@ import { LiquidGlassView as LiquidGlassView3, isLiquidGlassSupported as isLiquid
|
|
|
2746
2804
|
import { Plus } from "lucide-react-native";
|
|
2747
2805
|
|
|
2748
2806
|
// src/components/chat/MultilineTextInput.tsx
|
|
2749
|
-
import * as
|
|
2807
|
+
import * as React15 from "react";
|
|
2750
2808
|
import { TextInput } from "react-native";
|
|
2751
2809
|
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
|
2752
2810
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
2753
|
-
var MultilineTextInput =
|
|
2811
|
+
var MultilineTextInput = React15.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
|
|
2754
2812
|
const theme = useTheme();
|
|
2755
2813
|
const baseStyle = {
|
|
2756
2814
|
minHeight: 44,
|
|
@@ -2834,7 +2892,7 @@ function AspectRatioThumbnail({
|
|
|
2834
2892
|
onRemove,
|
|
2835
2893
|
renderRemoveIcon
|
|
2836
2894
|
}) {
|
|
2837
|
-
const [aspectRatio, setAspectRatio] =
|
|
2895
|
+
const [aspectRatio, setAspectRatio] = React16.useState(1);
|
|
2838
2896
|
return /* @__PURE__ */ jsxs8(View11, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
|
|
2839
2897
|
/* @__PURE__ */ jsx15(View11, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx15(
|
|
2840
2898
|
Image,
|
|
@@ -2876,6 +2934,7 @@ function ChatComposer({
|
|
|
2876
2934
|
onChangeValue,
|
|
2877
2935
|
placeholder = "Describe the idea you want to build",
|
|
2878
2936
|
disabled = false,
|
|
2937
|
+
sendDisabled = false,
|
|
2879
2938
|
sending = false,
|
|
2880
2939
|
autoFocus = false,
|
|
2881
2940
|
onSend,
|
|
@@ -2890,19 +2949,19 @@ function ChatComposer({
|
|
|
2890
2949
|
style
|
|
2891
2950
|
}) {
|
|
2892
2951
|
const theme = useTheme();
|
|
2893
|
-
const [internal, setInternal] =
|
|
2952
|
+
const [internal, setInternal] = React16.useState("");
|
|
2894
2953
|
const text = value ?? internal;
|
|
2895
2954
|
const setText = onChangeValue ?? setInternal;
|
|
2896
2955
|
const hasAttachments = attachments.length > 0;
|
|
2897
2956
|
const hasText = text.trim().length > 0;
|
|
2898
2957
|
const composerMinHeight = hasAttachments ? THUMBNAIL_HEIGHT + 44 + 24 : 44;
|
|
2899
|
-
const isButtonDisabled = sending || disabled;
|
|
2900
|
-
const maxInputHeight =
|
|
2901
|
-
const shakeAnim =
|
|
2902
|
-
const [sendPressed, setSendPressed] =
|
|
2903
|
-
const inputRef =
|
|
2904
|
-
const prevAutoFocusRef =
|
|
2905
|
-
|
|
2958
|
+
const isButtonDisabled = sending || disabled || sendDisabled;
|
|
2959
|
+
const maxInputHeight = React16.useMemo(() => Dimensions.get("window").height * 0.5, []);
|
|
2960
|
+
const shakeAnim = React16.useRef(new Animated5.Value(0)).current;
|
|
2961
|
+
const [sendPressed, setSendPressed] = React16.useState(false);
|
|
2962
|
+
const inputRef = React16.useRef(null);
|
|
2963
|
+
const prevAutoFocusRef = React16.useRef(false);
|
|
2964
|
+
React16.useEffect(() => {
|
|
2906
2965
|
const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
|
|
2907
2966
|
prevAutoFocusRef.current = autoFocus;
|
|
2908
2967
|
if (!shouldFocus) return;
|
|
@@ -2912,7 +2971,7 @@ function ChatComposer({
|
|
|
2912
2971
|
}, 75);
|
|
2913
2972
|
return () => clearTimeout(t);
|
|
2914
2973
|
}, [autoFocus, disabled, sending]);
|
|
2915
|
-
const triggerShake =
|
|
2974
|
+
const triggerShake = React16.useCallback(() => {
|
|
2916
2975
|
shakeAnim.setValue(0);
|
|
2917
2976
|
Animated5.sequence([
|
|
2918
2977
|
Animated5.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
|
|
@@ -2922,7 +2981,7 @@ function ChatComposer({
|
|
|
2922
2981
|
Animated5.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
|
|
2923
2982
|
]).start();
|
|
2924
2983
|
}, [shakeAnim]);
|
|
2925
|
-
const handleSend =
|
|
2984
|
+
const handleSend = React16.useCallback(async () => {
|
|
2926
2985
|
if (isButtonDisabled) return;
|
|
2927
2986
|
if (!hasText) {
|
|
2928
2987
|
triggerShake();
|
|
@@ -3055,7 +3114,7 @@ function ChatComposer({
|
|
|
3055
3114
|
}
|
|
3056
3115
|
|
|
3057
3116
|
// src/components/comments/CommentRow.tsx
|
|
3058
|
-
import * as
|
|
3117
|
+
import * as React17 from "react";
|
|
3059
3118
|
import { View as View13 } from "react-native";
|
|
3060
3119
|
|
|
3061
3120
|
// src/components/primitives/Avatar.tsx
|
|
@@ -3127,9 +3186,9 @@ function formatTimeAgo(iso) {
|
|
|
3127
3186
|
import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3128
3187
|
function CommentRow({ comment, showDivider }) {
|
|
3129
3188
|
const theme = useTheme();
|
|
3130
|
-
const [authorName, setAuthorName] =
|
|
3131
|
-
const [authorAvatar, setAuthorAvatar] =
|
|
3132
|
-
|
|
3189
|
+
const [authorName, setAuthorName] = React17.useState(null);
|
|
3190
|
+
const [authorAvatar, setAuthorAvatar] = React17.useState(null);
|
|
3191
|
+
React17.useEffect(() => {
|
|
3133
3192
|
let cancelled = false;
|
|
3134
3193
|
(async () => {
|
|
3135
3194
|
try {
|
|
@@ -3169,7 +3228,7 @@ function CommentRow({ comment, showDivider }) {
|
|
|
3169
3228
|
}
|
|
3170
3229
|
|
|
3171
3230
|
// src/components/comments/useAppComments.ts
|
|
3172
|
-
import * as
|
|
3231
|
+
import * as React18 from "react";
|
|
3173
3232
|
|
|
3174
3233
|
// src/data/comments/remote.ts
|
|
3175
3234
|
var AppCommentsRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -3241,18 +3300,18 @@ var appCommentsRepository = new AppCommentsRepositoryImpl(appCommentsRemoteDataS
|
|
|
3241
3300
|
|
|
3242
3301
|
// src/components/comments/useAppComments.ts
|
|
3243
3302
|
function useAppComments(appId) {
|
|
3244
|
-
const [comments, setComments] =
|
|
3245
|
-
const [loading, setLoading] =
|
|
3246
|
-
const [sending, setSending] =
|
|
3247
|
-
const [error, setError] =
|
|
3248
|
-
const sortByCreatedAtAsc =
|
|
3303
|
+
const [comments, setComments] = React18.useState([]);
|
|
3304
|
+
const [loading, setLoading] = React18.useState(false);
|
|
3305
|
+
const [sending, setSending] = React18.useState(false);
|
|
3306
|
+
const [error, setError] = React18.useState(null);
|
|
3307
|
+
const sortByCreatedAtAsc = React18.useCallback((items) => {
|
|
3249
3308
|
return [...items].sort((a, b) => {
|
|
3250
3309
|
const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
3251
3310
|
const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
3252
3311
|
return at - bt;
|
|
3253
3312
|
});
|
|
3254
3313
|
}, []);
|
|
3255
|
-
const refresh =
|
|
3314
|
+
const refresh = React18.useCallback(async () => {
|
|
3256
3315
|
if (!appId) {
|
|
3257
3316
|
setComments([]);
|
|
3258
3317
|
return;
|
|
@@ -3269,10 +3328,10 @@ function useAppComments(appId) {
|
|
|
3269
3328
|
setLoading(false);
|
|
3270
3329
|
}
|
|
3271
3330
|
}, [appId, sortByCreatedAtAsc]);
|
|
3272
|
-
|
|
3331
|
+
React18.useEffect(() => {
|
|
3273
3332
|
void refresh();
|
|
3274
3333
|
}, [refresh]);
|
|
3275
|
-
const create =
|
|
3334
|
+
const create = React18.useCallback(
|
|
3276
3335
|
async (text) => {
|
|
3277
3336
|
if (!appId) return;
|
|
3278
3337
|
const trimmed = text.trim();
|
|
@@ -3295,11 +3354,11 @@ function useAppComments(appId) {
|
|
|
3295
3354
|
}
|
|
3296
3355
|
|
|
3297
3356
|
// src/components/comments/useAppDetails.ts
|
|
3298
|
-
import * as
|
|
3357
|
+
import * as React19 from "react";
|
|
3299
3358
|
function useAppDetails(appId) {
|
|
3300
|
-
const [app, setApp] =
|
|
3301
|
-
const [loading, setLoading] =
|
|
3302
|
-
|
|
3359
|
+
const [app, setApp] = React19.useState(null);
|
|
3360
|
+
const [loading, setLoading] = React19.useState(false);
|
|
3361
|
+
React19.useEffect(() => {
|
|
3303
3362
|
if (!appId) {
|
|
3304
3363
|
setApp(null);
|
|
3305
3364
|
return;
|
|
@@ -3324,25 +3383,30 @@ function useAppDetails(appId) {
|
|
|
3324
3383
|
}
|
|
3325
3384
|
|
|
3326
3385
|
// src/components/comments/useIosKeyboardSnapFix.ts
|
|
3327
|
-
import * as
|
|
3386
|
+
import * as React20 from "react";
|
|
3328
3387
|
import { Keyboard as Keyboard2, Platform as Platform3 } from "react-native";
|
|
3329
|
-
function useIosKeyboardSnapFix(sheetRef) {
|
|
3330
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
3331
|
-
|
|
3388
|
+
function useIosKeyboardSnapFix(sheetRef, options) {
|
|
3389
|
+
const [keyboardVisible, setKeyboardVisible] = React20.useState(false);
|
|
3390
|
+
React20.useEffect(() => {
|
|
3332
3391
|
if (Platform3.OS !== "ios") return;
|
|
3333
3392
|
const show = Keyboard2.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
3334
3393
|
const hide = Keyboard2.addListener("keyboardWillHide", () => {
|
|
3394
|
+
var _a;
|
|
3335
3395
|
setKeyboardVisible(false);
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3396
|
+
const target = (options == null ? void 0 : options.targetIndex) ?? 1;
|
|
3397
|
+
const current = ((_a = options == null ? void 0 : options.getCurrentIndex) == null ? void 0 : _a.call(options)) ?? null;
|
|
3398
|
+
if (current === target) {
|
|
3399
|
+
setTimeout(() => {
|
|
3400
|
+
var _a2, _b;
|
|
3401
|
+
return (_b = (_a2 = sheetRef.current) == null ? void 0 : _a2.snapToIndex) == null ? void 0 : _b.call(_a2, target);
|
|
3402
|
+
}, 10);
|
|
3403
|
+
}
|
|
3340
3404
|
});
|
|
3341
3405
|
return () => {
|
|
3342
3406
|
show.remove();
|
|
3343
3407
|
hide.remove();
|
|
3344
3408
|
};
|
|
3345
|
-
}, [sheetRef]);
|
|
3409
|
+
}, [options == null ? void 0 : options.getCurrentIndex, options == null ? void 0 : options.targetIndex, sheetRef]);
|
|
3346
3410
|
return { keyboardVisible };
|
|
3347
3411
|
}
|
|
3348
3412
|
|
|
@@ -3351,12 +3415,16 @@ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
|
3351
3415
|
function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
3352
3416
|
const theme = useTheme();
|
|
3353
3417
|
const insets = useSafeAreaInsets3();
|
|
3354
|
-
const sheetRef =
|
|
3355
|
-
const snapPoints =
|
|
3418
|
+
const sheetRef = React21.useRef(null);
|
|
3419
|
+
const snapPoints = React21.useMemo(() => ["50%", "90%"], []);
|
|
3420
|
+
const currentIndexRef = React21.useRef(1);
|
|
3356
3421
|
const { comments, loading, sending, error, create, refresh } = useAppComments(appId);
|
|
3357
3422
|
const { app, loading: loadingApp } = useAppDetails(appId);
|
|
3358
|
-
const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef
|
|
3359
|
-
|
|
3423
|
+
const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef, {
|
|
3424
|
+
getCurrentIndex: () => currentIndexRef.current,
|
|
3425
|
+
targetIndex: 1
|
|
3426
|
+
});
|
|
3427
|
+
React21.useEffect(() => {
|
|
3360
3428
|
var _a, _b;
|
|
3361
3429
|
if (appId) {
|
|
3362
3430
|
(_a = sheetRef.current) == null ? void 0 : _a.present();
|
|
@@ -3365,21 +3433,22 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
|
3365
3433
|
(_b = sheetRef.current) == null ? void 0 : _b.dismiss();
|
|
3366
3434
|
}
|
|
3367
3435
|
}, [appId, refresh]);
|
|
3368
|
-
|
|
3436
|
+
React21.useEffect(() => {
|
|
3369
3437
|
if (!appId) return;
|
|
3370
3438
|
onCountChange == null ? void 0 : onCountChange(comments.length);
|
|
3371
3439
|
}, [appId, comments.length, onCountChange]);
|
|
3372
|
-
const renderBackdrop =
|
|
3440
|
+
const renderBackdrop = React21.useCallback(
|
|
3373
3441
|
(props) => /* @__PURE__ */ jsx18(BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
|
|
3374
3442
|
[]
|
|
3375
3443
|
);
|
|
3376
|
-
const handleChange =
|
|
3444
|
+
const handleChange = React21.useCallback(
|
|
3377
3445
|
(index) => {
|
|
3446
|
+
currentIndexRef.current = index;
|
|
3378
3447
|
if (index === -1) onClose();
|
|
3379
3448
|
},
|
|
3380
3449
|
[onClose]
|
|
3381
3450
|
);
|
|
3382
|
-
const handlePlay =
|
|
3451
|
+
const handlePlay = React21.useCallback(async () => {
|
|
3383
3452
|
var _a;
|
|
3384
3453
|
if (!appId) return;
|
|
3385
3454
|
(_a = sheetRef.current) == null ? void 0 : _a.dismiss();
|
|
@@ -3590,7 +3659,7 @@ function StudioSheetHeader({ left, center, right, style }) {
|
|
|
3590
3659
|
}
|
|
3591
3660
|
|
|
3592
3661
|
// src/components/studio-sheet/StudioSheetHeaderIconButton.tsx
|
|
3593
|
-
import * as
|
|
3662
|
+
import * as React22 from "react";
|
|
3594
3663
|
import { Pressable as Pressable6, View as View17 } from "react-native";
|
|
3595
3664
|
import { LiquidGlassView as LiquidGlassView5, isLiquidGlassSupported as isLiquidGlassSupported5 } from "@callstack/liquid-glass";
|
|
3596
3665
|
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
@@ -3605,7 +3674,7 @@ function StudioSheetHeaderIconButton({
|
|
|
3605
3674
|
}) {
|
|
3606
3675
|
const theme = useTheme();
|
|
3607
3676
|
const size = 44;
|
|
3608
|
-
const [pressed, setPressed] =
|
|
3677
|
+
const [pressed, setPressed] = React22.useState(false);
|
|
3609
3678
|
const solidBg = intent === "danger" ? theme.colors.danger : intent === "primary" ? theme.colors.primary : theme.colors.neutral;
|
|
3610
3679
|
const glassFallbackBg = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
|
|
3611
3680
|
const glassInnerBg = intent === "danger" ? theme.colors.danger : theme.colors.primary;
|
|
@@ -3795,14 +3864,14 @@ function PreviewHeroCard({
|
|
|
3795
3864
|
}
|
|
3796
3865
|
|
|
3797
3866
|
// src/components/preview/PreviewPlaceholder.tsx
|
|
3798
|
-
import * as
|
|
3867
|
+
import * as React23 from "react";
|
|
3799
3868
|
import { Animated as Animated6 } from "react-native";
|
|
3800
3869
|
import { LinearGradient as LinearGradient2 } from "expo-linear-gradient";
|
|
3801
3870
|
import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3802
3871
|
function PreviewPlaceholder({ visible, style }) {
|
|
3803
3872
|
if (!visible) return null;
|
|
3804
|
-
const opacityAnim =
|
|
3805
|
-
|
|
3873
|
+
const opacityAnim = React23.useRef(new Animated6.Value(0)).current;
|
|
3874
|
+
React23.useEffect(() => {
|
|
3806
3875
|
if (!visible) return;
|
|
3807
3876
|
const animation = Animated6.loop(
|
|
3808
3877
|
Animated6.sequence([
|
|
@@ -4394,12 +4463,12 @@ function PreviewCustomizeSection({
|
|
|
4394
4463
|
}
|
|
4395
4464
|
|
|
4396
4465
|
// src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
|
|
4397
|
-
import * as
|
|
4466
|
+
import * as React29 from "react";
|
|
4398
4467
|
import { ActivityIndicator as ActivityIndicator6, Alert, View as View32 } from "react-native";
|
|
4399
4468
|
import { Send as Send2 } from "lucide-react-native";
|
|
4400
4469
|
|
|
4401
4470
|
// src/components/merge-requests/MergeRequestStatusCard.tsx
|
|
4402
|
-
import * as
|
|
4471
|
+
import * as React25 from "react";
|
|
4403
4472
|
import { Animated as Animated7, Pressable as Pressable9, View as View28 } from "react-native";
|
|
4404
4473
|
import { Ban, Check as Check3, CheckCheck, ChevronDown as ChevronDown2 } from "lucide-react-native";
|
|
4405
4474
|
|
|
@@ -4481,11 +4550,11 @@ function toIsoString(input) {
|
|
|
4481
4550
|
}
|
|
4482
4551
|
|
|
4483
4552
|
// src/components/merge-requests/useControlledExpansion.ts
|
|
4484
|
-
import * as
|
|
4553
|
+
import * as React24 from "react";
|
|
4485
4554
|
function useControlledExpansion(props) {
|
|
4486
|
-
const [uncontrolled, setUncontrolled] =
|
|
4555
|
+
const [uncontrolled, setUncontrolled] = React24.useState(false);
|
|
4487
4556
|
const expanded = props.expanded ?? uncontrolled;
|
|
4488
|
-
const setExpanded =
|
|
4557
|
+
const setExpanded = React24.useCallback(
|
|
4489
4558
|
(next) => {
|
|
4490
4559
|
var _a;
|
|
4491
4560
|
(_a = props.onExpandedChange) == null ? void 0 : _a.call(props, next);
|
|
@@ -4510,8 +4579,8 @@ function MergeRequestStatusCard({
|
|
|
4510
4579
|
const isDark = theme.scheme === "dark";
|
|
4511
4580
|
const textColor = isDark ? "#FFFFFF" : "#000000";
|
|
4512
4581
|
const subTextColor = isDark ? "#A1A1AA" : "#71717A";
|
|
4513
|
-
const status =
|
|
4514
|
-
const { StatusIcon, iconColor, bgColor, statusText } =
|
|
4582
|
+
const status = React25.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
|
|
4583
|
+
const { StatusIcon, iconColor, bgColor, statusText } = React25.useMemo(() => {
|
|
4515
4584
|
switch (mergeRequest.status) {
|
|
4516
4585
|
case "approved":
|
|
4517
4586
|
case "merged":
|
|
@@ -4542,8 +4611,8 @@ function MergeRequestStatusCard({
|
|
|
4542
4611
|
const createdIso = toIsoString(mergeRequest.createdAt ?? null);
|
|
4543
4612
|
const headerTimeAgo = updatedIso ? formatTimeAgo(updatedIso) : "";
|
|
4544
4613
|
const createdTimeAgo = createdIso ? formatTimeAgo(createdIso) : "";
|
|
4545
|
-
const rotate =
|
|
4546
|
-
|
|
4614
|
+
const rotate = React25.useRef(new Animated7.Value(expanded ? 1 : 0)).current;
|
|
4615
|
+
React25.useEffect(() => {
|
|
4547
4616
|
Animated7.timing(rotate, {
|
|
4548
4617
|
toValue: expanded ? 1 : 0,
|
|
4549
4618
|
duration: 200,
|
|
@@ -4634,16 +4703,16 @@ function MergeRequestStatusCard({
|
|
|
4634
4703
|
}
|
|
4635
4704
|
|
|
4636
4705
|
// src/components/merge-requests/ReviewMergeRequestCarousel.tsx
|
|
4637
|
-
import * as
|
|
4706
|
+
import * as React28 from "react";
|
|
4638
4707
|
import { Animated as Animated9, FlatList, View as View31, useWindowDimensions as useWindowDimensions3 } from "react-native";
|
|
4639
4708
|
|
|
4640
4709
|
// src/components/merge-requests/ReviewMergeRequestCard.tsx
|
|
4641
|
-
import * as
|
|
4710
|
+
import * as React27 from "react";
|
|
4642
4711
|
import { ActivityIndicator as ActivityIndicator5, Animated as Animated8, Pressable as Pressable11, View as View30 } from "react-native";
|
|
4643
4712
|
import { Check as Check4, ChevronDown as ChevronDown3, Play as Play3, X as X3 } from "lucide-react-native";
|
|
4644
4713
|
|
|
4645
4714
|
// src/components/merge-requests/ReviewMergeRequestActionButton.tsx
|
|
4646
|
-
import * as
|
|
4715
|
+
import * as React26 from "react";
|
|
4647
4716
|
import { Pressable as Pressable10, View as View29 } from "react-native";
|
|
4648
4717
|
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
4649
4718
|
function ReviewMergeRequestActionButton({
|
|
@@ -4654,7 +4723,7 @@ function ReviewMergeRequestActionButton({
|
|
|
4654
4723
|
children,
|
|
4655
4724
|
iconOnly
|
|
4656
4725
|
}) {
|
|
4657
|
-
const [pressed, setPressed] =
|
|
4726
|
+
const [pressed, setPressed] = React26.useState(false);
|
|
4658
4727
|
const height = iconOnly ? 36 : 40;
|
|
4659
4728
|
const width = iconOnly ? 36 : void 0;
|
|
4660
4729
|
const paddingHorizontal = iconOnly ? 0 : 16;
|
|
@@ -4716,10 +4785,10 @@ function ReviewMergeRequestCard({
|
|
|
4716
4785
|
onTest
|
|
4717
4786
|
}) {
|
|
4718
4787
|
const theme = useTheme();
|
|
4719
|
-
const status =
|
|
4788
|
+
const status = React27.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
|
|
4720
4789
|
const canAct = mr.status === "open";
|
|
4721
|
-
const rotate =
|
|
4722
|
-
|
|
4790
|
+
const rotate = React27.useRef(new Animated8.Value(isExpanded ? 1 : 0)).current;
|
|
4791
|
+
React27.useEffect(() => {
|
|
4723
4792
|
Animated8.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
|
|
4724
4793
|
}, [isExpanded, rotate]);
|
|
4725
4794
|
const position = total > 1 ? `${index + 1}/${total}` : "Merge request";
|
|
@@ -4851,11 +4920,11 @@ function ReviewMergeRequestCarousel({
|
|
|
4851
4920
|
}) {
|
|
4852
4921
|
const theme = useTheme();
|
|
4853
4922
|
const { width } = useWindowDimensions3();
|
|
4854
|
-
const [expanded, setExpanded] =
|
|
4855
|
-
const carouselScrollX =
|
|
4923
|
+
const [expanded, setExpanded] = React28.useState({});
|
|
4924
|
+
const carouselScrollX = React28.useRef(new Animated9.Value(0)).current;
|
|
4856
4925
|
const peekAmount = 24;
|
|
4857
4926
|
const gap = 16;
|
|
4858
|
-
const cardWidth =
|
|
4927
|
+
const cardWidth = React28.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
|
|
4859
4928
|
const snapInterval = cardWidth + gap;
|
|
4860
4929
|
const dotColor = theme.scheme === "dark" ? "#FFFFFF" : "#000000";
|
|
4861
4930
|
if (mergeRequests.length === 0) return null;
|
|
@@ -4954,7 +5023,7 @@ function PreviewCollaborateSection({
|
|
|
4954
5023
|
onTestMr
|
|
4955
5024
|
}) {
|
|
4956
5025
|
const theme = useTheme();
|
|
4957
|
-
const [submittingMr, setSubmittingMr] =
|
|
5026
|
+
const [submittingMr, setSubmittingMr] = React29.useState(false);
|
|
4958
5027
|
const hasSection = canSubmitMergeRequest || incomingMergeRequests.length > 0 || outgoingMergeRequests.length > 0;
|
|
4959
5028
|
if (!hasSection) return null;
|
|
4960
5029
|
const showActionsSubtitle = canSubmitMergeRequest && onSubmitMergeRequest || onTestMr && incomingMergeRequests.length > 0;
|
|
@@ -5062,7 +5131,7 @@ function PreviewCollaborateSection({
|
|
|
5062
5131
|
}
|
|
5063
5132
|
|
|
5064
5133
|
// src/studio/ui/preview-panel/usePreviewPanelData.ts
|
|
5065
|
-
import * as
|
|
5134
|
+
import * as React31 from "react";
|
|
5066
5135
|
|
|
5067
5136
|
// src/data/apps/images/remote.ts
|
|
5068
5137
|
var AppImagesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -5113,7 +5182,7 @@ var AppImagesRepositoryImpl = class extends BaseRepository {
|
|
|
5113
5182
|
var appImagesRepository = new AppImagesRepositoryImpl(appImagesRemoteDataSource);
|
|
5114
5183
|
|
|
5115
5184
|
// src/studio/hooks/useAppStats.ts
|
|
5116
|
-
import * as
|
|
5185
|
+
import * as React30 from "react";
|
|
5117
5186
|
import * as Haptics2 from "expo-haptics";
|
|
5118
5187
|
|
|
5119
5188
|
// src/data/likes/remote.ts
|
|
@@ -5182,34 +5251,34 @@ function useAppStats({
|
|
|
5182
5251
|
initialIsLiked = false,
|
|
5183
5252
|
onOpenComments
|
|
5184
5253
|
}) {
|
|
5185
|
-
const [likeCount, setLikeCount] =
|
|
5186
|
-
const [commentCount, setCommentCount] =
|
|
5187
|
-
const [forkCount, setForkCount] =
|
|
5188
|
-
const [isLiked, setIsLiked] =
|
|
5189
|
-
const didMutateRef =
|
|
5190
|
-
const lastAppIdRef =
|
|
5191
|
-
|
|
5254
|
+
const [likeCount, setLikeCount] = React30.useState(initialLikes);
|
|
5255
|
+
const [commentCount, setCommentCount] = React30.useState(initialComments);
|
|
5256
|
+
const [forkCount, setForkCount] = React30.useState(initialForks);
|
|
5257
|
+
const [isLiked, setIsLiked] = React30.useState(initialIsLiked);
|
|
5258
|
+
const didMutateRef = React30.useRef(false);
|
|
5259
|
+
const lastAppIdRef = React30.useRef("");
|
|
5260
|
+
React30.useEffect(() => {
|
|
5192
5261
|
if (lastAppIdRef.current === appId) return;
|
|
5193
5262
|
lastAppIdRef.current = appId;
|
|
5194
5263
|
didMutateRef.current = false;
|
|
5195
5264
|
}, [appId]);
|
|
5196
|
-
|
|
5265
|
+
React30.useEffect(() => {
|
|
5197
5266
|
if (didMutateRef.current) return;
|
|
5198
5267
|
setLikeCount(initialLikes);
|
|
5199
5268
|
}, [appId, initialLikes]);
|
|
5200
|
-
|
|
5269
|
+
React30.useEffect(() => {
|
|
5201
5270
|
if (didMutateRef.current) return;
|
|
5202
5271
|
setCommentCount(initialComments);
|
|
5203
5272
|
}, [appId, initialComments]);
|
|
5204
|
-
|
|
5273
|
+
React30.useEffect(() => {
|
|
5205
5274
|
if (didMutateRef.current) return;
|
|
5206
5275
|
setForkCount(initialForks);
|
|
5207
5276
|
}, [appId, initialForks]);
|
|
5208
|
-
|
|
5277
|
+
React30.useEffect(() => {
|
|
5209
5278
|
if (didMutateRef.current) return;
|
|
5210
5279
|
setIsLiked(initialIsLiked);
|
|
5211
5280
|
}, [appId, initialIsLiked]);
|
|
5212
|
-
const handleLike =
|
|
5281
|
+
const handleLike = React30.useCallback(async () => {
|
|
5213
5282
|
var _a, _b;
|
|
5214
5283
|
if (!appId) return;
|
|
5215
5284
|
didMutateRef.current = true;
|
|
@@ -5233,7 +5302,7 @@ function useAppStats({
|
|
|
5233
5302
|
setLikeCount((prev) => Math.max(0, prev + (newIsLiked ? -1 : 1)));
|
|
5234
5303
|
}
|
|
5235
5304
|
}, [appId, isLiked, likeCount]);
|
|
5236
|
-
const handleOpenComments =
|
|
5305
|
+
const handleOpenComments = React30.useCallback(() => {
|
|
5237
5306
|
if (!appId) return;
|
|
5238
5307
|
try {
|
|
5239
5308
|
void Haptics2.impactAsync(Haptics2.ImpactFeedbackStyle.Light);
|
|
@@ -5248,11 +5317,11 @@ function useAppStats({
|
|
|
5248
5317
|
var LIKE_DEBUG_PREFIX = "[COMERGE_LIKE_DEBUG]";
|
|
5249
5318
|
function usePreviewPanelData(params) {
|
|
5250
5319
|
const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
|
|
5251
|
-
const [imageUrl, setImageUrl] =
|
|
5252
|
-
const [imageLoaded, setImageLoaded] =
|
|
5253
|
-
const [insights, setInsights] =
|
|
5254
|
-
const [creator, setCreator] =
|
|
5255
|
-
|
|
5320
|
+
const [imageUrl, setImageUrl] = React31.useState(null);
|
|
5321
|
+
const [imageLoaded, setImageLoaded] = React31.useState(false);
|
|
5322
|
+
const [insights, setInsights] = React31.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
|
|
5323
|
+
const [creator, setCreator] = React31.useState(null);
|
|
5324
|
+
React31.useEffect(() => {
|
|
5256
5325
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5257
5326
|
let cancelled = false;
|
|
5258
5327
|
(async () => {
|
|
@@ -5267,7 +5336,7 @@ function usePreviewPanelData(params) {
|
|
|
5267
5336
|
cancelled = true;
|
|
5268
5337
|
};
|
|
5269
5338
|
}, [app == null ? void 0 : app.id]);
|
|
5270
|
-
|
|
5339
|
+
React31.useEffect(() => {
|
|
5271
5340
|
if (!(app == null ? void 0 : app.createdBy)) return;
|
|
5272
5341
|
let cancelled = false;
|
|
5273
5342
|
(async () => {
|
|
@@ -5283,10 +5352,10 @@ function usePreviewPanelData(params) {
|
|
|
5283
5352
|
cancelled = true;
|
|
5284
5353
|
};
|
|
5285
5354
|
}, [app == null ? void 0 : app.createdBy]);
|
|
5286
|
-
|
|
5355
|
+
React31.useEffect(() => {
|
|
5287
5356
|
setImageLoaded(false);
|
|
5288
5357
|
}, [app == null ? void 0 : app.id]);
|
|
5289
|
-
|
|
5358
|
+
React31.useEffect(() => {
|
|
5290
5359
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5291
5360
|
let cancelled = false;
|
|
5292
5361
|
(async () => {
|
|
@@ -5311,7 +5380,7 @@ function usePreviewPanelData(params) {
|
|
|
5311
5380
|
cancelled = true;
|
|
5312
5381
|
};
|
|
5313
5382
|
}, [app == null ? void 0 : app.id]);
|
|
5314
|
-
|
|
5383
|
+
React31.useEffect(() => {
|
|
5315
5384
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5316
5385
|
log.debug(
|
|
5317
5386
|
`${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
|
|
@@ -5325,7 +5394,7 @@ function usePreviewPanelData(params) {
|
|
|
5325
5394
|
initialIsLiked: Boolean(app == null ? void 0 : app.isLiked),
|
|
5326
5395
|
onOpenComments
|
|
5327
5396
|
});
|
|
5328
|
-
const canSubmitMergeRequest =
|
|
5397
|
+
const canSubmitMergeRequest = React31.useMemo(() => {
|
|
5329
5398
|
if (!isOwner) return false;
|
|
5330
5399
|
if (!app) return false;
|
|
5331
5400
|
if (!app.forkedFromAppId) return false;
|
|
@@ -5438,18 +5507,17 @@ function PreviewPanel({
|
|
|
5438
5507
|
}
|
|
5439
5508
|
|
|
5440
5509
|
// src/studio/ui/ChatPanel.tsx
|
|
5441
|
-
import * as
|
|
5510
|
+
import * as React36 from "react";
|
|
5442
5511
|
import { ActivityIndicator as ActivityIndicator8, View as View41 } from "react-native";
|
|
5443
5512
|
|
|
5444
5513
|
// src/components/chat/ChatPage.tsx
|
|
5445
|
-
import * as
|
|
5446
|
-
import { Keyboard as Keyboard4, Platform as
|
|
5514
|
+
import * as React34 from "react";
|
|
5515
|
+
import { Keyboard as Keyboard4, Platform as Platform7, View as View37 } from "react-native";
|
|
5447
5516
|
import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
|
|
5448
|
-
import Animated11, { useAnimatedKeyboard, useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
|
|
5449
5517
|
|
|
5450
5518
|
// src/components/chat/ChatMessageList.tsx
|
|
5451
|
-
import * as
|
|
5452
|
-
import { View as View36 } from "react-native";
|
|
5519
|
+
import * as React33 from "react";
|
|
5520
|
+
import { Platform as Platform6, View as View36 } from "react-native";
|
|
5453
5521
|
import { BottomSheetFlatList } from "@gorhom/bottom-sheet";
|
|
5454
5522
|
|
|
5455
5523
|
// src/components/chat/ChatMessageBubble.tsx
|
|
@@ -5494,17 +5562,17 @@ function ChatMessageBubble({ message, renderContent, style }) {
|
|
|
5494
5562
|
}
|
|
5495
5563
|
|
|
5496
5564
|
// src/components/chat/TypingIndicator.tsx
|
|
5497
|
-
import * as
|
|
5565
|
+
import * as React32 from "react";
|
|
5498
5566
|
import { Animated as Animated10, View as View35 } from "react-native";
|
|
5499
5567
|
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
5500
5568
|
function TypingIndicator({ style }) {
|
|
5501
5569
|
const theme = useTheme();
|
|
5502
5570
|
const dotColor = theme.colors.textSubtle;
|
|
5503
|
-
const anims =
|
|
5571
|
+
const anims = React32.useMemo(
|
|
5504
5572
|
() => [new Animated10.Value(0.3), new Animated10.Value(0.3), new Animated10.Value(0.3)],
|
|
5505
5573
|
[]
|
|
5506
5574
|
);
|
|
5507
|
-
|
|
5575
|
+
React32.useEffect(() => {
|
|
5508
5576
|
const loops = [];
|
|
5509
5577
|
anims.forEach((a, idx) => {
|
|
5510
5578
|
const seq = Animated10.sequence([
|
|
@@ -5537,40 +5605,44 @@ function TypingIndicator({ style }) {
|
|
|
5537
5605
|
}
|
|
5538
5606
|
|
|
5539
5607
|
// src/components/chat/ChatMessageList.tsx
|
|
5540
|
-
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
5541
|
-
var ChatMessageList =
|
|
5608
|
+
import { jsx as jsx46, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
5609
|
+
var ChatMessageList = React33.forwardRef(
|
|
5542
5610
|
({
|
|
5543
5611
|
messages,
|
|
5544
5612
|
showTypingIndicator = false,
|
|
5545
5613
|
renderMessageContent,
|
|
5546
5614
|
contentStyle,
|
|
5615
|
+
bottomInset = 0,
|
|
5547
5616
|
onNearBottomChange,
|
|
5548
5617
|
nearBottomThreshold = 200
|
|
5549
5618
|
}, ref) => {
|
|
5550
5619
|
const theme = useTheme();
|
|
5551
|
-
const listRef =
|
|
5552
|
-
const nearBottomRef =
|
|
5553
|
-
const initialScrollDoneRef =
|
|
5554
|
-
const lastMessageIdRef =
|
|
5555
|
-
const scrollToBottom =
|
|
5620
|
+
const listRef = React33.useRef(null);
|
|
5621
|
+
const nearBottomRef = React33.useRef(true);
|
|
5622
|
+
const initialScrollDoneRef = React33.useRef(false);
|
|
5623
|
+
const lastMessageIdRef = React33.useRef(null);
|
|
5624
|
+
const scrollToBottom = React33.useCallback((options) => {
|
|
5556
5625
|
var _a;
|
|
5557
5626
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
5558
5627
|
(_a = listRef.current) == null ? void 0 : _a.scrollToEnd({ animated });
|
|
5559
5628
|
}, []);
|
|
5560
|
-
|
|
5561
|
-
const handleScroll =
|
|
5629
|
+
React33.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
|
|
5630
|
+
const handleScroll = React33.useCallback(
|
|
5562
5631
|
(e) => {
|
|
5563
5632
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
5564
|
-
const distanceFromBottom = Math.max(
|
|
5633
|
+
const distanceFromBottom = Math.max(
|
|
5634
|
+
contentSize.height - Math.max(bottomInset, 0) - (contentOffset.y + layoutMeasurement.height),
|
|
5635
|
+
0
|
|
5636
|
+
);
|
|
5565
5637
|
const isNear = distanceFromBottom <= nearBottomThreshold;
|
|
5566
5638
|
if (nearBottomRef.current !== isNear) {
|
|
5567
5639
|
nearBottomRef.current = isNear;
|
|
5568
5640
|
onNearBottomChange == null ? void 0 : onNearBottomChange(isNear);
|
|
5569
5641
|
}
|
|
5570
5642
|
},
|
|
5571
|
-
[nearBottomThreshold, onNearBottomChange]
|
|
5643
|
+
[bottomInset, nearBottomThreshold, onNearBottomChange]
|
|
5572
5644
|
);
|
|
5573
|
-
|
|
5645
|
+
React33.useEffect(() => {
|
|
5574
5646
|
var _a;
|
|
5575
5647
|
if (initialScrollDoneRef.current) return;
|
|
5576
5648
|
if (messages.length === 0) return;
|
|
@@ -5579,7 +5651,7 @@ var ChatMessageList = React32.forwardRef(
|
|
|
5579
5651
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
|
|
5580
5652
|
return () => cancelAnimationFrame(id);
|
|
5581
5653
|
}, [messages, scrollToBottom]);
|
|
5582
|
-
|
|
5654
|
+
React33.useEffect(() => {
|
|
5583
5655
|
if (!initialScrollDoneRef.current) return;
|
|
5584
5656
|
const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
5585
5657
|
const prevLastId = lastMessageIdRef.current;
|
|
@@ -5589,19 +5661,27 @@ var ChatMessageList = React32.forwardRef(
|
|
|
5589
5661
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5590
5662
|
return () => cancelAnimationFrame(id);
|
|
5591
5663
|
}, [messages, scrollToBottom]);
|
|
5592
|
-
|
|
5664
|
+
React33.useEffect(() => {
|
|
5593
5665
|
if (showTypingIndicator && nearBottomRef.current) {
|
|
5594
5666
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5595
5667
|
return () => cancelAnimationFrame(id);
|
|
5596
5668
|
}
|
|
5597
5669
|
return void 0;
|
|
5598
5670
|
}, [showTypingIndicator, scrollToBottom]);
|
|
5671
|
+
React33.useEffect(() => {
|
|
5672
|
+
if (!initialScrollDoneRef.current) return;
|
|
5673
|
+
if (!nearBottomRef.current) return;
|
|
5674
|
+
const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
|
|
5675
|
+
return () => cancelAnimationFrame(id);
|
|
5676
|
+
}, [bottomInset, scrollToBottom]);
|
|
5599
5677
|
return /* @__PURE__ */ jsx46(
|
|
5600
5678
|
BottomSheetFlatList,
|
|
5601
5679
|
{
|
|
5602
5680
|
ref: listRef,
|
|
5603
5681
|
data: messages,
|
|
5604
5682
|
keyExtractor: (m) => m.id,
|
|
5683
|
+
keyboardDismissMode: Platform6.OS === "ios" ? "interactive" : "on-drag",
|
|
5684
|
+
keyboardShouldPersistTaps: "handled",
|
|
5605
5685
|
onScroll: handleScroll,
|
|
5606
5686
|
scrollEventThrottle: 16,
|
|
5607
5687
|
showsVerticalScrollIndicator: false,
|
|
@@ -5609,13 +5689,15 @@ var ChatMessageList = React32.forwardRef(
|
|
|
5609
5689
|
{
|
|
5610
5690
|
paddingHorizontal: theme.spacing.lg,
|
|
5611
5691
|
paddingTop: theme.spacing.sm,
|
|
5612
|
-
paddingBottom: theme.spacing.
|
|
5692
|
+
paddingBottom: theme.spacing.sm
|
|
5613
5693
|
},
|
|
5614
5694
|
contentStyle
|
|
5615
5695
|
],
|
|
5616
5696
|
renderItem: ({ item, index }) => /* @__PURE__ */ jsx46(View36, { style: { marginTop: index === 0 ? 0 : theme.spacing.sm }, children: /* @__PURE__ */ jsx46(ChatMessageBubble, { message: item, renderContent: renderMessageContent }) }),
|
|
5617
|
-
ListFooterComponent:
|
|
5618
|
-
|
|
5697
|
+
ListFooterComponent: /* @__PURE__ */ jsxs28(View36, { children: [
|
|
5698
|
+
showTypingIndicator ? /* @__PURE__ */ jsx46(View36, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ jsx46(TypingIndicator, {}) }) : null,
|
|
5699
|
+
bottomInset > 0 ? /* @__PURE__ */ jsx46(View36, { style: { height: bottomInset } }) : null
|
|
5700
|
+
] })
|
|
5619
5701
|
}
|
|
5620
5702
|
);
|
|
5621
5703
|
}
|
|
@@ -5623,7 +5705,7 @@ var ChatMessageList = React32.forwardRef(
|
|
|
5623
5705
|
ChatMessageList.displayName = "ChatMessageList";
|
|
5624
5706
|
|
|
5625
5707
|
// src/components/chat/ChatPage.tsx
|
|
5626
|
-
import { jsx as jsx47, jsxs as
|
|
5708
|
+
import { jsx as jsx47, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
5627
5709
|
function ChatPage({
|
|
5628
5710
|
header,
|
|
5629
5711
|
messages,
|
|
@@ -5638,11 +5720,10 @@ function ChatPage({
|
|
|
5638
5720
|
}) {
|
|
5639
5721
|
const theme = useTheme();
|
|
5640
5722
|
const insets = useSafeAreaInsets4();
|
|
5641
|
-
const [composerHeight, setComposerHeight] =
|
|
5642
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
if (Platform6.OS !== "ios") return;
|
|
5723
|
+
const [composerHeight, setComposerHeight] = React34.useState(0);
|
|
5724
|
+
const [keyboardVisible, setKeyboardVisible] = React34.useState(false);
|
|
5725
|
+
React34.useEffect(() => {
|
|
5726
|
+
if (Platform7.OS !== "ios") return;
|
|
5646
5727
|
const show = Keyboard4.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
5647
5728
|
const hide = Keyboard4.addListener("keyboardWillHide", () => setKeyboardVisible(false));
|
|
5648
5729
|
return () => {
|
|
@@ -5650,51 +5731,54 @@ function ChatPage({
|
|
|
5650
5731
|
hide.remove();
|
|
5651
5732
|
};
|
|
5652
5733
|
}, []);
|
|
5653
|
-
const footerBottomPadding =
|
|
5654
|
-
const footerAnimatedStyle = useAnimatedStyle2(() => {
|
|
5655
|
-
if (Platform6.OS !== "ios") return { paddingBottom: insets.bottom + 10 };
|
|
5656
|
-
return { paddingBottom: animatedKeyboard.height.value > 0 ? 0 : insets.bottom };
|
|
5657
|
-
});
|
|
5734
|
+
const footerBottomPadding = Platform7.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
|
|
5658
5735
|
const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
|
|
5659
|
-
const
|
|
5736
|
+
const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
|
|
5737
|
+
const resolvedOverlay = React34.useMemo(() => {
|
|
5660
5738
|
var _a;
|
|
5661
5739
|
if (!overlay) return null;
|
|
5662
|
-
if (!
|
|
5740
|
+
if (!React34.isValidElement(overlay)) return overlay;
|
|
5663
5741
|
const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
|
|
5664
|
-
return
|
|
5742
|
+
return React34.cloneElement(overlay, {
|
|
5665
5743
|
style: [prevStyle, { bottom: overlayBottom }]
|
|
5666
5744
|
});
|
|
5667
5745
|
}, [overlay, overlayBottom]);
|
|
5668
|
-
return /* @__PURE__ */
|
|
5746
|
+
return /* @__PURE__ */ jsxs29(View37, { style: [{ flex: 1 }, style], children: [
|
|
5669
5747
|
header ? /* @__PURE__ */ jsx47(View37, { children: header }) : null,
|
|
5670
5748
|
topBanner ? /* @__PURE__ */ jsx47(View37, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
|
|
5671
|
-
/* @__PURE__ */
|
|
5672
|
-
/* @__PURE__ */
|
|
5673
|
-
|
|
5749
|
+
/* @__PURE__ */ jsxs29(View37, { style: { flex: 1 }, children: [
|
|
5750
|
+
/* @__PURE__ */ jsxs29(
|
|
5751
|
+
View37,
|
|
5674
5752
|
{
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5753
|
+
style: { flex: 1 },
|
|
5754
|
+
children: [
|
|
5755
|
+
/* @__PURE__ */ jsx47(
|
|
5756
|
+
ChatMessageList,
|
|
5757
|
+
{
|
|
5758
|
+
ref: listRef,
|
|
5759
|
+
messages,
|
|
5760
|
+
showTypingIndicator,
|
|
5761
|
+
renderMessageContent,
|
|
5762
|
+
onNearBottomChange,
|
|
5763
|
+
bottomInset
|
|
5764
|
+
}
|
|
5765
|
+
),
|
|
5766
|
+
resolvedOverlay
|
|
5767
|
+
]
|
|
5681
5768
|
}
|
|
5682
5769
|
),
|
|
5683
|
-
resolvedOverlay,
|
|
5684
5770
|
/* @__PURE__ */ jsx47(
|
|
5685
|
-
|
|
5771
|
+
View37,
|
|
5686
5772
|
{
|
|
5687
|
-
style:
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
footerAnimatedStyle
|
|
5697
|
-
],
|
|
5773
|
+
style: {
|
|
5774
|
+
position: "absolute",
|
|
5775
|
+
left: 0,
|
|
5776
|
+
right: 0,
|
|
5777
|
+
bottom: 0,
|
|
5778
|
+
paddingHorizontal: theme.spacing.lg,
|
|
5779
|
+
paddingTop: theme.spacing.sm,
|
|
5780
|
+
paddingBottom: footerBottomPadding
|
|
5781
|
+
},
|
|
5698
5782
|
children: /* @__PURE__ */ jsx47(
|
|
5699
5783
|
ChatComposer,
|
|
5700
5784
|
{
|
|
@@ -5710,25 +5794,25 @@ function ChatPage({
|
|
|
5710
5794
|
}
|
|
5711
5795
|
|
|
5712
5796
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
5713
|
-
import * as
|
|
5797
|
+
import * as React35 from "react";
|
|
5714
5798
|
import { Pressable as Pressable12, View as View38 } from "react-native";
|
|
5715
|
-
import
|
|
5799
|
+
import Animated11, { Easing as Easing2, useAnimatedStyle as useAnimatedStyle2, useSharedValue as useSharedValue2, withTiming as withTiming2 } from "react-native-reanimated";
|
|
5716
5800
|
import { jsx as jsx48 } from "react/jsx-runtime";
|
|
5717
5801
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
5718
5802
|
const theme = useTheme();
|
|
5719
5803
|
const progress = useSharedValue2(visible ? 1 : 0);
|
|
5720
|
-
const [pressed, setPressed] =
|
|
5721
|
-
|
|
5804
|
+
const [pressed, setPressed] = React35.useState(false);
|
|
5805
|
+
React35.useEffect(() => {
|
|
5722
5806
|
progress.value = withTiming2(visible ? 1 : 0, { duration: 200, easing: Easing2.out(Easing2.ease) });
|
|
5723
5807
|
}, [progress, visible]);
|
|
5724
|
-
const animStyle =
|
|
5808
|
+
const animStyle = useAnimatedStyle2(() => ({
|
|
5725
5809
|
opacity: progress.value,
|
|
5726
5810
|
transform: [{ translateY: (1 - progress.value) * 20 }]
|
|
5727
5811
|
}));
|
|
5728
5812
|
const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
|
|
5729
5813
|
const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
|
|
5730
5814
|
return /* @__PURE__ */ jsx48(
|
|
5731
|
-
|
|
5815
|
+
Animated11.View,
|
|
5732
5816
|
{
|
|
5733
5817
|
pointerEvents: visible ? "auto" : "none",
|
|
5734
5818
|
style: [
|
|
@@ -5800,7 +5884,7 @@ function ChatHeader({ left, right, center, style }) {
|
|
|
5800
5884
|
|
|
5801
5885
|
// src/components/chat/ForkNoticeBanner.tsx
|
|
5802
5886
|
import { View as View40 } from "react-native";
|
|
5803
|
-
import { jsx as jsx50, jsxs as
|
|
5887
|
+
import { jsx as jsx50, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
5804
5888
|
function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
5805
5889
|
const theme = useTheme();
|
|
5806
5890
|
const resolvedTitle = title ?? (isOwner ? "Remixed app" : "Remix app");
|
|
@@ -5820,7 +5904,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
5820
5904
|
},
|
|
5821
5905
|
style
|
|
5822
5906
|
],
|
|
5823
|
-
children: /* @__PURE__ */
|
|
5907
|
+
children: /* @__PURE__ */ jsxs30(View40, { style: { minWidth: 0 }, children: [
|
|
5824
5908
|
/* @__PURE__ */ jsx50(
|
|
5825
5909
|
Text,
|
|
5826
5910
|
{
|
|
@@ -5853,7 +5937,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
5853
5937
|
}
|
|
5854
5938
|
|
|
5855
5939
|
// src/studio/ui/ChatPanel.tsx
|
|
5856
|
-
import { jsx as jsx51, jsxs as
|
|
5940
|
+
import { jsx as jsx51, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5857
5941
|
function ChatPanel({
|
|
5858
5942
|
title = "Chat",
|
|
5859
5943
|
autoFocusComposer = false,
|
|
@@ -5873,32 +5957,34 @@ function ChatPanel({
|
|
|
5873
5957
|
onStartDraw,
|
|
5874
5958
|
onSend
|
|
5875
5959
|
}) {
|
|
5876
|
-
const listRef =
|
|
5877
|
-
const [nearBottom, setNearBottom] =
|
|
5878
|
-
const handleSend =
|
|
5960
|
+
const listRef = React36.useRef(null);
|
|
5961
|
+
const [nearBottom, setNearBottom] = React36.useState(true);
|
|
5962
|
+
const handleSend = React36.useCallback(
|
|
5879
5963
|
async (text, composerAttachments) => {
|
|
5880
5964
|
const all = composerAttachments ?? attachments;
|
|
5881
5965
|
await onSend(text, all.length > 0 ? all : void 0);
|
|
5882
5966
|
onClearAttachments == null ? void 0 : onClearAttachments();
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5967
|
+
if (!nearBottom) {
|
|
5968
|
+
requestAnimationFrame(() => {
|
|
5969
|
+
var _a;
|
|
5970
|
+
return (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
5971
|
+
});
|
|
5972
|
+
}
|
|
5887
5973
|
},
|
|
5888
|
-
[attachments, onClearAttachments, onSend]
|
|
5974
|
+
[attachments, nearBottom, onClearAttachments, onSend]
|
|
5889
5975
|
);
|
|
5890
|
-
const handleScrollToBottom =
|
|
5976
|
+
const handleScrollToBottom = React36.useCallback(() => {
|
|
5891
5977
|
var _a;
|
|
5892
5978
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
5893
5979
|
}, []);
|
|
5894
5980
|
const header = /* @__PURE__ */ jsx51(
|
|
5895
5981
|
ChatHeader,
|
|
5896
5982
|
{
|
|
5897
|
-
left: /* @__PURE__ */
|
|
5983
|
+
left: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
5898
5984
|
/* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx51(IconBack, { size: 20, colorToken: "floatingContent" }) }),
|
|
5899
5985
|
onNavigateHome ? /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx51(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
|
|
5900
5986
|
] }),
|
|
5901
|
-
right: /* @__PURE__ */
|
|
5987
|
+
right: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
5902
5988
|
onStartDraw ? /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx51(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
|
|
5903
5989
|
/* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx51(IconClose, { size: 20, colorToken: "floatingContent" }) })
|
|
5904
5990
|
] }),
|
|
@@ -5914,10 +6000,10 @@ function ChatPanel({
|
|
|
5914
6000
|
) : null;
|
|
5915
6001
|
const showMessagesLoading = Boolean(loading) && messages.length === 0 || forking;
|
|
5916
6002
|
if (showMessagesLoading) {
|
|
5917
|
-
return /* @__PURE__ */
|
|
6003
|
+
return /* @__PURE__ */ jsxs31(View41, { style: { flex: 1 }, children: [
|
|
5918
6004
|
/* @__PURE__ */ jsx51(View41, { children: header }),
|
|
5919
6005
|
topBanner ? /* @__PURE__ */ jsx51(View41, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
|
|
5920
|
-
/* @__PURE__ */
|
|
6006
|
+
/* @__PURE__ */ jsxs31(View41, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
|
|
5921
6007
|
/* @__PURE__ */ jsx51(ActivityIndicator8, {}),
|
|
5922
6008
|
/* @__PURE__ */ jsx51(View41, { style: { height: 12 } }),
|
|
5923
6009
|
/* @__PURE__ */ jsx51(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
|
|
@@ -5943,7 +6029,10 @@ function ChatPanel({
|
|
|
5943
6029
|
}
|
|
5944
6030
|
),
|
|
5945
6031
|
composer: {
|
|
5946
|
-
|
|
6032
|
+
// Keep the input editable even when sending is disallowed (e.g. agent still working),
|
|
6033
|
+
// otherwise iOS will drop focus/keyboard and BottomSheet can get "stuck" with a keyboard-sized gap.
|
|
6034
|
+
disabled: Boolean(loading) || Boolean(forking),
|
|
6035
|
+
sendDisabled: Boolean(sendDisabled) || Boolean(loading) || Boolean(forking),
|
|
5947
6036
|
sending: Boolean(sending),
|
|
5948
6037
|
autoFocus: autoFocusComposer,
|
|
5949
6038
|
onSend: handleSend,
|
|
@@ -5957,7 +6046,7 @@ function ChatPanel({
|
|
|
5957
6046
|
}
|
|
5958
6047
|
|
|
5959
6048
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
5960
|
-
import * as
|
|
6049
|
+
import * as React37 from "react";
|
|
5961
6050
|
import { Pressable as Pressable14, View as View43 } from "react-native";
|
|
5962
6051
|
|
|
5963
6052
|
// src/components/primitives/Modal.tsx
|
|
@@ -5966,7 +6055,7 @@ import {
|
|
|
5966
6055
|
Pressable as Pressable13,
|
|
5967
6056
|
View as View42
|
|
5968
6057
|
} from "react-native";
|
|
5969
|
-
import { jsx as jsx52, jsxs as
|
|
6058
|
+
import { jsx as jsx52, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
5970
6059
|
function Modal({
|
|
5971
6060
|
visible,
|
|
5972
6061
|
onRequestClose,
|
|
@@ -5982,7 +6071,7 @@ function Modal({
|
|
|
5982
6071
|
transparent: true,
|
|
5983
6072
|
animationType: "fade",
|
|
5984
6073
|
onRequestClose,
|
|
5985
|
-
children: /* @__PURE__ */
|
|
6074
|
+
children: /* @__PURE__ */ jsxs32(View42, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
|
|
5986
6075
|
/* @__PURE__ */ jsx52(
|
|
5987
6076
|
Pressable13,
|
|
5988
6077
|
{
|
|
@@ -5998,7 +6087,7 @@ function Modal({
|
|
|
5998
6087
|
}
|
|
5999
6088
|
|
|
6000
6089
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
6001
|
-
import { jsx as jsx53, jsxs as
|
|
6090
|
+
import { jsx as jsx53, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
6002
6091
|
function ConfirmMergeRequestDialog({
|
|
6003
6092
|
visible,
|
|
6004
6093
|
onOpenChange,
|
|
@@ -6009,14 +6098,14 @@ function ConfirmMergeRequestDialog({
|
|
|
6009
6098
|
onTestFirst
|
|
6010
6099
|
}) {
|
|
6011
6100
|
const theme = useTheme();
|
|
6012
|
-
const close =
|
|
6101
|
+
const close = React37.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
6013
6102
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
6014
|
-
const handleConfirm =
|
|
6103
|
+
const handleConfirm = React37.useCallback(() => {
|
|
6015
6104
|
if (!mergeRequest) return;
|
|
6016
6105
|
onOpenChange(false);
|
|
6017
6106
|
void onConfirm();
|
|
6018
6107
|
}, [mergeRequest, onConfirm, onOpenChange]);
|
|
6019
|
-
const handleTestFirst =
|
|
6108
|
+
const handleTestFirst = React37.useCallback(() => {
|
|
6020
6109
|
if (!mergeRequest) return;
|
|
6021
6110
|
onOpenChange(false);
|
|
6022
6111
|
void onTestFirst(mergeRequest);
|
|
@@ -6028,7 +6117,7 @@ function ConfirmMergeRequestDialog({
|
|
|
6028
6117
|
justifyContent: "center",
|
|
6029
6118
|
alignSelf: "stretch"
|
|
6030
6119
|
};
|
|
6031
|
-
return /* @__PURE__ */
|
|
6120
|
+
return /* @__PURE__ */ jsxs33(
|
|
6032
6121
|
Modal,
|
|
6033
6122
|
{
|
|
6034
6123
|
visible,
|
|
@@ -6051,7 +6140,7 @@ function ConfirmMergeRequestDialog({
|
|
|
6051
6140
|
children: "Are you sure you want to approve this merge request?"
|
|
6052
6141
|
}
|
|
6053
6142
|
) }),
|
|
6054
|
-
/* @__PURE__ */
|
|
6143
|
+
/* @__PURE__ */ jsxs33(View43, { style: { marginTop: 16 }, children: [
|
|
6055
6144
|
/* @__PURE__ */ jsx53(
|
|
6056
6145
|
View43,
|
|
6057
6146
|
{
|
|
@@ -6165,7 +6254,7 @@ function ConfirmMergeFlow({
|
|
|
6165
6254
|
}
|
|
6166
6255
|
|
|
6167
6256
|
// src/studio/ui/StudioOverlay.tsx
|
|
6168
|
-
import { Fragment as Fragment6, jsx as jsx55, jsxs as
|
|
6257
|
+
import { Fragment as Fragment6, jsx as jsx55, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
6169
6258
|
function StudioOverlay({
|
|
6170
6259
|
captureTargetRef,
|
|
6171
6260
|
app,
|
|
@@ -6196,28 +6285,31 @@ function StudioOverlay({
|
|
|
6196
6285
|
}) {
|
|
6197
6286
|
const theme = useTheme();
|
|
6198
6287
|
const { width } = useWindowDimensions4();
|
|
6199
|
-
const [sheetOpen, setSheetOpen] =
|
|
6200
|
-
const [activePage, setActivePage] =
|
|
6201
|
-
const [drawing, setDrawing] =
|
|
6202
|
-
const [chatAttachments, setChatAttachments] =
|
|
6203
|
-
const [commentsAppId, setCommentsAppId] =
|
|
6204
|
-
const [commentsCount, setCommentsCount] =
|
|
6205
|
-
const [confirmMrId, setConfirmMrId] =
|
|
6206
|
-
const confirmMr =
|
|
6288
|
+
const [sheetOpen, setSheetOpen] = React38.useState(false);
|
|
6289
|
+
const [activePage, setActivePage] = React38.useState("preview");
|
|
6290
|
+
const [drawing, setDrawing] = React38.useState(false);
|
|
6291
|
+
const [chatAttachments, setChatAttachments] = React38.useState([]);
|
|
6292
|
+
const [commentsAppId, setCommentsAppId] = React38.useState(null);
|
|
6293
|
+
const [commentsCount, setCommentsCount] = React38.useState(null);
|
|
6294
|
+
const [confirmMrId, setConfirmMrId] = React38.useState(null);
|
|
6295
|
+
const confirmMr = React38.useMemo(
|
|
6207
6296
|
() => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
|
|
6208
6297
|
[confirmMrId, incomingMergeRequests]
|
|
6209
6298
|
);
|
|
6210
|
-
const
|
|
6211
|
-
setSheetOpen(
|
|
6212
|
-
Keyboard5.dismiss();
|
|
6299
|
+
const handleSheetOpenChange = React38.useCallback((open) => {
|
|
6300
|
+
setSheetOpen(open);
|
|
6301
|
+
if (!open) Keyboard5.dismiss();
|
|
6213
6302
|
}, []);
|
|
6214
|
-
const
|
|
6215
|
-
|
|
6303
|
+
const closeSheet = React38.useCallback(() => {
|
|
6304
|
+
handleSheetOpenChange(false);
|
|
6305
|
+
}, [handleSheetOpenChange]);
|
|
6306
|
+
const openSheet = React38.useCallback(() => setSheetOpen(true), []);
|
|
6307
|
+
const goToChat = React38.useCallback(() => {
|
|
6216
6308
|
setActivePage("chat");
|
|
6217
6309
|
openSheet();
|
|
6218
6310
|
}, [openSheet]);
|
|
6219
|
-
const backToPreview =
|
|
6220
|
-
if (
|
|
6311
|
+
const backToPreview = React38.useCallback(() => {
|
|
6312
|
+
if (Platform8.OS !== "ios") {
|
|
6221
6313
|
Keyboard5.dismiss();
|
|
6222
6314
|
setActivePage("preview");
|
|
6223
6315
|
return;
|
|
@@ -6234,11 +6326,11 @@ function StudioOverlay({
|
|
|
6234
6326
|
const t = setTimeout(finalize, 350);
|
|
6235
6327
|
Keyboard5.dismiss();
|
|
6236
6328
|
}, []);
|
|
6237
|
-
const startDraw =
|
|
6329
|
+
const startDraw = React38.useCallback(() => {
|
|
6238
6330
|
setDrawing(true);
|
|
6239
6331
|
closeSheet();
|
|
6240
6332
|
}, [closeSheet]);
|
|
6241
|
-
const handleDrawCapture =
|
|
6333
|
+
const handleDrawCapture = React38.useCallback(
|
|
6242
6334
|
(dataUrl) => {
|
|
6243
6335
|
setChatAttachments((prev) => [...prev, dataUrl]);
|
|
6244
6336
|
setDrawing(false);
|
|
@@ -6247,7 +6339,7 @@ function StudioOverlay({
|
|
|
6247
6339
|
},
|
|
6248
6340
|
[openSheet]
|
|
6249
6341
|
);
|
|
6250
|
-
const toggleSheet =
|
|
6342
|
+
const toggleSheet = React38.useCallback(async () => {
|
|
6251
6343
|
if (!sheetOpen) {
|
|
6252
6344
|
const shouldExitTest = Boolean(testingMrId) || isTesting;
|
|
6253
6345
|
if (shouldExitTest) {
|
|
@@ -6259,7 +6351,7 @@ function StudioOverlay({
|
|
|
6259
6351
|
closeSheet();
|
|
6260
6352
|
}
|
|
6261
6353
|
}, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
|
|
6262
|
-
const handleTestMr =
|
|
6354
|
+
const handleTestMr = React38.useCallback(
|
|
6263
6355
|
async (mr) => {
|
|
6264
6356
|
if (!onTestMr) return;
|
|
6265
6357
|
await onTestMr(mr);
|
|
@@ -6267,9 +6359,9 @@ function StudioOverlay({
|
|
|
6267
6359
|
},
|
|
6268
6360
|
[closeSheet, onTestMr]
|
|
6269
6361
|
);
|
|
6270
|
-
return /* @__PURE__ */
|
|
6362
|
+
return /* @__PURE__ */ jsxs34(Fragment6, { children: [
|
|
6271
6363
|
/* @__PURE__ */ jsx55(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
|
|
6272
|
-
/* @__PURE__ */ jsx55(StudioBottomSheet, { open: sheetOpen, onOpenChange:
|
|
6364
|
+
/* @__PURE__ */ jsx55(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ jsx55(
|
|
6273
6365
|
StudioSheetPager,
|
|
6274
6366
|
{
|
|
6275
6367
|
activePage,
|
|
@@ -6369,7 +6461,7 @@ function StudioOverlay({
|
|
|
6369
6461
|
}
|
|
6370
6462
|
|
|
6371
6463
|
// src/studio/ComergeStudio.tsx
|
|
6372
|
-
import { jsx as jsx56, jsxs as
|
|
6464
|
+
import { jsx as jsx56, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
6373
6465
|
function ComergeStudio({
|
|
6374
6466
|
appId,
|
|
6375
6467
|
apiKey,
|
|
@@ -6377,16 +6469,16 @@ function ComergeStudio({
|
|
|
6377
6469
|
onNavigateHome,
|
|
6378
6470
|
style
|
|
6379
6471
|
}) {
|
|
6380
|
-
const [activeAppId, setActiveAppId] =
|
|
6381
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
6382
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
6383
|
-
const platform =
|
|
6384
|
-
|
|
6472
|
+
const [activeAppId, setActiveAppId] = React39.useState(appId);
|
|
6473
|
+
const [runtimeAppId, setRuntimeAppId] = React39.useState(appId);
|
|
6474
|
+
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React39.useState(null);
|
|
6475
|
+
const platform = React39.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
|
|
6476
|
+
React39.useEffect(() => {
|
|
6385
6477
|
setActiveAppId(appId);
|
|
6386
6478
|
setRuntimeAppId(appId);
|
|
6387
6479
|
setPendingRuntimeTargetAppId(null);
|
|
6388
6480
|
}, [appId]);
|
|
6389
|
-
const captureTargetRef =
|
|
6481
|
+
const captureTargetRef = React39.useRef(null);
|
|
6390
6482
|
return /* @__PURE__ */ jsx56(StudioBootstrap, { apiKey, children: ({ userId }) => /* @__PURE__ */ jsx56(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx56(
|
|
6391
6483
|
ComergeStudioInner,
|
|
6392
6484
|
{
|
|
@@ -6422,11 +6514,11 @@ function ComergeStudioInner({
|
|
|
6422
6514
|
const { app, loading: appLoading } = useApp(activeAppId);
|
|
6423
6515
|
const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
|
|
6424
6516
|
const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
|
|
6425
|
-
const sawEditingOnPendingTargetRef =
|
|
6426
|
-
|
|
6517
|
+
const sawEditingOnPendingTargetRef = React39.useRef(false);
|
|
6518
|
+
React39.useEffect(() => {
|
|
6427
6519
|
sawEditingOnPendingTargetRef.current = false;
|
|
6428
6520
|
}, [pendingRuntimeTargetAppId]);
|
|
6429
|
-
|
|
6521
|
+
React39.useEffect(() => {
|
|
6430
6522
|
if (!pendingRuntimeTargetAppId) return;
|
|
6431
6523
|
if (activeAppId !== pendingRuntimeTargetAppId) return;
|
|
6432
6524
|
if ((app == null ? void 0 : app.status) === "editing") {
|
|
@@ -6446,10 +6538,10 @@ function ComergeStudioInner({
|
|
|
6446
6538
|
const threadId = (app == null ? void 0 : app.threadId) ?? "";
|
|
6447
6539
|
const thread = useThreadMessages(threadId);
|
|
6448
6540
|
const mergeRequests = useMergeRequests({ appId: activeAppId });
|
|
6449
|
-
const hasOpenOutgoingMr =
|
|
6541
|
+
const hasOpenOutgoingMr = React39.useMemo(() => {
|
|
6450
6542
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
6451
6543
|
}, [mergeRequests.lists.outgoing]);
|
|
6452
|
-
const incomingReviewMrs =
|
|
6544
|
+
const incomingReviewMrs = React39.useMemo(() => {
|
|
6453
6545
|
if (!userId) return mergeRequests.lists.incoming;
|
|
6454
6546
|
return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
|
|
6455
6547
|
}, [mergeRequests.lists.incoming, userId]);
|
|
@@ -6471,16 +6563,16 @@ function ComergeStudioInner({
|
|
|
6471
6563
|
uploadAttachments: uploader.uploadBase64Images
|
|
6472
6564
|
});
|
|
6473
6565
|
const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
|
|
6474
|
-
const [processingMrId, setProcessingMrId] =
|
|
6475
|
-
const [testingMrId, setTestingMrId] =
|
|
6476
|
-
const chatShowTypingIndicator =
|
|
6566
|
+
const [processingMrId, setProcessingMrId] = React39.useState(null);
|
|
6567
|
+
const [testingMrId, setTestingMrId] = React39.useState(null);
|
|
6568
|
+
const chatShowTypingIndicator = React39.useMemo(() => {
|
|
6477
6569
|
var _a;
|
|
6478
6570
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
6479
6571
|
const last = thread.raw[thread.raw.length - 1];
|
|
6480
6572
|
const payloadType = typeof ((_a = last.payload) == null ? void 0 : _a.type) === "string" ? String(last.payload.type) : void 0;
|
|
6481
6573
|
return payloadType !== "outcome";
|
|
6482
6574
|
}, [thread.raw]);
|
|
6483
|
-
return /* @__PURE__ */ jsx56(View45, { style: [{ flex: 1 }, style], children: /* @__PURE__ */
|
|
6575
|
+
return /* @__PURE__ */ jsx56(View45, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs35(View45, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
|
|
6484
6576
|
/* @__PURE__ */ jsx56(RuntimeRenderer, { appKey, bundlePath: bundle.bundlePath, renderToken: bundle.renderToken }),
|
|
6485
6577
|
/* @__PURE__ */ jsx56(
|
|
6486
6578
|
StudioOverlay,
|