@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 CHANGED
@@ -36,8 +36,8 @@ __export(index_exports, {
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/studio/ComergeStudio.tsx
39
- var React38 = __toESM(require("react"));
40
- var import_react_native52 = require("react-native");
39
+ var React39 = __toESM(require("react"));
40
+ var import_react_native53 = require("react-native");
41
41
  var import_bottom_sheet6 = require("@gorhom/bottom-sheet");
42
42
 
43
43
  // src/studio/bootstrap/StudioBootstrap.tsx
@@ -393,7 +393,7 @@ function StudioBootstrap({ children, fallback, renderError, apiKey }) {
393
393
  }
394
394
 
395
395
  // src/studio/hooks/useApp.ts
396
- var React2 = __toESM(require("react"));
396
+ var React3 = __toESM(require("react"));
397
397
 
398
398
  // src/core/services/http/index.ts
399
399
  var import_axios2 = __toESM(require("axios"));
@@ -692,13 +692,40 @@ var AppsRepositoryImpl = class extends BaseRepository {
692
692
  };
693
693
  var appsRepository = new AppsRepositoryImpl(appsRemoteDataSource);
694
694
 
695
+ // src/studio/hooks/useForegroundSignal.ts
696
+ var React2 = __toESM(require("react"));
697
+ var import_react_native4 = require("react-native");
698
+ function useForegroundSignal(enabled = true) {
699
+ const [signal, setSignal] = React2.useState(0);
700
+ const lastStateRef = React2.useRef(import_react_native4.AppState.currentState);
701
+ React2.useEffect(() => {
702
+ if (!enabled) return;
703
+ const sub = import_react_native4.AppState.addEventListener("change", (nextState) => {
704
+ var _a, _b;
705
+ const prevState = lastStateRef.current;
706
+ lastStateRef.current = nextState;
707
+ const didResume = (prevState === "background" || prevState === "inactive") && nextState === "active";
708
+ if (!didResume) return;
709
+ try {
710
+ const supabase = getSupabaseClient();
711
+ (_b = (_a = supabase == null ? void 0 : supabase.realtime) == null ? void 0 : _a.connect) == null ? void 0 : _b.call(_a);
712
+ } catch {
713
+ }
714
+ setSignal((s) => s + 1);
715
+ });
716
+ return () => sub.remove();
717
+ }, [enabled]);
718
+ return signal;
719
+ }
720
+
695
721
  // src/studio/hooks/useApp.ts
696
722
  function useApp(appId, options) {
697
723
  const enabled = (options == null ? void 0 : options.enabled) ?? true;
698
- const [app, setApp] = React2.useState(null);
699
- const [loading, setLoading] = React2.useState(false);
700
- const [error, setError] = React2.useState(null);
701
- const mergeApp = React2.useCallback((prev, next) => {
724
+ const [app, setApp] = React3.useState(null);
725
+ const [loading, setLoading] = React3.useState(false);
726
+ const [error, setError] = React3.useState(null);
727
+ const foregroundSignal = useForegroundSignal(enabled && Boolean(appId));
728
+ const mergeApp = React3.useCallback((prev, next) => {
702
729
  const merged = {
703
730
  ...prev ?? {},
704
731
  ...next,
@@ -707,7 +734,7 @@ function useApp(appId, options) {
707
734
  };
708
735
  return merged;
709
736
  }, []);
710
- const fetchOnce = React2.useCallback(async () => {
737
+ const fetchOnce = React3.useCallback(async () => {
711
738
  if (!enabled) return;
712
739
  if (!appId) return;
713
740
  setLoading(true);
@@ -722,34 +749,37 @@ function useApp(appId, options) {
722
749
  setLoading(false);
723
750
  }
724
751
  }, [appId, enabled]);
725
- React2.useEffect(() => {
752
+ React3.useEffect(() => {
726
753
  if (!enabled) return;
727
754
  void fetchOnce();
728
755
  }, [enabled, fetchOnce]);
729
- React2.useEffect(() => {
756
+ React3.useEffect(() => {
730
757
  if (!enabled) return;
731
758
  if (!appId) return;
732
759
  const unsubscribe = appsRepository.subscribeApp(appId, {
733
760
  onInsert: (a) => {
734
- console.log("[useApp] onInsert", a);
735
761
  setApp((prev) => mergeApp(prev, a));
736
762
  },
737
763
  onUpdate: (a) => {
738
- console.log("[useApp] onUpdate", a);
739
764
  setApp((prev) => mergeApp(prev, a));
740
765
  },
741
766
  onDelete: () => {
742
- console.log("[useApp] onDelete");
743
767
  setApp(null);
744
768
  }
745
769
  });
746
770
  return unsubscribe;
747
- }, [appId, enabled, mergeApp]);
771
+ }, [appId, enabled, mergeApp, foregroundSignal]);
772
+ React3.useEffect(() => {
773
+ if (!enabled) return;
774
+ if (!appId) return;
775
+ if (foregroundSignal <= 0) return;
776
+ void fetchOnce();
777
+ }, [appId, enabled, fetchOnce, foregroundSignal]);
748
778
  return { app, loading, error, refetch: fetchOnce };
749
779
  }
750
780
 
751
781
  // src/studio/hooks/useThreadMessages.ts
752
- var React3 = __toESM(require("react"));
782
+ var React4 = __toESM(require("react"));
753
783
 
754
784
  // src/data/messages/remote.ts
755
785
  var MessagesRemoteDataSourceImpl = class extends BaseRemote {
@@ -850,44 +880,59 @@ function mapMessageToChatMessage(m) {
850
880
  };
851
881
  }
852
882
  function useThreadMessages(threadId) {
853
- const [raw, setRaw] = React3.useState([]);
854
- const [loading, setLoading] = React3.useState(false);
855
- const [error, setError] = React3.useState(null);
856
- const refetch = React3.useCallback(async () => {
883
+ const [raw, setRaw] = React4.useState([]);
884
+ const [loading, setLoading] = React4.useState(false);
885
+ const [error, setError] = React4.useState(null);
886
+ const activeRequestIdRef = React4.useRef(0);
887
+ const foregroundSignal = useForegroundSignal(Boolean(threadId));
888
+ const upsertSorted = React4.useCallback((prev, m) => {
889
+ const next = prev.some((x) => x.id === m.id) ? prev.map((x) => x.id === m.id ? m : x) : [...prev, m];
890
+ next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
891
+ return next;
892
+ }, []);
893
+ const refetch = React4.useCallback(async () => {
857
894
  if (!threadId) {
858
895
  setRaw([]);
859
896
  return;
860
897
  }
898
+ const requestId = ++activeRequestIdRef.current;
861
899
  setLoading(true);
862
900
  setError(null);
863
901
  try {
864
902
  const list = await messagesRepository.list(threadId);
865
- setRaw(list);
903
+ if (activeRequestIdRef.current !== requestId) return;
904
+ setRaw([...list].sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt))));
866
905
  } catch (e) {
906
+ if (activeRequestIdRef.current !== requestId) return;
867
907
  setError(e instanceof Error ? e : new Error(String(e)));
868
908
  setRaw([]);
869
909
  } finally {
870
- setLoading(false);
910
+ if (activeRequestIdRef.current === requestId) setLoading(false);
871
911
  }
872
912
  }, [threadId]);
873
- React3.useEffect(() => {
913
+ React4.useEffect(() => {
874
914
  void refetch();
875
915
  }, [refetch]);
876
- React3.useEffect(() => {
916
+ React4.useEffect(() => {
877
917
  if (!threadId) return;
878
918
  const unsubscribe = messagesRepository.subscribeThread(threadId, {
879
- onInsert: (m) => setRaw((prev) => [...prev, m]),
880
- onUpdate: (m) => setRaw((prev) => prev.map((x) => x.id === m.id ? m : x)),
919
+ onInsert: (m) => setRaw((prev) => upsertSorted(prev, m)),
920
+ onUpdate: (m) => setRaw((prev) => upsertSorted(prev, m)),
881
921
  onDelete: (m) => setRaw((prev) => prev.filter((x) => x.id !== m.id))
882
922
  });
883
923
  return unsubscribe;
884
- }, [threadId]);
885
- const messages = React3.useMemo(() => raw.map(mapMessageToChatMessage), [raw]);
924
+ }, [threadId, upsertSorted, foregroundSignal]);
925
+ React4.useEffect(() => {
926
+ if (!threadId) return;
927
+ if (foregroundSignal <= 0) return;
928
+ void refetch();
929
+ }, [foregroundSignal, refetch, threadId]);
930
+ const messages = React4.useMemo(() => raw.map(mapMessageToChatMessage), [raw]);
886
931
  return { raw, messages, loading, error, refetch };
887
932
  }
888
933
 
889
934
  // src/studio/hooks/useBundleManager.ts
890
- var React4 = __toESM(require("react"));
935
+ var React5 = __toESM(require("react"));
891
936
  var FileSystem = __toESM(require("expo-file-system/legacy"));
892
937
 
893
938
  // src/data/apps/bundles/remote.ts
@@ -1060,19 +1105,19 @@ function useBundleManager({
1060
1105
  platform,
1061
1106
  canRequestLatest = true
1062
1107
  }) {
1063
- const [bundlePath, setBundlePath] = React4.useState(null);
1064
- const [renderToken, setRenderToken] = React4.useState(0);
1065
- const [loading, setLoading] = React4.useState(false);
1066
- const [statusLabel, setStatusLabel] = React4.useState(null);
1067
- const [error, setError] = React4.useState(null);
1068
- const [isTesting, setIsTesting] = React4.useState(false);
1069
- const baseRef = React4.useRef(base);
1108
+ const [bundlePath, setBundlePath] = React5.useState(null);
1109
+ const [renderToken, setRenderToken] = React5.useState(0);
1110
+ const [loading, setLoading] = React5.useState(false);
1111
+ const [statusLabel, setStatusLabel] = React5.useState(null);
1112
+ const [error, setError] = React5.useState(null);
1113
+ const [isTesting, setIsTesting] = React5.useState(false);
1114
+ const baseRef = React5.useRef(base);
1070
1115
  baseRef.current = base;
1071
- const baseOpIdRef = React4.useRef(0);
1072
- const testOpIdRef = React4.useRef(0);
1073
- const activeLoadModeRef = React4.useRef(null);
1074
- const canRequestLatestRef = React4.useRef(canRequestLatest);
1075
- React4.useEffect(() => {
1116
+ const baseOpIdRef = React5.useRef(0);
1117
+ const testOpIdRef = React5.useRef(0);
1118
+ const activeLoadModeRef = React5.useRef(null);
1119
+ const canRequestLatestRef = React5.useRef(canRequestLatest);
1120
+ React5.useEffect(() => {
1076
1121
  canRequestLatestRef.current = canRequestLatest;
1077
1122
  if (!canRequestLatest) {
1078
1123
  baseOpIdRef.current += 1;
@@ -1083,11 +1128,11 @@ function useBundleManager({
1083
1128
  }
1084
1129
  }
1085
1130
  }, [canRequestLatest]);
1086
- const lastBaseBundlePathRef = React4.useRef(null);
1087
- const lastBaseFingerprintRef = React4.useRef(null);
1088
- const initialHydratedBaseFromDiskRef = React4.useRef(false);
1089
- const hasCompletedFirstNetworkBaseLoadRef = React4.useRef(false);
1090
- const hydrateBaseFromDisk = React4.useCallback(
1131
+ const lastBaseBundlePathRef = React5.useRef(null);
1132
+ const lastBaseFingerprintRef = React5.useRef(null);
1133
+ const initialHydratedBaseFromDiskRef = React5.useRef(false);
1134
+ const hasCompletedFirstNetworkBaseLoadRef = React5.useRef(false);
1135
+ const hydrateBaseFromDisk = React5.useCallback(
1091
1136
  async (appId, reason) => {
1092
1137
  try {
1093
1138
  const dir = bundlesCacheDir();
@@ -1112,13 +1157,13 @@ function useBundleManager({
1112
1157
  },
1113
1158
  [platform]
1114
1159
  );
1115
- React4.useEffect(() => {
1160
+ React5.useEffect(() => {
1116
1161
  if (!base.appId) return;
1117
1162
  initialHydratedBaseFromDiskRef.current = false;
1118
1163
  hasCompletedFirstNetworkBaseLoadRef.current = false;
1119
1164
  void hydrateBaseFromDisk(base.appId, "initial");
1120
1165
  }, [base.appId, platform, hydrateBaseFromDisk]);
1121
- const activateCachedBase = React4.useCallback(
1166
+ const activateCachedBase = React5.useCallback(
1122
1167
  async (appId) => {
1123
1168
  setIsTesting(false);
1124
1169
  setStatusLabel(null);
@@ -1132,7 +1177,7 @@ function useBundleManager({
1132
1177
  },
1133
1178
  [hydrateBaseFromDisk]
1134
1179
  );
1135
- const load = React4.useCallback(async (src, mode) => {
1180
+ const load = React5.useCallback(async (src, mode) => {
1136
1181
  if (!src.appId) return;
1137
1182
  const canRequestLatest2 = canRequestLatestRef.current;
1138
1183
  if (mode === "base" && !canRequestLatest2) {
@@ -1187,13 +1232,13 @@ function useBundleManager({
1187
1232
  if (activeLoadModeRef.current === mode) activeLoadModeRef.current = null;
1188
1233
  }
1189
1234
  }, [activateCachedBase, platform]);
1190
- const loadBase = React4.useCallback(async () => {
1235
+ const loadBase = React5.useCallback(async () => {
1191
1236
  await load(baseRef.current, "base");
1192
1237
  }, [load]);
1193
- const loadTest = React4.useCallback(async (src) => {
1238
+ const loadTest = React5.useCallback(async (src) => {
1194
1239
  await load(src, "test");
1195
1240
  }, [load]);
1196
- const restoreBase = React4.useCallback(async () => {
1241
+ const restoreBase = React5.useCallback(async () => {
1197
1242
  const src = baseRef.current;
1198
1243
  if (!src.appId) return;
1199
1244
  await activateCachedBase(src.appId);
@@ -1201,7 +1246,7 @@ function useBundleManager({
1201
1246
  await load(src, "base");
1202
1247
  }
1203
1248
  }, [activateCachedBase, load]);
1204
- React4.useEffect(() => {
1249
+ React5.useEffect(() => {
1205
1250
  if (!canRequestLatest) return;
1206
1251
  void loadBase();
1207
1252
  }, [base.appId, base.commitId, platform, canRequestLatest, loadBase]);
@@ -1209,7 +1254,7 @@ function useBundleManager({
1209
1254
  }
1210
1255
 
1211
1256
  // src/studio/hooks/useMergeRequests.ts
1212
- var React5 = __toESM(require("react"));
1257
+ var React6 = __toESM(require("react"));
1213
1258
 
1214
1259
  // src/data/merge-requests/remote.ts
1215
1260
  var MergeRequestsRemoteDataSourceImpl = class extends BaseRemote {
@@ -1355,12 +1400,12 @@ function toUiStatus(status) {
1355
1400
  }
1356
1401
  function useMergeRequests(params) {
1357
1402
  const { appId } = params;
1358
- const [incoming, setIncoming] = React5.useState([]);
1359
- const [outgoing, setOutgoing] = React5.useState([]);
1360
- const [loading, setLoading] = React5.useState(false);
1361
- const [error, setError] = React5.useState(null);
1362
- const [creatorStatsById, setCreatorStatsById] = React5.useState({});
1363
- const pollUntilMerged = React5.useCallback(async (mrId) => {
1403
+ const [incoming, setIncoming] = React6.useState([]);
1404
+ const [outgoing, setOutgoing] = React6.useState([]);
1405
+ const [loading, setLoading] = React6.useState(false);
1406
+ const [error, setError] = React6.useState(null);
1407
+ const [creatorStatsById, setCreatorStatsById] = React6.useState({});
1408
+ const pollUntilMerged = React6.useCallback(async (mrId) => {
1364
1409
  const startedAt = Date.now();
1365
1410
  const timeoutMs = 2 * 60 * 1e3;
1366
1411
  for (; ; ) {
@@ -1370,7 +1415,7 @@ function useMergeRequests(params) {
1370
1415
  await new Promise((r) => setTimeout(r, 1500));
1371
1416
  }
1372
1417
  }, []);
1373
- const refresh = React5.useCallback(async () => {
1418
+ const refresh = React6.useCallback(async () => {
1374
1419
  if (!appId) {
1375
1420
  setIncoming([]);
1376
1421
  setOutgoing([]);
@@ -1409,27 +1454,27 @@ function useMergeRequests(params) {
1409
1454
  setLoading(false);
1410
1455
  }
1411
1456
  }, [appId]);
1412
- React5.useEffect(() => {
1457
+ React6.useEffect(() => {
1413
1458
  void refresh();
1414
1459
  }, [refresh]);
1415
- const openMergeRequest = React5.useCallback(async (sourceAppId) => {
1460
+ const openMergeRequest = React6.useCallback(async (sourceAppId) => {
1416
1461
  const mr = await mergeRequestsRepository.open({ sourceAppId });
1417
1462
  await refresh();
1418
1463
  return mr;
1419
1464
  }, [refresh]);
1420
- const approve = React5.useCallback(async (mrId) => {
1465
+ const approve = React6.useCallback(async (mrId) => {
1421
1466
  const mr = await mergeRequestsRepository.update(mrId, { status: "approved" });
1422
1467
  await refresh();
1423
1468
  const merged = await pollUntilMerged(mrId);
1424
1469
  await refresh();
1425
1470
  return merged ?? mr;
1426
1471
  }, [pollUntilMerged, refresh]);
1427
- const reject = React5.useCallback(async (mrId) => {
1472
+ const reject = React6.useCallback(async (mrId) => {
1428
1473
  const mr = await mergeRequestsRepository.update(mrId, { status: "rejected" });
1429
1474
  await refresh();
1430
1475
  return mr;
1431
1476
  }, [refresh]);
1432
- const toSummary = React5.useCallback((mr) => {
1477
+ const toSummary = React6.useCallback((mr) => {
1433
1478
  const stats = creatorStatsById[mr.createdBy];
1434
1479
  return {
1435
1480
  id: mr.id,
@@ -1445,7 +1490,7 @@ function useMergeRequests(params) {
1445
1490
  updatedAt: mr.updatedAt
1446
1491
  };
1447
1492
  }, [creatorStatsById]);
1448
- const byId = React5.useMemo(() => {
1493
+ const byId = React6.useMemo(() => {
1449
1494
  const all = [...incoming, ...outgoing];
1450
1495
  const map = {};
1451
1496
  for (const mr of all) map[mr.id] = mr;
@@ -1463,7 +1508,7 @@ function useMergeRequests(params) {
1463
1508
  }
1464
1509
 
1465
1510
  // src/studio/hooks/useAttachmentUpload.ts
1466
- var React6 = __toESM(require("react"));
1511
+ var React7 = __toESM(require("react"));
1467
1512
 
1468
1513
  // src/data/attachment/remote.ts
1469
1514
  var AttachmentRemoteDataSourceImpl = class extends BaseRemote {
@@ -1504,9 +1549,9 @@ var attachmentRepository = new AttachmentRepositoryImpl(
1504
1549
 
1505
1550
  // src/studio/hooks/useAttachmentUpload.ts
1506
1551
  function useAttachmentUpload() {
1507
- const [uploading, setUploading] = React6.useState(false);
1508
- const [error, setError] = React6.useState(null);
1509
- const uploadBase64Images = React6.useCallback(async ({ threadId, appId, dataUrls }) => {
1552
+ const [uploading, setUploading] = React7.useState(false);
1553
+ const [error, setError] = React7.useState(null);
1554
+ const uploadBase64Images = React7.useCallback(async ({ threadId, appId, dataUrls }) => {
1510
1555
  if (!threadId || !appId) return [];
1511
1556
  if (!dataUrls || dataUrls.length === 0) return [];
1512
1557
  setUploading(true);
@@ -1540,7 +1585,7 @@ function useAttachmentUpload() {
1540
1585
  }
1541
1586
 
1542
1587
  // src/studio/hooks/useStudioActions.ts
1543
- var React7 = __toESM(require("react"));
1588
+ var React8 = __toESM(require("react"));
1544
1589
 
1545
1590
  // src/data/agent/remote.ts
1546
1591
  var AgentRemoteDataSourceImpl = class extends BaseRemote {
@@ -1579,12 +1624,12 @@ function useStudioActions({
1579
1624
  onForkedApp,
1580
1625
  uploadAttachments
1581
1626
  }) {
1582
- const [forking, setForking] = React7.useState(false);
1583
- const [sending, setSending] = React7.useState(false);
1584
- const [error, setError] = React7.useState(null);
1627
+ const [forking, setForking] = React8.useState(false);
1628
+ const [sending, setSending] = React8.useState(false);
1629
+ const [error, setError] = React8.useState(null);
1585
1630
  const isOwner = Boolean(userId && (app == null ? void 0 : app.createdBy) && userId === app.createdBy);
1586
1631
  const shouldForkOnEdit = Boolean(userId && app && app.createdBy !== userId);
1587
- const sendEdit = React7.useCallback(
1632
+ const sendEdit = React8.useCallback(
1588
1633
  async ({ prompt, attachments }) => {
1589
1634
  if (!userId || !app) return;
1590
1635
  if (!prompt.trim()) return;
@@ -1647,14 +1692,14 @@ function hasNoOutcomeAfterLastHuman(messages) {
1647
1692
  }
1648
1693
 
1649
1694
  // src/studio/ui/RuntimeRenderer.tsx
1650
- var import_react_native4 = require("react-native");
1695
+ var import_react_native5 = require("react-native");
1651
1696
  var import_runtime = require("@comergehq/runtime");
1652
1697
  var import_jsx_runtime3 = require("react/jsx-runtime");
1653
1698
  function RuntimeRenderer({ appKey, bundlePath, renderToken, style }) {
1654
1699
  if (!bundlePath) {
1655
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [{ flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { variant: "bodyMuted", children: "Preparing app\u2026" }) });
1700
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.View, { style: [{ flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { variant: "bodyMuted", children: "Preparing app\u2026" }) });
1656
1701
  }
1657
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1702
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1658
1703
  import_runtime.ComergeRuntimeRenderer,
1659
1704
  {
1660
1705
  appKey,
@@ -1666,17 +1711,17 @@ function RuntimeRenderer({ appKey, bundlePath, renderToken, style }) {
1666
1711
  }
1667
1712
 
1668
1713
  // src/studio/ui/StudioOverlay.tsx
1669
- var React37 = __toESM(require("react"));
1670
- var import_react_native51 = require("react-native");
1714
+ var React38 = __toESM(require("react"));
1715
+ var import_react_native52 = require("react-native");
1671
1716
 
1672
1717
  // src/components/studio-sheet/StudioBottomSheet.tsx
1673
- var React8 = __toESM(require("react"));
1674
- var import_react_native6 = require("react-native");
1718
+ var React9 = __toESM(require("react"));
1719
+ var import_react_native7 = require("react-native");
1675
1720
  var import_bottom_sheet = __toESM(require("@gorhom/bottom-sheet"));
1676
1721
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
1677
1722
 
1678
1723
  // src/components/studio-sheet/StudioSheetBackground.tsx
1679
- var import_react_native5 = require("react-native");
1724
+ var import_react_native6 = require("react-native");
1680
1725
  var import_liquid_glass = require("@callstack/liquid-glass");
1681
1726
  var import_jsx_runtime4 = require("react/jsx-runtime");
1682
1727
  function StudioSheetBackground({
@@ -1684,7 +1729,7 @@ function StudioSheetBackground({
1684
1729
  renderBackground
1685
1730
  }) {
1686
1731
  const theme = useTheme();
1687
- const radius = import_react_native5.Platform.OS === "ios" ? 39 : 16;
1732
+ const radius = import_react_native6.Platform.OS === "ios" ? 39 : 16;
1688
1733
  const fallbackBgColor = theme.scheme === "dark" ? "rgba(11, 8, 15, 0.85)" : "rgba(255, 255, 255, 0.85)";
1689
1734
  const secondaryBgBaseColor = theme.scheme === "dark" ? "rgb(24, 24, 27)" : "rgb(173, 173, 173)";
1690
1735
  const containerStyle = {
@@ -1705,7 +1750,7 @@ function StudioSheetBackground({
1705
1750
  }
1706
1751
  ),
1707
1752
  import_liquid_glass.isLiquidGlassSupported && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1708
- import_react_native5.View,
1753
+ import_react_native6.View,
1709
1754
  {
1710
1755
  style: [
1711
1756
  containerStyle,
@@ -1738,19 +1783,31 @@ function StudioBottomSheet({
1738
1783
  }) {
1739
1784
  const theme = useTheme();
1740
1785
  const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
1741
- const internalSheetRef = React8.useRef(null);
1786
+ const internalSheetRef = React9.useRef(null);
1742
1787
  const resolvedSheetRef = sheetRef ?? internalSheetRef;
1743
- React8.useEffect(() => {
1744
- if (import_react_native6.Platform.OS !== "ios") return;
1745
- const sub = import_react_native6.Keyboard.addListener("keyboardDidHide", () => {
1788
+ const currentIndexRef = React9.useRef(open ? snapPoints.length - 1 : -1);
1789
+ const lastAppStateRef = React9.useRef(import_react_native7.AppState.currentState);
1790
+ React9.useEffect(() => {
1791
+ const sub = import_react_native7.AppState.addEventListener("change", (state) => {
1792
+ const prev = lastAppStateRef.current;
1793
+ lastAppStateRef.current = state;
1794
+ if (state === "background" || state === "inactive") {
1795
+ import_react_native7.Keyboard.dismiss();
1796
+ return;
1797
+ }
1798
+ if (state !== "active") return;
1746
1799
  const sheet = resolvedSheetRef.current;
1747
- if (!sheet || !open) return;
1748
- const targetIndex = snapPoints.length - 1;
1749
- setTimeout(() => sheet.snapToIndex(targetIndex), 10);
1800
+ if (!sheet) return;
1801
+ const idx = currentIndexRef.current;
1802
+ if (open && idx >= 0) {
1803
+ import_react_native7.Keyboard.dismiss();
1804
+ requestAnimationFrame(() => sheet.snapToIndex(idx));
1805
+ setTimeout(() => sheet.snapToIndex(idx), 120);
1806
+ }
1750
1807
  });
1751
1808
  return () => sub.remove();
1752
- }, [open, resolvedSheetRef, snapPoints.length]);
1753
- React8.useEffect(() => {
1809
+ }, [open, resolvedSheetRef]);
1810
+ React9.useEffect(() => {
1754
1811
  const sheet = resolvedSheetRef.current;
1755
1812
  if (!sheet) return;
1756
1813
  if (open) {
@@ -1759,8 +1816,9 @@ function StudioBottomSheet({
1759
1816
  sheet.close();
1760
1817
  }
1761
1818
  }, [open, resolvedSheetRef, snapPoints.length]);
1762
- const handleChange = React8.useCallback(
1819
+ const handleChange = React9.useCallback(
1763
1820
  (index) => {
1821
+ currentIndexRef.current = index;
1764
1822
  onOpenChange == null ? void 0 : onOpenChange(index >= 0);
1765
1823
  },
1766
1824
  [onOpenChange]
@@ -1772,7 +1830,7 @@ function StudioBottomSheet({
1772
1830
  index: open ? snapPoints.length - 1 : -1,
1773
1831
  snapPoints,
1774
1832
  enablePanDownToClose: true,
1775
- keyboardBehavior: "extend",
1833
+ keyboardBehavior: "interactive",
1776
1834
  keyboardBlurBehavior: "restore",
1777
1835
  android_keyboardInputMode: "adjustResize",
1778
1836
  backgroundComponent: (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StudioSheetBackground, { ...props, renderBackground: background == null ? void 0 : background.renderBackground }),
@@ -1781,19 +1839,19 @@ function StudioBottomSheet({
1781
1839
  handleIndicatorStyle: { backgroundColor: theme.colors.handleIndicator },
1782
1840
  onChange: handleChange,
1783
1841
  ...bottomSheetProps,
1784
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: { flex: 1, overflow: "hidden" }, children })
1842
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native7.View, { style: { flex: 1, overflow: "hidden" }, children })
1785
1843
  }
1786
1844
  );
1787
1845
  }
1788
1846
 
1789
1847
  // src/components/studio-sheet/StudioSheetPager.tsx
1790
- var React9 = __toESM(require("react"));
1791
- var import_react_native7 = require("react-native");
1848
+ var React10 = __toESM(require("react"));
1849
+ var import_react_native8 = require("react-native");
1792
1850
  var import_jsx_runtime6 = require("react/jsx-runtime");
1793
1851
  function StudioSheetPager({ activePage, width, preview, chat, style }) {
1794
- const anim = React9.useRef(new import_react_native7.Animated.Value(activePage === "chat" ? 1 : 0)).current;
1795
- React9.useEffect(() => {
1796
- import_react_native7.Animated.spring(anim, {
1852
+ const anim = React10.useRef(new import_react_native8.Animated.Value(activePage === "chat" ? 1 : 0)).current;
1853
+ React10.useEffect(() => {
1854
+ import_react_native8.Animated.spring(anim, {
1797
1855
  toValue: activePage === "chat" ? 1 : 0,
1798
1856
  useNativeDriver: true,
1799
1857
  tension: 65,
@@ -1802,9 +1860,9 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1802
1860
  }, [activePage, anim]);
1803
1861
  const previewTranslateX = anim.interpolate({ inputRange: [0, 1], outputRange: [0, -width] });
1804
1862
  const chatTranslateX = anim.interpolate({ inputRange: [0, 1], outputRange: [width, 0] });
1805
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.Animated.View, { style: [{ flex: 1 }, style], children: [
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native8.Animated.View, { style: [{ flex: 1 }, style], children: [
1806
1864
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1807
- import_react_native7.Animated.View,
1865
+ import_react_native8.Animated.View,
1808
1866
  {
1809
1867
  style: [
1810
1868
  {
@@ -1821,7 +1879,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1821
1879
  }
1822
1880
  ),
1823
1881
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1824
- import_react_native7.Animated.View,
1882
+ import_react_native8.Animated.View,
1825
1883
  {
1826
1884
  style: [
1827
1885
  {
@@ -1842,7 +1900,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1842
1900
 
1843
1901
  // src/components/floating-draggable-button/FloatingDraggableButton.tsx
1844
1902
  var import_react = require("react");
1845
- var import_react_native8 = require("react-native");
1903
+ var import_react_native9 = require("react-native");
1846
1904
  var Haptics = __toESM(require("expo-haptics"));
1847
1905
  var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
1848
1906
  var import_liquid_glass2 = require("@callstack/liquid-glass");
@@ -1901,7 +1959,7 @@ function FloatingDraggableButton({
1901
1959
  backgroundColor
1902
1960
  }) {
1903
1961
  const theme = useTheme();
1904
- const { width, height } = (0, import_react_native8.useWindowDimensions)();
1962
+ const { width, height } = (0, import_react_native9.useWindowDimensions)();
1905
1963
  const isDanger = variant === "danger";
1906
1964
  const onPressRef = (0, import_react.useRef)(onPress);
1907
1965
  (0, import_react.useEffect)(() => {
@@ -2004,7 +2062,7 @@ function FloatingDraggableButton({
2004
2062
  }
2005
2063
  }, [forceShowTrigger, visible, animateIn]);
2006
2064
  const panResponder = (0, import_react.useRef)(
2007
- import_react_native8.PanResponder.create({
2065
+ import_react_native9.PanResponder.create({
2008
2066
  onStartShouldSetPanResponder: () => true,
2009
2067
  onMoveShouldSetPanResponder: () => true,
2010
2068
  onPanResponderGrant: () => {
@@ -2067,24 +2125,24 @@ function FloatingDraggableButton({
2067
2125
  interactive: true,
2068
2126
  effect: "clear",
2069
2127
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2070
- import_react_native8.Pressable,
2128
+ import_react_native9.Pressable,
2071
2129
  {
2072
2130
  onPress: () => {
2073
2131
  if (!disabled) animateOut();
2074
2132
  },
2075
2133
  style: styles.buttonInner,
2076
2134
  android_ripple: { color: "rgba(255, 255, 255, 0.3)", borderless: true },
2077
- children: children ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, {})
2135
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, {})
2078
2136
  }
2079
2137
  )
2080
2138
  }
2081
2139
  ) }),
2082
- badgeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles.badge, { backgroundColor: theme.colors.danger }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.Text, { style: [styles.badgeText, { color: theme.colors.onDanger }], children: badgeCount > 99 ? "99+" : badgeCount }) })
2140
+ badgeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, { style: [styles.badge, { backgroundColor: theme.colors.danger }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.Text, { style: [styles.badgeText, { color: theme.colors.onDanger }], children: badgeCount > 99 ? "99+" : badgeCount }) })
2083
2141
  ]
2084
2142
  }
2085
2143
  );
2086
2144
  }
2087
- var styles = import_react_native8.StyleSheet.create({
2145
+ var styles = import_react_native9.StyleSheet.create({
2088
2146
  floatingButton: {
2089
2147
  position: "absolute",
2090
2148
  justifyContent: "center",
@@ -2120,8 +2178,8 @@ var styles = import_react_native8.StyleSheet.create({
2120
2178
  });
2121
2179
 
2122
2180
  // src/components/overlays/EdgeGlowFrame.tsx
2123
- var React10 = __toESM(require("react"));
2124
- var import_react_native9 = require("react-native");
2181
+ var React11 = __toESM(require("react"));
2182
+ var import_react_native10 = require("react-native");
2125
2183
  var import_expo_linear_gradient = require("expo-linear-gradient");
2126
2184
 
2127
2185
  // src/components/utils/color.ts
@@ -2163,9 +2221,9 @@ function EdgeGlowFrame({
2163
2221
  }) {
2164
2222
  const theme = useTheme();
2165
2223
  const alpha = Math.max(0, Math.min(1, intensity));
2166
- const anim = React10.useRef(new import_react_native9.Animated.Value(visible ? 1 : 0)).current;
2167
- React10.useEffect(() => {
2168
- import_react_native9.Animated.timing(anim, {
2224
+ const anim = React11.useRef(new import_react_native10.Animated.Value(visible ? 1 : 0)).current;
2225
+ React11.useEffect(() => {
2226
+ import_react_native10.Animated.timing(anim, {
2169
2227
  toValue: visible ? 1 : 0,
2170
2228
  duration: 300,
2171
2229
  useNativeDriver: true
@@ -2174,8 +2232,8 @@ function EdgeGlowFrame({
2174
2232
  const c = baseColor(role, theme);
2175
2233
  const strong = withAlpha(c, 0.6 * alpha);
2176
2234
  const soft = withAlpha(c, 0.22 * alpha);
2177
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.Animated.View, { pointerEvents: "none", style: [{ position: "absolute", inset: 0, opacity: anim }, style], children: [
2178
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: { position: "absolute", top: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2235
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native10.Animated.View, { pointerEvents: "none", style: [{ position: "absolute", inset: 0, opacity: anim }, style], children: [
2236
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.View, { style: { position: "absolute", top: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2179
2237
  import_expo_linear_gradient.LinearGradient,
2180
2238
  {
2181
2239
  colors: [strong, soft, "transparent"],
@@ -2184,7 +2242,7 @@ function EdgeGlowFrame({
2184
2242
  style: { width: "100%", height: "100%" }
2185
2243
  }
2186
2244
  ) }),
2187
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: { position: "absolute", bottom: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2245
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.View, { style: { position: "absolute", bottom: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2188
2246
  import_expo_linear_gradient.LinearGradient,
2189
2247
  {
2190
2248
  colors: ["transparent", soft, strong],
@@ -2193,7 +2251,7 @@ function EdgeGlowFrame({
2193
2251
  style: { width: "100%", height: "100%" }
2194
2252
  }
2195
2253
  ) }),
2196
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: { position: "absolute", top: 0, bottom: 0, left: 0, width: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2254
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.View, { style: { position: "absolute", top: 0, bottom: 0, left: 0, width: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2197
2255
  import_expo_linear_gradient.LinearGradient,
2198
2256
  {
2199
2257
  colors: [strong, soft, "transparent"],
@@ -2202,7 +2260,7 @@ function EdgeGlowFrame({
2202
2260
  style: { width: "100%", height: "100%" }
2203
2261
  }
2204
2262
  ) }),
2205
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: { position: "absolute", top: 0, bottom: 0, right: 0, width: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2263
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.View, { style: { position: "absolute", top: 0, bottom: 0, right: 0, width: thickness }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2206
2264
  import_expo_linear_gradient.LinearGradient,
2207
2265
  {
2208
2266
  colors: ["transparent", soft, strong],
@@ -2215,13 +2273,13 @@ function EdgeGlowFrame({
2215
2273
  }
2216
2274
 
2217
2275
  // src/components/draw/DrawModeOverlay.tsx
2218
- var React13 = __toESM(require("react"));
2219
- var import_react_native13 = require("react-native");
2276
+ var React14 = __toESM(require("react"));
2277
+ var import_react_native14 = require("react-native");
2220
2278
  var import_react_native_view_shot = require("react-native-view-shot");
2221
2279
 
2222
2280
  // src/components/draw/DrawSurface.tsx
2223
- var React11 = __toESM(require("react"));
2224
- var import_react_native10 = require("react-native");
2281
+ var React12 = __toESM(require("react"));
2282
+ var import_react_native11 = require("react-native");
2225
2283
  var import_react_native_svg = __toESM(require("react-native-svg"));
2226
2284
 
2227
2285
  // src/components/draw/strokes.ts
@@ -2252,25 +2310,25 @@ function DrawSurface({
2252
2310
  style,
2253
2311
  minDistance = 1
2254
2312
  }) {
2255
- const [renderTick, setRenderTick] = React11.useState(0);
2256
- const currentPointsRef = React11.useRef([]);
2257
- const rafRef = React11.useRef(null);
2258
- const triggerRender = React11.useCallback(() => {
2313
+ const [renderTick, setRenderTick] = React12.useState(0);
2314
+ const currentPointsRef = React12.useRef([]);
2315
+ const rafRef = React12.useRef(null);
2316
+ const triggerRender = React12.useCallback(() => {
2259
2317
  if (rafRef.current !== null) return;
2260
2318
  rafRef.current = requestAnimationFrame(() => {
2261
2319
  rafRef.current = null;
2262
2320
  setRenderTick((n) => n + 1);
2263
2321
  });
2264
2322
  }, []);
2265
- React11.useEffect(() => () => {
2323
+ React12.useEffect(() => () => {
2266
2324
  if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2267
2325
  }, []);
2268
- const onStart = React11.useCallback((e) => {
2326
+ const onStart = React12.useCallback((e) => {
2269
2327
  const { locationX, locationY } = e.nativeEvent;
2270
2328
  currentPointsRef.current = [{ x: locationX, y: locationY }];
2271
2329
  triggerRender();
2272
2330
  }, [triggerRender]);
2273
- const onMove = React11.useCallback((e, _g) => {
2331
+ const onMove = React12.useCallback((e, _g) => {
2274
2332
  const { locationX, locationY } = e.nativeEvent;
2275
2333
  const pts = currentPointsRef.current;
2276
2334
  if (pts.length > 0) {
@@ -2283,7 +2341,7 @@ function DrawSurface({
2283
2341
  currentPointsRef.current = [...pts, { x: locationX, y: locationY }];
2284
2342
  triggerRender();
2285
2343
  }, [minDistance, triggerRender]);
2286
- const onEnd = React11.useCallback(() => {
2344
+ const onEnd = React12.useCallback(() => {
2287
2345
  const points = currentPointsRef.current;
2288
2346
  if (points.length > 0) {
2289
2347
  onAddStroke({ points, color, width: strokeWidth });
@@ -2291,8 +2349,8 @@ function DrawSurface({
2291
2349
  currentPointsRef.current = [];
2292
2350
  triggerRender();
2293
2351
  }, [color, onAddStroke, strokeWidth, triggerRender]);
2294
- const panResponder = React11.useMemo(
2295
- () => import_react_native10.PanResponder.create({
2352
+ const panResponder = React12.useMemo(
2353
+ () => import_react_native11.PanResponder.create({
2296
2354
  onStartShouldSetPanResponder: () => true,
2297
2355
  onMoveShouldSetPanResponder: () => true,
2298
2356
  onPanResponderGrant: onStart,
@@ -2304,7 +2362,7 @@ function DrawSurface({
2304
2362
  );
2305
2363
  const currentPath = pointsToSmoothPath(currentPointsRef.current);
2306
2364
  void renderTick;
2307
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles2.container, style], ...panResponder.panHandlers, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_svg.default, { style: import_react_native10.StyleSheet.absoluteFill, width: "100%", height: "100%", children: [
2365
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native11.View, { style: [import_react_native11.StyleSheet.absoluteFill, styles2.container, style], ...panResponder.panHandlers, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_svg.default, { style: import_react_native11.StyleSheet.absoluteFill, width: "100%", height: "100%", children: [
2308
2366
  strokes.map((s, idx) => {
2309
2367
  const d = pointsToSmoothPath(s.points);
2310
2368
  if (!d) return null;
@@ -2334,15 +2392,15 @@ function DrawSurface({
2334
2392
  ) : null
2335
2393
  ] }) });
2336
2394
  }
2337
- var styles2 = import_react_native10.StyleSheet.create({
2395
+ var styles2 = import_react_native11.StyleSheet.create({
2338
2396
  container: {
2339
2397
  zIndex: 5
2340
2398
  }
2341
2399
  });
2342
2400
 
2343
2401
  // src/components/draw/DrawToolbar.tsx
2344
- var React12 = __toESM(require("react"));
2345
- var import_react_native12 = require("react-native");
2402
+ var React13 = __toESM(require("react"));
2403
+ var import_react_native13 = require("react-native");
2346
2404
  var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
2347
2405
  var import_lucide_react_native = require("lucide-react-native");
2348
2406
 
@@ -2361,7 +2419,7 @@ async function impact(style) {
2361
2419
  }
2362
2420
 
2363
2421
  // src/components/draw/DrawColorPicker.tsx
2364
- var import_react_native11 = require("react-native");
2422
+ var import_react_native12 = require("react-native");
2365
2423
  var import_jsx_runtime10 = require("react/jsx-runtime");
2366
2424
  function DrawColorPicker({
2367
2425
  colors,
@@ -2396,10 +2454,10 @@ function DrawColorPicker({
2396
2454
  return { ...base, ...selectedStyle, ...whiteStyle };
2397
2455
  };
2398
2456
  if (!expanded) {
2399
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.Pressable, { onPress: onToggle, style: [swatchStyle(selected, true), style] });
2457
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.Pressable, { onPress: onToggle, style: [swatchStyle(selected, true), style] });
2400
2458
  }
2401
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [{ flexDirection: "row", alignItems: "center", gap: 8 }, style], children: colors.map((c, idx) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2402
- import_react_native11.Pressable,
2459
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [{ flexDirection: "row", alignItems: "center", gap: 8 }, style], children: colors.map((c, idx) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2460
+ import_react_native12.Pressable,
2403
2461
  {
2404
2462
  onPress: () => {
2405
2463
  onSelect(c);
@@ -2430,14 +2488,14 @@ function DrawToolbar({
2430
2488
  style
2431
2489
  }) {
2432
2490
  const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
2433
- const { width: screenWidth, height: screenHeight } = (0, import_react_native12.useWindowDimensions)();
2434
- const [expanded, setExpanded] = React12.useState(false);
2435
- const pos = React12.useRef(new import_react_native12.Animated.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
2436
- const start = React12.useRef({ x: 0, y: 0 });
2437
- const currentPos = React12.useRef({ x: 0, y: 0 });
2438
- React12.useEffect(() => {
2491
+ const { width: screenWidth, height: screenHeight } = (0, import_react_native13.useWindowDimensions)();
2492
+ const [expanded, setExpanded] = React13.useState(false);
2493
+ const pos = React13.useRef(new import_react_native13.Animated.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
2494
+ const start = React13.useRef({ x: 0, y: 0 });
2495
+ const currentPos = React13.useRef({ x: 0, y: 0 });
2496
+ React13.useEffect(() => {
2439
2497
  if (hidden) return;
2440
- import_react_native12.Animated.spring(pos.y, {
2498
+ import_react_native13.Animated.spring(pos.y, {
2441
2499
  toValue: insets.top + 60,
2442
2500
  useNativeDriver: true,
2443
2501
  damping: 12,
@@ -2445,7 +2503,7 @@ function DrawToolbar({
2445
2503
  mass: 0.8
2446
2504
  }).start();
2447
2505
  }, [hidden, insets.top, pos.y]);
2448
- React12.useEffect(() => {
2506
+ React13.useEffect(() => {
2449
2507
  const id = pos.addListener((v) => {
2450
2508
  currentPos.current = { x: v.x ?? 0, y: v.y ?? 0 };
2451
2509
  });
@@ -2453,7 +2511,7 @@ function DrawToolbar({
2453
2511
  pos.removeListener(id);
2454
2512
  };
2455
2513
  }, [pos]);
2456
- const clamp2 = React12.useCallback(
2514
+ const clamp2 = React13.useCallback(
2457
2515
  (x, y) => {
2458
2516
  const minX = 10;
2459
2517
  const maxX = Math.max(10, screenWidth - 230);
@@ -2463,8 +2521,8 @@ function DrawToolbar({
2463
2521
  },
2464
2522
  [insets.top, screenHeight, screenWidth]
2465
2523
  );
2466
- const panResponder = React12.useMemo(
2467
- () => import_react_native12.PanResponder.create({
2524
+ const panResponder = React13.useMemo(
2525
+ () => import_react_native13.PanResponder.create({
2468
2526
  onStartShouldSetPanResponder: () => false,
2469
2527
  onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 5 || Math.abs(g.dy) > 5,
2470
2528
  onPanResponderGrant: () => {
@@ -2476,7 +2534,7 @@ function DrawToolbar({
2476
2534
  },
2477
2535
  onPanResponderRelease: () => {
2478
2536
  const next = clamp2(currentPos.current.x, currentPos.current.y);
2479
- import_react_native12.Animated.spring(pos, { toValue: next, useNativeDriver: true }).start();
2537
+ import_react_native13.Animated.spring(pos, { toValue: next, useNativeDriver: true }).start();
2480
2538
  }
2481
2539
  }),
2482
2540
  [clamp2, pos]
@@ -2491,9 +2549,9 @@ function DrawToolbar({
2491
2549
  children
2492
2550
  }) {
2493
2551
  const isDisabled = Boolean(disabled) || Boolean(capturingDisabled);
2494
- const [pressed, setPressed] = React12.useState(false);
2552
+ const [pressed, setPressed] = React13.useState(false);
2495
2553
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2496
- import_react_native12.View,
2554
+ import_react_native13.View,
2497
2555
  {
2498
2556
  style: {
2499
2557
  width: 28,
@@ -2505,7 +2563,7 @@ function DrawToolbar({
2505
2563
  opacity: isDisabled ? 0.5 : pressed ? 0.85 : 1
2506
2564
  },
2507
2565
  children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2508
- import_react_native12.Pressable,
2566
+ import_react_native13.Pressable,
2509
2567
  {
2510
2568
  accessibilityRole: "button",
2511
2569
  accessibilityLabel,
@@ -2522,7 +2580,7 @@ function DrawToolbar({
2522
2580
  );
2523
2581
  }
2524
2582
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2525
- import_react_native12.Animated.View,
2583
+ import_react_native13.Animated.View,
2526
2584
  {
2527
2585
  style: [
2528
2586
  {
@@ -2539,7 +2597,7 @@ function DrawToolbar({
2539
2597
  ],
2540
2598
  ...panResponder.panHandlers,
2541
2599
  children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2542
- import_react_native12.View,
2600
+ import_react_native13.View,
2543
2601
  {
2544
2602
  style: {
2545
2603
  backgroundColor: "#F43F5E",
@@ -2547,7 +2605,7 @@ function DrawToolbar({
2547
2605
  padding: 12,
2548
2606
  minWidth: 220
2549
2607
  },
2550
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: { flexDirection: "row", alignItems: "center", gap: 8 }, children: [
2608
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: { flexDirection: "row", alignItems: "center", gap: 8 }, children: [
2551
2609
  renderDragHandle ? renderDragHandle() : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react_native.GripVertical, { size: 20, color: "rgba(255, 255, 255, 0.6)" }),
2552
2610
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2553
2611
  DrawColorPicker,
@@ -2565,7 +2623,7 @@ function DrawToolbar({
2565
2623
  }
2566
2624
  }
2567
2625
  ),
2568
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: { width: 1, height: 20, backgroundColor: "rgba(255, 255, 255, 0.3)", marginHorizontal: 4 } }),
2626
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.View, { style: { width: 1, height: 20, backgroundColor: "rgba(255, 255, 255, 0.3)", marginHorizontal: 4 } }),
2569
2627
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2570
2628
  CircleActionButton,
2571
2629
  {
@@ -2603,7 +2661,7 @@ function DrawToolbar({
2603
2661
  void impact("medium");
2604
2662
  onDone();
2605
2663
  },
2606
- children: capturing ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.ActivityIndicator, { color: "#FFFFFF", size: "small" }) : renderDoneIcon ? renderDoneIcon() : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react_native.Check, { size: 16, color: "#FFFFFF" })
2664
+ children: capturing ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.ActivityIndicator, { color: "#FFFFFF", size: "small" }) : renderDoneIcon ? renderDoneIcon() : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react_native.Check, { size: 16, color: "#FFFFFF" })
2607
2665
  }
2608
2666
  )
2609
2667
  ] })
@@ -2629,7 +2687,7 @@ function DrawModeOverlay({
2629
2687
  renderDragHandle
2630
2688
  }) {
2631
2689
  const theme = useTheme();
2632
- const defaultPalette = React13.useMemo(
2690
+ const defaultPalette = React14.useMemo(
2633
2691
  () => [
2634
2692
  "#EF4444",
2635
2693
  // Red
@@ -2647,11 +2705,11 @@ function DrawModeOverlay({
2647
2705
  []
2648
2706
  );
2649
2707
  const colors = palette && palette.length > 0 ? palette : defaultPalette;
2650
- const [selectedColor, setSelectedColor] = React13.useState(colors[0] ?? "#EF4444");
2651
- const [strokes, setStrokes] = React13.useState([]);
2652
- const [capturing, setCapturing] = React13.useState(false);
2653
- const [hideUi, setHideUi] = React13.useState(false);
2654
- React13.useEffect(() => {
2708
+ const [selectedColor, setSelectedColor] = React14.useState(colors[0] ?? "#EF4444");
2709
+ const [strokes, setStrokes] = React14.useState([]);
2710
+ const [capturing, setCapturing] = React14.useState(false);
2711
+ const [hideUi, setHideUi] = React14.useState(false);
2712
+ React14.useEffect(() => {
2655
2713
  if (!visible) return;
2656
2714
  setStrokes([]);
2657
2715
  setSelectedColor(colors[0] ?? "#EF4444");
@@ -2659,14 +2717,14 @@ function DrawModeOverlay({
2659
2717
  setHideUi(false);
2660
2718
  }, [colors, visible]);
2661
2719
  const canUndo = strokes.length > 0;
2662
- const handleUndo = React13.useCallback(() => {
2720
+ const handleUndo = React14.useCallback(() => {
2663
2721
  setStrokes((prev) => prev.slice(0, -1));
2664
2722
  }, []);
2665
- const handleCancel = React13.useCallback(() => {
2723
+ const handleCancel = React14.useCallback(() => {
2666
2724
  setStrokes([]);
2667
2725
  onCancel();
2668
2726
  }, [onCancel]);
2669
- const handleDone = React13.useCallback(async () => {
2727
+ const handleDone = React14.useCallback(async () => {
2670
2728
  if (!captureTargetRef.current || capturing) return;
2671
2729
  try {
2672
2730
  setCapturing(true);
@@ -2688,7 +2746,7 @@ function DrawModeOverlay({
2688
2746
  }
2689
2747
  }, [captureTargetRef, capturing, onCapture]);
2690
2748
  if (!visible) return null;
2691
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: [import_react_native13.StyleSheet.absoluteFill, styles3.root, style], pointerEvents: "box-none", children: [
2749
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native14.View, { style: [import_react_native14.StyleSheet.absoluteFill, styles3.root, style], pointerEvents: "box-none", children: [
2692
2750
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EdgeGlowFrame, { visible: !hideUi, role: "danger", thickness: 50, intensity: 1 }),
2693
2751
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2694
2752
  DrawSurface,
@@ -2719,32 +2777,32 @@ function DrawModeOverlay({
2719
2777
  )
2720
2778
  ] });
2721
2779
  }
2722
- var styles3 = import_react_native13.StyleSheet.create({
2780
+ var styles3 = import_react_native14.StyleSheet.create({
2723
2781
  root: {
2724
2782
  zIndex: 9999
2725
2783
  }
2726
2784
  });
2727
2785
 
2728
2786
  // src/components/comments/AppCommentsSheet.tsx
2729
- var React20 = __toESM(require("react"));
2730
- var import_react_native19 = require("react-native");
2787
+ var React21 = __toESM(require("react"));
2788
+ var import_react_native20 = require("react-native");
2731
2789
  var import_bottom_sheet3 = require("@gorhom/bottom-sheet");
2732
2790
  var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
2733
2791
  var import_liquid_glass4 = require("@callstack/liquid-glass");
2734
2792
  var import_lucide_react_native4 = require("lucide-react-native");
2735
2793
 
2736
2794
  // src/components/chat/ChatComposer.tsx
2737
- var React15 = __toESM(require("react"));
2738
- var import_react_native15 = require("react-native");
2795
+ var React16 = __toESM(require("react"));
2796
+ var import_react_native16 = require("react-native");
2739
2797
  var import_liquid_glass3 = require("@callstack/liquid-glass");
2740
2798
  var import_lucide_react_native3 = require("lucide-react-native");
2741
2799
 
2742
2800
  // src/components/chat/MultilineTextInput.tsx
2743
- var React14 = __toESM(require("react"));
2744
- var import_react_native14 = require("react-native");
2801
+ var React15 = __toESM(require("react"));
2802
+ var import_react_native15 = require("react-native");
2745
2803
  var import_bottom_sheet2 = require("@gorhom/bottom-sheet");
2746
2804
  var import_jsx_runtime13 = require("react/jsx-runtime");
2747
- var MultilineTextInput = React14.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
2805
+ var MultilineTextInput = React15.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
2748
2806
  const theme = useTheme();
2749
2807
  const baseStyle = {
2750
2808
  minHeight: 44,
@@ -2764,7 +2822,7 @@ var MultilineTextInput = React14.forwardRef(function MultilineTextInput2({ useBo
2764
2822
  style: [baseStyle, style],
2765
2823
  textAlignVertical: "top"
2766
2824
  };
2767
- return useBottomSheetTextInput ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_bottom_sheet2.BottomSheetTextInput, { ref, ...commonProps }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.TextInput, { ref, ...commonProps });
2825
+ return useBottomSheetTextInput ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_bottom_sheet2.BottomSheetTextInput, { ref, ...commonProps }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native15.TextInput, { ref, ...commonProps });
2768
2826
  });
2769
2827
 
2770
2828
  // src/components/icons/StudioIcons.tsx
@@ -2816,10 +2874,10 @@ function AspectRatioThumbnail({
2816
2874
  onRemove,
2817
2875
  renderRemoveIcon
2818
2876
  }) {
2819
- const [aspectRatio, setAspectRatio] = React15.useState(1);
2820
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
2821
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.View, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2822
- import_react_native15.Image,
2877
+ const [aspectRatio, setAspectRatio] = React16.useState(1);
2878
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native16.View, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
2879
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native16.View, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2880
+ import_react_native16.Image,
2823
2881
  {
2824
2882
  source: { uri },
2825
2883
  style: { width: "100%", height: "100%" },
@@ -2832,7 +2890,7 @@ function AspectRatioThumbnail({
2832
2890
  }
2833
2891
  ) }),
2834
2892
  onRemove ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2835
- import_react_native15.Pressable,
2893
+ import_react_native16.Pressable,
2836
2894
  {
2837
2895
  style: {
2838
2896
  position: "absolute",
@@ -2858,6 +2916,7 @@ function ChatComposer({
2858
2916
  onChangeValue,
2859
2917
  placeholder = "Describe the idea you want to build",
2860
2918
  disabled = false,
2919
+ sendDisabled = false,
2861
2920
  sending = false,
2862
2921
  autoFocus = false,
2863
2922
  onSend,
@@ -2872,19 +2931,19 @@ function ChatComposer({
2872
2931
  style
2873
2932
  }) {
2874
2933
  const theme = useTheme();
2875
- const [internal, setInternal] = React15.useState("");
2934
+ const [internal, setInternal] = React16.useState("");
2876
2935
  const text = value ?? internal;
2877
2936
  const setText = onChangeValue ?? setInternal;
2878
2937
  const hasAttachments = attachments.length > 0;
2879
2938
  const hasText = text.trim().length > 0;
2880
2939
  const composerMinHeight = hasAttachments ? THUMBNAIL_HEIGHT + 44 + 24 : 44;
2881
- const isButtonDisabled = sending || disabled;
2882
- const maxInputHeight = React15.useMemo(() => import_react_native15.Dimensions.get("window").height * 0.5, []);
2883
- const shakeAnim = React15.useRef(new import_react_native15.Animated.Value(0)).current;
2884
- const [sendPressed, setSendPressed] = React15.useState(false);
2885
- const inputRef = React15.useRef(null);
2886
- const prevAutoFocusRef = React15.useRef(false);
2887
- React15.useEffect(() => {
2940
+ const isButtonDisabled = sending || disabled || sendDisabled;
2941
+ const maxInputHeight = React16.useMemo(() => import_react_native16.Dimensions.get("window").height * 0.5, []);
2942
+ const shakeAnim = React16.useRef(new import_react_native16.Animated.Value(0)).current;
2943
+ const [sendPressed, setSendPressed] = React16.useState(false);
2944
+ const inputRef = React16.useRef(null);
2945
+ const prevAutoFocusRef = React16.useRef(false);
2946
+ React16.useEffect(() => {
2888
2947
  const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
2889
2948
  prevAutoFocusRef.current = autoFocus;
2890
2949
  if (!shouldFocus) return;
@@ -2894,17 +2953,17 @@ function ChatComposer({
2894
2953
  }, 75);
2895
2954
  return () => clearTimeout(t);
2896
2955
  }, [autoFocus, disabled, sending]);
2897
- const triggerShake = React15.useCallback(() => {
2956
+ const triggerShake = React16.useCallback(() => {
2898
2957
  shakeAnim.setValue(0);
2899
- import_react_native15.Animated.sequence([
2900
- import_react_native15.Animated.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
2901
- import_react_native15.Animated.timing(shakeAnim, { toValue: -10, duration: 50, useNativeDriver: true }),
2902
- import_react_native15.Animated.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
2903
- import_react_native15.Animated.timing(shakeAnim, { toValue: -10, duration: 50, useNativeDriver: true }),
2904
- import_react_native15.Animated.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
2958
+ import_react_native16.Animated.sequence([
2959
+ import_react_native16.Animated.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
2960
+ import_react_native16.Animated.timing(shakeAnim, { toValue: -10, duration: 50, useNativeDriver: true }),
2961
+ import_react_native16.Animated.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
2962
+ import_react_native16.Animated.timing(shakeAnim, { toValue: -10, duration: 50, useNativeDriver: true }),
2963
+ import_react_native16.Animated.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
2905
2964
  ]).start();
2906
2965
  }, [shakeAnim]);
2907
- const handleSend = React15.useCallback(async () => {
2966
+ const handleSend = React16.useCallback(async () => {
2908
2967
  if (isButtonDisabled) return;
2909
2968
  if (!hasText) {
2910
2969
  triggerShake();
@@ -2917,12 +2976,12 @@ function ChatComposer({
2917
2976
  const textareaBgColor = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
2918
2977
  const placeholderTextColor = theme.scheme === "dark" ? "#A1A1AA" : "#71717A";
2919
2978
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2920
- import_react_native15.View,
2979
+ import_react_native16.View,
2921
2980
  {
2922
2981
  style: [{ paddingHorizontal: 16, paddingBottom: 12, paddingTop: 8 }, style],
2923
2982
  onLayout: (e) => onLayout == null ? void 0 : onLayout({ height: e.nativeEvent.layout.height }),
2924
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8 }, children: [
2925
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.Animated.View, { style: { flex: 1, transform: [{ translateX: shakeAnim }] }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2983
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native16.View, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8 }, children: [
2984
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native16.Animated.View, { style: { flex: 1, transform: [{ translateX: shakeAnim }] }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2926
2985
  import_liquid_glass3.LiquidGlassView,
2927
2986
  {
2928
2987
  style: [
@@ -2935,7 +2994,7 @@ function ChatComposer({
2935
2994
  effect: "clear",
2936
2995
  children: [
2937
2996
  hasAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2938
- import_react_native15.ScrollView,
2997
+ import_react_native16.ScrollView,
2939
2998
  {
2940
2999
  horizontal: true,
2941
3000
  showsHorizontalScrollIndicator: false,
@@ -2952,7 +3011,7 @@ function ChatComposer({
2952
3011
  `attachment-${index}`
2953
3012
  )),
2954
3013
  onAddAttachment ? renderAddAttachment ? renderAddAttachment() : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2955
- import_react_native15.Pressable,
3014
+ import_react_native16.Pressable,
2956
3015
  {
2957
3016
  style: {
2958
3017
  height: THUMBNAIL_HEIGHT,
@@ -3004,7 +3063,7 @@ function ChatComposer({
3004
3063
  interactive: true,
3005
3064
  effect: "clear",
3006
3065
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3007
- import_react_native15.View,
3066
+ import_react_native16.View,
3008
3067
  {
3009
3068
  style: {
3010
3069
  width: 44,
@@ -3015,7 +3074,7 @@ function ChatComposer({
3015
3074
  opacity: isButtonDisabled ? 0.6 : sendPressed ? 0.9 : 1
3016
3075
  },
3017
3076
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3018
- import_react_native15.Pressable,
3077
+ import_react_native16.Pressable,
3019
3078
  {
3020
3079
  accessibilityRole: "button",
3021
3080
  accessibilityLabel: "Send",
@@ -3024,7 +3083,7 @@ function ChatComposer({
3024
3083
  onPressIn: () => setSendPressed(true),
3025
3084
  onPressOut: () => setSendPressed(false),
3026
3085
  style: { flex: 1, alignItems: "center", justifyContent: "center" },
3027
- children: sending ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.ActivityIndicator, {}) : renderSendIcon ? renderSendIcon() : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconChevronRight, { size: 20, colorToken: "onPrimary" })
3086
+ children: sending ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native16.ActivityIndicator, {}) : renderSendIcon ? renderSendIcon() : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconChevronRight, { size: 20, colorToken: "onPrimary" })
3028
3087
  }
3029
3088
  )
3030
3089
  }
@@ -3037,11 +3096,11 @@ function ChatComposer({
3037
3096
  }
3038
3097
 
3039
3098
  // src/components/comments/CommentRow.tsx
3040
- var React16 = __toESM(require("react"));
3041
- var import_react_native17 = require("react-native");
3099
+ var React17 = __toESM(require("react"));
3100
+ var import_react_native18 = require("react-native");
3042
3101
 
3043
3102
  // src/components/primitives/Avatar.tsx
3044
- var import_react_native16 = require("react-native");
3103
+ var import_react_native17 = require("react-native");
3045
3104
  var import_jsx_runtime16 = require("react/jsx-runtime");
3046
3105
  function initialsFrom(name) {
3047
3106
  var _a, _b;
@@ -3061,7 +3120,7 @@ function Avatar({
3061
3120
  const radius = size / 2;
3062
3121
  const fallbackBg = fallbackBackgroundColor ?? theme.colors.neutral;
3063
3122
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3064
- import_react_native16.View,
3123
+ import_react_native17.View,
3065
3124
  {
3066
3125
  style: [
3067
3126
  {
@@ -3076,7 +3135,7 @@ function Avatar({
3076
3135
  style
3077
3136
  ],
3078
3137
  children: uri ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3079
- import_react_native16.Image,
3138
+ import_react_native17.Image,
3080
3139
  {
3081
3140
  source: { uri },
3082
3141
  style: [{ width: size, height: size }, imageStyle],
@@ -3109,9 +3168,9 @@ function formatTimeAgo(iso) {
3109
3168
  var import_jsx_runtime17 = require("react/jsx-runtime");
3110
3169
  function CommentRow({ comment, showDivider }) {
3111
3170
  const theme = useTheme();
3112
- const [authorName, setAuthorName] = React16.useState(null);
3113
- const [authorAvatar, setAuthorAvatar] = React16.useState(null);
3114
- React16.useEffect(() => {
3171
+ const [authorName, setAuthorName] = React17.useState(null);
3172
+ const [authorAvatar, setAuthorAvatar] = React17.useState(null);
3173
+ React17.useEffect(() => {
3115
3174
  let cancelled = false;
3116
3175
  (async () => {
3117
3176
  try {
@@ -3127,7 +3186,7 @@ function CommentRow({ comment, showDivider }) {
3127
3186
  };
3128
3187
  }, [comment.authorId]);
3129
3188
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3130
- import_react_native17.View,
3189
+ import_react_native18.View,
3131
3190
  {
3132
3191
  style: {
3133
3192
  flexDirection: "row",
@@ -3138,8 +3197,8 @@ function CommentRow({ comment, showDivider }) {
3138
3197
  },
3139
3198
  children: [
3140
3199
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Avatar, { size: 32, uri: authorAvatar, name: authorName ?? comment.authorId, style: { marginTop: 6 } }),
3141
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { style: { flex: 1, minWidth: 0, gap: 4 }, children: [
3142
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native17.View, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.sm }, children: [
3200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: { flex: 1, minWidth: 0, gap: 4 }, children: [
3201
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.sm }, children: [
3143
3202
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { style: { fontSize: 14, lineHeight: 18, fontWeight: theme.typography.fontWeight.bold, color: theme.colors.text }, children: authorName ?? "Unknown User" }),
3144
3203
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, children: formatTimeAgo(comment.createdAt) })
3145
3204
  ] }),
@@ -3151,7 +3210,7 @@ function CommentRow({ comment, showDivider }) {
3151
3210
  }
3152
3211
 
3153
3212
  // src/components/comments/useAppComments.ts
3154
- var React17 = __toESM(require("react"));
3213
+ var React18 = __toESM(require("react"));
3155
3214
 
3156
3215
  // src/data/comments/remote.ts
3157
3216
  var AppCommentsRemoteDataSourceImpl = class extends BaseRemote {
@@ -3223,18 +3282,18 @@ var appCommentsRepository = new AppCommentsRepositoryImpl(appCommentsRemoteDataS
3223
3282
 
3224
3283
  // src/components/comments/useAppComments.ts
3225
3284
  function useAppComments(appId) {
3226
- const [comments, setComments] = React17.useState([]);
3227
- const [loading, setLoading] = React17.useState(false);
3228
- const [sending, setSending] = React17.useState(false);
3229
- const [error, setError] = React17.useState(null);
3230
- const sortByCreatedAtAsc = React17.useCallback((items) => {
3285
+ const [comments, setComments] = React18.useState([]);
3286
+ const [loading, setLoading] = React18.useState(false);
3287
+ const [sending, setSending] = React18.useState(false);
3288
+ const [error, setError] = React18.useState(null);
3289
+ const sortByCreatedAtAsc = React18.useCallback((items) => {
3231
3290
  return [...items].sort((a, b) => {
3232
3291
  const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
3233
3292
  const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
3234
3293
  return at - bt;
3235
3294
  });
3236
3295
  }, []);
3237
- const refresh = React17.useCallback(async () => {
3296
+ const refresh = React18.useCallback(async () => {
3238
3297
  if (!appId) {
3239
3298
  setComments([]);
3240
3299
  return;
@@ -3251,10 +3310,10 @@ function useAppComments(appId) {
3251
3310
  setLoading(false);
3252
3311
  }
3253
3312
  }, [appId, sortByCreatedAtAsc]);
3254
- React17.useEffect(() => {
3313
+ React18.useEffect(() => {
3255
3314
  void refresh();
3256
3315
  }, [refresh]);
3257
- const create = React17.useCallback(
3316
+ const create = React18.useCallback(
3258
3317
  async (text) => {
3259
3318
  if (!appId) return;
3260
3319
  const trimmed = text.trim();
@@ -3277,11 +3336,11 @@ function useAppComments(appId) {
3277
3336
  }
3278
3337
 
3279
3338
  // src/components/comments/useAppDetails.ts
3280
- var React18 = __toESM(require("react"));
3339
+ var React19 = __toESM(require("react"));
3281
3340
  function useAppDetails(appId) {
3282
- const [app, setApp] = React18.useState(null);
3283
- const [loading, setLoading] = React18.useState(false);
3284
- React18.useEffect(() => {
3341
+ const [app, setApp] = React19.useState(null);
3342
+ const [loading, setLoading] = React19.useState(false);
3343
+ React19.useEffect(() => {
3285
3344
  if (!appId) {
3286
3345
  setApp(null);
3287
3346
  return;
@@ -3306,25 +3365,30 @@ function useAppDetails(appId) {
3306
3365
  }
3307
3366
 
3308
3367
  // src/components/comments/useIosKeyboardSnapFix.ts
3309
- var React19 = __toESM(require("react"));
3310
- var import_react_native18 = require("react-native");
3311
- function useIosKeyboardSnapFix(sheetRef) {
3312
- const [keyboardVisible, setKeyboardVisible] = React19.useState(false);
3313
- React19.useEffect(() => {
3314
- if (import_react_native18.Platform.OS !== "ios") return;
3315
- const show = import_react_native18.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
3316
- const hide = import_react_native18.Keyboard.addListener("keyboardWillHide", () => {
3368
+ var React20 = __toESM(require("react"));
3369
+ var import_react_native19 = require("react-native");
3370
+ function useIosKeyboardSnapFix(sheetRef, options) {
3371
+ const [keyboardVisible, setKeyboardVisible] = React20.useState(false);
3372
+ React20.useEffect(() => {
3373
+ if (import_react_native19.Platform.OS !== "ios") return;
3374
+ const show = import_react_native19.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
3375
+ const hide = import_react_native19.Keyboard.addListener("keyboardWillHide", () => {
3376
+ var _a;
3317
3377
  setKeyboardVisible(false);
3318
- setTimeout(() => {
3319
- var _a, _b;
3320
- return (_b = (_a = sheetRef.current) == null ? void 0 : _a.snapToIndex) == null ? void 0 : _b.call(_a, 1);
3321
- }, 10);
3378
+ const target = (options == null ? void 0 : options.targetIndex) ?? 1;
3379
+ const current = ((_a = options == null ? void 0 : options.getCurrentIndex) == null ? void 0 : _a.call(options)) ?? null;
3380
+ if (current === target) {
3381
+ setTimeout(() => {
3382
+ var _a2, _b;
3383
+ return (_b = (_a2 = sheetRef.current) == null ? void 0 : _a2.snapToIndex) == null ? void 0 : _b.call(_a2, target);
3384
+ }, 10);
3385
+ }
3322
3386
  });
3323
3387
  return () => {
3324
3388
  show.remove();
3325
3389
  hide.remove();
3326
3390
  };
3327
- }, [sheetRef]);
3391
+ }, [options == null ? void 0 : options.getCurrentIndex, options == null ? void 0 : options.targetIndex, sheetRef]);
3328
3392
  return { keyboardVisible };
3329
3393
  }
3330
3394
 
@@ -3333,12 +3397,16 @@ var import_jsx_runtime18 = require("react/jsx-runtime");
3333
3397
  function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3334
3398
  const theme = useTheme();
3335
3399
  const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
3336
- const sheetRef = React20.useRef(null);
3337
- const snapPoints = React20.useMemo(() => ["50%", "90%"], []);
3400
+ const sheetRef = React21.useRef(null);
3401
+ const snapPoints = React21.useMemo(() => ["50%", "90%"], []);
3402
+ const currentIndexRef = React21.useRef(1);
3338
3403
  const { comments, loading, sending, error, create, refresh } = useAppComments(appId);
3339
3404
  const { app, loading: loadingApp } = useAppDetails(appId);
3340
- const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef);
3341
- React20.useEffect(() => {
3405
+ const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef, {
3406
+ getCurrentIndex: () => currentIndexRef.current,
3407
+ targetIndex: 1
3408
+ });
3409
+ React21.useEffect(() => {
3342
3410
  var _a, _b;
3343
3411
  if (appId) {
3344
3412
  (_a = sheetRef.current) == null ? void 0 : _a.present();
@@ -3347,21 +3415,22 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3347
3415
  (_b = sheetRef.current) == null ? void 0 : _b.dismiss();
3348
3416
  }
3349
3417
  }, [appId, refresh]);
3350
- React20.useEffect(() => {
3418
+ React21.useEffect(() => {
3351
3419
  if (!appId) return;
3352
3420
  onCountChange == null ? void 0 : onCountChange(comments.length);
3353
3421
  }, [appId, comments.length, onCountChange]);
3354
- const renderBackdrop = React20.useCallback(
3422
+ const renderBackdrop = React21.useCallback(
3355
3423
  (props) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_bottom_sheet3.BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
3356
3424
  []
3357
3425
  );
3358
- const handleChange = React20.useCallback(
3426
+ const handleChange = React21.useCallback(
3359
3427
  (index) => {
3428
+ currentIndexRef.current = index;
3360
3429
  if (index === -1) onClose();
3361
3430
  },
3362
3431
  [onClose]
3363
3432
  );
3364
- const handlePlay = React20.useCallback(async () => {
3433
+ const handlePlay = React21.useCallback(async () => {
3365
3434
  var _a;
3366
3435
  if (!appId) return;
3367
3436
  (_a = sheetRef.current) == null ? void 0 : _a.dismiss();
@@ -3379,17 +3448,17 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3379
3448
  onChange: handleChange,
3380
3449
  backgroundStyle: {
3381
3450
  backgroundColor: theme.scheme === "dark" ? "#0B080F" : "#FFFFFF",
3382
- borderTopLeftRadius: import_react_native19.Platform.OS === "ios" ? 39 : 16,
3383
- borderTopRightRadius: import_react_native19.Platform.OS === "ios" ? 39 : 16
3451
+ borderTopLeftRadius: import_react_native20.Platform.OS === "ios" ? 39 : 16,
3452
+ borderTopRightRadius: import_react_native20.Platform.OS === "ios" ? 39 : 16
3384
3453
  },
3385
3454
  handleIndicatorStyle: { backgroundColor: theme.colors.handleIndicator },
3386
3455
  keyboardBehavior: "interactive",
3387
3456
  keyboardBlurBehavior: "restore",
3388
3457
  android_keyboardInputMode: "adjustResize",
3389
3458
  topInset: insets.top,
3390
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: { flex: 1 }, children: [
3459
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native20.View, { style: { flex: 1 }, children: [
3391
3460
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
3392
- import_react_native19.View,
3461
+ import_react_native20.View,
3393
3462
  {
3394
3463
  style: {
3395
3464
  flexDirection: "row",
@@ -3425,7 +3494,7 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3425
3494
  interactive: true,
3426
3495
  effect: "clear",
3427
3496
  children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3428
- import_react_native19.View,
3497
+ import_react_native20.View,
3429
3498
  {
3430
3499
  style: {
3431
3500
  width: 32,
@@ -3437,7 +3506,7 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3437
3506
  opacity: appId ? 1 : 0.5
3438
3507
  },
3439
3508
  children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3440
- import_react_native19.Pressable,
3509
+ import_react_native20.Pressable,
3441
3510
  {
3442
3511
  disabled: !appId,
3443
3512
  onPress: () => void handlePlay(),
@@ -3472,13 +3541,13 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3472
3541
  },
3473
3542
  keyboardShouldPersistTaps: "handled",
3474
3543
  children: [
3475
- loading && comments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native19.View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native19.ActivityIndicator, {}) }) : comments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native19.View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { variant: "bodyMuted", style: { textAlign: "center" }, children: "No comments yet" }) }) : comments.map((c, idx) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CommentRow, { comment: c, showDivider: idx < comments.length - 1 }, c.id)),
3544
+ loading && comments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native20.View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native20.ActivityIndicator, {}) }) : comments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native20.View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { variant: "bodyMuted", style: { textAlign: "center" }, children: "No comments yet" }) }) : comments.map((c, idx) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CommentRow, { comment: c, showDivider: idx < comments.length - 1 }, c.id)),
3476
3545
  error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { variant: "captionMuted", style: { marginTop: theme.spacing.lg }, children: "Failed to load comments." }) : null
3477
3546
  ]
3478
3547
  }
3479
3548
  ),
3480
3549
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3481
- import_react_native19.View,
3550
+ import_react_native20.View,
3482
3551
  {
3483
3552
  style: {
3484
3553
  position: "absolute",
@@ -3487,7 +3556,7 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3487
3556
  bottom: 0,
3488
3557
  paddingHorizontal: theme.spacing.lg,
3489
3558
  paddingTop: theme.spacing.sm,
3490
- paddingBottom: import_react_native19.Platform.OS === "ios" ? keyboardVisible ? theme.spacing.lg : insets.bottom : insets.bottom + 10,
3559
+ paddingBottom: import_react_native20.Platform.OS === "ios" ? keyboardVisible ? theme.spacing.lg : insets.bottom : insets.bottom + 10,
3491
3560
  borderTopWidth: 1,
3492
3561
  borderTopColor: withAlpha(theme.colors.border, 0.1),
3493
3562
  backgroundColor: withAlpha(theme.colors.background, 0.8)
@@ -3501,7 +3570,7 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3501
3570
  useBottomSheetTextInput: true,
3502
3571
  onSend: async (text) => {
3503
3572
  await create(text);
3504
- import_react_native19.Keyboard.dismiss();
3573
+ import_react_native20.Keyboard.dismiss();
3505
3574
  }
3506
3575
  }
3507
3576
  )
@@ -3513,16 +3582,16 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3513
3582
  }
3514
3583
 
3515
3584
  // src/studio/ui/PreviewPanel.tsx
3516
- var import_react_native40 = require("react-native");
3585
+ var import_react_native41 = require("react-native");
3517
3586
 
3518
3587
  // src/components/preview/PreviewPage.tsx
3519
- var import_react_native20 = require("react-native");
3588
+ var import_react_native21 = require("react-native");
3520
3589
  var import_bottom_sheet4 = require("@gorhom/bottom-sheet");
3521
3590
  var import_jsx_runtime19 = require("react/jsx-runtime");
3522
3591
  function PreviewPage({ header, children, contentStyle }) {
3523
3592
  const theme = useTheme();
3524
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native20.View, { style: { flex: 1 }, children: [
3525
- header ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native20.View, { children: header }) : null,
3593
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native21.View, { style: { flex: 1 }, children: [
3594
+ header ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native21.View, { children: header }) : null,
3526
3595
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3527
3596
  import_bottom_sheet4.BottomSheetScrollView,
3528
3597
  {
@@ -3542,15 +3611,15 @@ function PreviewPage({ header, children, contentStyle }) {
3542
3611
  }
3543
3612
 
3544
3613
  // src/studio/ui/preview-panel/PreviewPanelHeader.tsx
3545
- var import_react_native23 = require("react-native");
3614
+ var import_react_native24 = require("react-native");
3546
3615
 
3547
3616
  // src/components/studio-sheet/StudioSheetHeader.tsx
3548
- var import_react_native21 = require("react-native");
3617
+ var import_react_native22 = require("react-native");
3549
3618
  var import_jsx_runtime20 = require("react/jsx-runtime");
3550
3619
  function StudioSheetHeader({ left, center, right, style }) {
3551
3620
  const theme = useTheme();
3552
3621
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3553
- import_react_native21.View,
3622
+ import_react_native22.View,
3554
3623
  {
3555
3624
  style: [
3556
3625
  {
@@ -3563,17 +3632,17 @@ function StudioSheetHeader({ left, center, right, style }) {
3563
3632
  style
3564
3633
  ],
3565
3634
  children: [
3566
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native21.View, { style: { flexDirection: "row", alignItems: "center" }, children: left }),
3567
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native21.View, { style: { flex: 1, alignItems: "center" }, children: center }),
3568
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native21.View, { style: { flexDirection: "row", alignItems: "center" }, children: right })
3635
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native22.View, { style: { flexDirection: "row", alignItems: "center" }, children: left }),
3636
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native22.View, { style: { flex: 1, alignItems: "center" }, children: center }),
3637
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native22.View, { style: { flexDirection: "row", alignItems: "center" }, children: right })
3569
3638
  ]
3570
3639
  }
3571
3640
  );
3572
3641
  }
3573
3642
 
3574
3643
  // src/components/studio-sheet/StudioSheetHeaderIconButton.tsx
3575
- var React21 = __toESM(require("react"));
3576
- var import_react_native22 = require("react-native");
3644
+ var React22 = __toESM(require("react"));
3645
+ var import_react_native23 = require("react-native");
3577
3646
  var import_liquid_glass5 = require("@callstack/liquid-glass");
3578
3647
  var import_jsx_runtime21 = require("react/jsx-runtime");
3579
3648
  function StudioSheetHeaderIconButton({
@@ -3587,19 +3656,19 @@ function StudioSheetHeaderIconButton({
3587
3656
  }) {
3588
3657
  const theme = useTheme();
3589
3658
  const size = 44;
3590
- const [pressed, setPressed] = React21.useState(false);
3659
+ const [pressed, setPressed] = React22.useState(false);
3591
3660
  const solidBg = intent === "danger" ? theme.colors.danger : intent === "primary" ? theme.colors.primary : theme.colors.neutral;
3592
3661
  const glassFallbackBg = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
3593
3662
  const glassInnerBg = intent === "danger" ? theme.colors.danger : theme.colors.primary;
3594
3663
  const resolvedOpacity = disabled ? 0.6 : pressed ? 0.9 : 1;
3595
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native22.View, { style, children: appearance === "glass" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3664
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native23.View, { style, children: appearance === "glass" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3596
3665
  import_liquid_glass5.LiquidGlassView,
3597
3666
  {
3598
3667
  style: [{ borderRadius: 100 }, !import_liquid_glass5.isLiquidGlassSupported && { backgroundColor: glassFallbackBg }],
3599
3668
  interactive: true,
3600
3669
  effect: "clear",
3601
3670
  children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3602
- import_react_native22.View,
3671
+ import_react_native23.View,
3603
3672
  {
3604
3673
  style: {
3605
3674
  width: size,
@@ -3611,7 +3680,7 @@ function StudioSheetHeaderIconButton({
3611
3680
  opacity: resolvedOpacity
3612
3681
  },
3613
3682
  children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3614
- import_react_native22.Pressable,
3683
+ import_react_native23.Pressable,
3615
3684
  {
3616
3685
  accessibilityRole: "button",
3617
3686
  accessibilityLabel,
@@ -3630,7 +3699,7 @@ function StudioSheetHeaderIconButton({
3630
3699
  )
3631
3700
  }
3632
3701
  ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3633
- import_react_native22.View,
3702
+ import_react_native23.View,
3634
3703
  {
3635
3704
  style: {
3636
3705
  width: size,
@@ -3642,7 +3711,7 @@ function StudioSheetHeaderIconButton({
3642
3711
  opacity: resolvedOpacity
3643
3712
  },
3644
3713
  children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3645
- import_react_native22.Pressable,
3714
+ import_react_native23.Pressable,
3646
3715
  {
3647
3716
  accessibilityRole: "button",
3648
3717
  accessibilityLabel,
@@ -3669,7 +3738,7 @@ function PreviewPanelHeader({ isOwner, onClose, onNavigateHome, onGoToChat }) {
3669
3738
  {
3670
3739
  left: onNavigateHome ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", appearance: "glass", intent: "primary", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(IconHome, { size: 20, colorToken: "onPrimary" }) }) : null,
3671
3740
  center: null,
3672
- right: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native23.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
3741
+ right: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native24.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
3673
3742
  isOwner ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3674
3743
  StudioSheetHeaderIconButton,
3675
3744
  {
@@ -3688,10 +3757,10 @@ function PreviewPanelHeader({ isOwner, onClose, onNavigateHome, onGoToChat }) {
3688
3757
  }
3689
3758
 
3690
3759
  // src/components/preview/PreviewHeroCard.tsx
3691
- var import_react_native25 = require("react-native");
3760
+ var import_react_native26 = require("react-native");
3692
3761
 
3693
3762
  // src/components/primitives/Surface.tsx
3694
- var import_react_native24 = require("react-native");
3763
+ var import_react_native25 = require("react-native");
3695
3764
  var import_jsx_runtime23 = require("react/jsx-runtime");
3696
3765
  function backgroundFor(variant, theme) {
3697
3766
  const { colors } = theme;
@@ -3710,7 +3779,7 @@ function backgroundFor(variant, theme) {
3710
3779
  function Surface({ variant = "surface", border = false, style, ...props }) {
3711
3780
  const theme = useTheme();
3712
3781
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3713
- import_react_native24.View,
3782
+ import_react_native25.View,
3714
3783
  {
3715
3784
  ...props,
3716
3785
  style: [
@@ -3766,32 +3835,32 @@ function PreviewHeroCard({
3766
3835
  },
3767
3836
  style
3768
3837
  ],
3769
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native25.View, { style: { flex: 1 }, children: [
3770
- background ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: { position: "absolute", inset: 0 }, children: background }) : null,
3771
- image ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: { position: "absolute", inset: 0 }, children: image }) : null,
3772
- overlayTopLeft ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: { position: "absolute", top: theme.spacing.sm, left: theme.spacing.sm, zIndex: 2 }, children: overlayTopLeft }) : null,
3773
- overlayBottom ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: { flex: 1, justifyContent: "flex-end" }, children: overlayBottom }) : null
3838
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native26.View, { style: { flex: 1 }, children: [
3839
+ background ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native26.View, { style: { position: "absolute", inset: 0 }, children: background }) : null,
3840
+ image ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native26.View, { style: { position: "absolute", inset: 0 }, children: image }) : null,
3841
+ overlayTopLeft ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native26.View, { style: { position: "absolute", top: theme.spacing.sm, left: theme.spacing.sm, zIndex: 2 }, children: overlayTopLeft }) : null,
3842
+ overlayBottom ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native26.View, { style: { flex: 1, justifyContent: "flex-end" }, children: overlayBottom }) : null
3774
3843
  ] })
3775
3844
  }
3776
3845
  );
3777
3846
  }
3778
3847
 
3779
3848
  // src/components/preview/PreviewPlaceholder.tsx
3780
- var React22 = __toESM(require("react"));
3781
- var import_react_native26 = require("react-native");
3849
+ var React23 = __toESM(require("react"));
3850
+ var import_react_native27 = require("react-native");
3782
3851
  var import_expo_linear_gradient2 = require("expo-linear-gradient");
3783
3852
  var import_jsx_runtime26 = require("react/jsx-runtime");
3784
3853
  function PreviewPlaceholder({ visible, style }) {
3785
3854
  if (!visible) return null;
3786
- const opacityAnim = React22.useRef(new import_react_native26.Animated.Value(0)).current;
3787
- React22.useEffect(() => {
3855
+ const opacityAnim = React23.useRef(new import_react_native27.Animated.Value(0)).current;
3856
+ React23.useEffect(() => {
3788
3857
  if (!visible) return;
3789
- const animation = import_react_native26.Animated.loop(
3790
- import_react_native26.Animated.sequence([
3791
- import_react_native26.Animated.timing(opacityAnim, { toValue: 1, duration: 1500, useNativeDriver: true }),
3792
- import_react_native26.Animated.timing(opacityAnim, { toValue: 2, duration: 1500, useNativeDriver: true }),
3793
- import_react_native26.Animated.timing(opacityAnim, { toValue: 3, duration: 1500, useNativeDriver: true }),
3794
- import_react_native26.Animated.timing(opacityAnim, { toValue: 0, duration: 1500, useNativeDriver: true })
3858
+ const animation = import_react_native27.Animated.loop(
3859
+ import_react_native27.Animated.sequence([
3860
+ import_react_native27.Animated.timing(opacityAnim, { toValue: 1, duration: 1500, useNativeDriver: true }),
3861
+ import_react_native27.Animated.timing(opacityAnim, { toValue: 2, duration: 1500, useNativeDriver: true }),
3862
+ import_react_native27.Animated.timing(opacityAnim, { toValue: 3, duration: 1500, useNativeDriver: true }),
3863
+ import_react_native27.Animated.timing(opacityAnim, { toValue: 0, duration: 1500, useNativeDriver: true })
3795
3864
  ])
3796
3865
  );
3797
3866
  animation.start();
@@ -3802,7 +3871,7 @@ function PreviewPlaceholder({ visible, style }) {
3802
3871
  const opacity3 = opacityAnim.interpolate({ inputRange: [0, 1, 2, 3], outputRange: [0, 0, 1, 0] });
3803
3872
  const opacity4 = opacityAnim.interpolate({ inputRange: [0, 1, 2, 3], outputRange: [0, 0, 0, 1] });
3804
3873
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
3805
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3874
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native27.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3806
3875
  import_expo_linear_gradient2.LinearGradient,
3807
3876
  {
3808
3877
  colors: ["rgba(98, 0, 238, 0.45)", "rgba(168, 85, 247, 0.35)"],
@@ -3811,7 +3880,7 @@ function PreviewPlaceholder({ visible, style }) {
3811
3880
  style: { width: "100%", height: "100%" }
3812
3881
  }
3813
3882
  ) }),
3814
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity2 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3883
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native27.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity2 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3815
3884
  import_expo_linear_gradient2.LinearGradient,
3816
3885
  {
3817
3886
  colors: ["rgba(168, 85, 247, 0.45)", "rgba(139, 92, 246, 0.35)"],
@@ -3820,7 +3889,7 @@ function PreviewPlaceholder({ visible, style }) {
3820
3889
  style: { width: "100%", height: "100%" }
3821
3890
  }
3822
3891
  ) }),
3823
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity3 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3892
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native27.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity3 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3824
3893
  import_expo_linear_gradient2.LinearGradient,
3825
3894
  {
3826
3895
  colors: ["rgba(139, 92, 246, 0.45)", "rgba(126, 34, 206, 0.35)"],
@@ -3829,7 +3898,7 @@ function PreviewPlaceholder({ visible, style }) {
3829
3898
  style: { width: "100%", height: "100%" }
3830
3899
  }
3831
3900
  ) }),
3832
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity4 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3901
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native27.Animated.View, { style: [{ position: "absolute", inset: 0, opacity: opacity4 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3833
3902
  import_expo_linear_gradient2.LinearGradient,
3834
3903
  {
3835
3904
  colors: ["rgba(126, 34, 206, 0.45)", "rgba(98, 0, 238, 0.35)"],
@@ -3842,12 +3911,12 @@ function PreviewPlaceholder({ visible, style }) {
3842
3911
  }
3843
3912
 
3844
3913
  // src/components/preview/PreviewImage.tsx
3845
- var import_react_native27 = require("react-native");
3914
+ var import_react_native28 = require("react-native");
3846
3915
  var import_jsx_runtime27 = require("react/jsx-runtime");
3847
3916
  function PreviewImage({ uri, onLoad, style }) {
3848
3917
  if (!uri) return null;
3849
3918
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3850
- import_react_native27.Image,
3919
+ import_react_native28.Image,
3851
3920
  {
3852
3921
  source: { uri },
3853
3922
  resizeMode: "cover",
@@ -3858,7 +3927,7 @@ function PreviewImage({ uri, onLoad, style }) {
3858
3927
  }
3859
3928
 
3860
3929
  // src/components/preview/StatsBar.tsx
3861
- var import_react_native28 = require("react-native");
3930
+ var import_react_native29 = require("react-native");
3862
3931
  var import_liquid_glass6 = require("@callstack/liquid-glass");
3863
3932
  var import_lucide_react_native5 = require("lucide-react-native");
3864
3933
 
@@ -3891,7 +3960,7 @@ function StatsBar({
3891
3960
  const theme = useTheme();
3892
3961
  const statsBgColor = theme.scheme === "dark" ? "rgba(24, 24, 27, 0.5)" : "rgba(255, 255, 255, 0.5)";
3893
3962
  return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3894
- import_react_native28.View,
3963
+ import_react_native29.View,
3895
3964
  {
3896
3965
  style: [
3897
3966
  { position: "absolute", bottom: 12, width: "100%", paddingHorizontal: 12 },
@@ -3907,15 +3976,15 @@ function StatsBar({
3907
3976
  !import_liquid_glass6.isLiquidGlassSupported && { backgroundColor: statsBgColor }
3908
3977
  ],
3909
3978
  effect: "clear",
3910
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native28.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 16 }, children: [
3979
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native29.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 16 }, children: [
3911
3980
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3912
- import_react_native28.Pressable,
3981
+ import_react_native29.Pressable,
3913
3982
  {
3914
3983
  disabled: !onPressLike,
3915
3984
  onPress: onPressLike,
3916
3985
  hitSlop: 8,
3917
3986
  style: { paddingVertical: 8 },
3918
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native28.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
3987
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native29.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
3919
3988
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3920
3989
  import_lucide_react_native5.Heart,
3921
3990
  {
@@ -3925,7 +3994,7 @@ function StatsBar({
3925
3994
  fill: isLiked ? theme.colors.danger : "transparent"
3926
3995
  }
3927
3996
  ),
3928
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native28.View, { style: { width: 4 } }),
3997
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native29.View, { style: { width: 4 } }),
3929
3998
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3930
3999
  Text,
3931
4000
  {
@@ -3941,22 +4010,22 @@ function StatsBar({
3941
4010
  }
3942
4011
  ),
3943
4012
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3944
- import_react_native28.Pressable,
4013
+ import_react_native29.Pressable,
3945
4014
  {
3946
4015
  disabled: !onPressComments,
3947
4016
  onPress: onPressComments,
3948
4017
  hitSlop: 8,
3949
4018
  style: { paddingVertical: 8 },
3950
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native28.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
4019
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native29.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
3951
4020
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react_native5.MessageCircle, { size: 16, strokeWidth: 2.5, color: "#FFFFFF" }),
3952
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native28.View, { style: { width: 4 } }),
4021
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native29.View, { style: { width: 4 } }),
3953
4022
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: commentCount })
3954
4023
  ] })
3955
4024
  }
3956
4025
  ),
3957
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native28.View, { style: { flexDirection: "row", alignItems: "center", paddingVertical: 8 }, children: [
3958
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native28.View, { style: { transform: [{ scaleY: -1 }] }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(MergeIcon, { width: 14, height: 14, color: "#FFFFFF" }) }),
3959
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native28.View, { style: { width: 4 } }),
4026
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_native29.View, { style: { flexDirection: "row", alignItems: "center", paddingVertical: 8 }, children: [
4027
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native29.View, { style: { transform: [{ scaleY: -1 }] }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(MergeIcon, { width: 14, height: 14, color: "#FFFFFF" }) }),
4028
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native29.View, { style: { width: 4 } }),
3960
4029
  /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: forkCount })
3961
4030
  ] })
3962
4031
  ] })
@@ -3967,7 +4036,7 @@ function StatsBar({
3967
4036
  }
3968
4037
 
3969
4038
  // src/components/preview/PreviewStatusBadge.tsx
3970
- var import_react_native29 = require("react-native");
4039
+ var import_react_native30 = require("react-native");
3971
4040
  var import_lucide_react_native6 = require("lucide-react-native");
3972
4041
 
3973
4042
  // src/data/apps/types.ts
@@ -4012,7 +4081,7 @@ function PreviewStatusBadge({ status }) {
4012
4081
  const IconComp = STATUS_ICON[status];
4013
4082
  const label = APP_STATUS_LABEL[status] ?? status;
4014
4083
  return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
4015
- import_react_native29.View,
4084
+ import_react_native30.View,
4016
4085
  {
4017
4086
  style: {
4018
4087
  flexDirection: "row",
@@ -4065,10 +4134,10 @@ function PreviewHeroSection({
4065
4134
  }
4066
4135
 
4067
4136
  // src/studio/ui/preview-panel/PreviewMetaSection.tsx
4068
- var import_react_native31 = require("react-native");
4137
+ var import_react_native32 = require("react-native");
4069
4138
 
4070
4139
  // src/components/preview/PreviewMetaRow.tsx
4071
- var import_react_native30 = require("react-native");
4140
+ var import_react_native31 = require("react-native");
4072
4141
  var import_jsx_runtime32 = require("react/jsx-runtime");
4073
4142
  function PreviewMetaRow({
4074
4143
  avatarUri,
@@ -4080,10 +4149,10 @@ function PreviewMetaRow({
4080
4149
  style
4081
4150
  }) {
4082
4151
  const theme = useTheme();
4083
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native30.View, { style: [{ alignSelf: "stretch" }, style], children: [
4084
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native30.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
4152
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native31.View, { style: [{ alignSelf: "stretch" }, style], children: [
4153
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native31.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
4085
4154
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Avatar, { uri: avatarUri, name: creatorName, size: 24, style: { marginRight: theme.spacing.sm } }),
4086
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native30.View, { style: { flexDirection: "row", alignItems: "center", flex: 1, minWidth: 0, marginRight: theme.spacing.sm }, children: [
4155
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react_native31.View, { style: { flexDirection: "row", alignItems: "center", flex: 1, minWidth: 0, marginRight: theme.spacing.sm }, children: [
4087
4156
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4088
4157
  Text,
4089
4158
  {
@@ -4098,9 +4167,9 @@ function PreviewMetaRow({
4098
4167
  children: title
4099
4168
  }
4100
4169
  ),
4101
- tag ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_native30.View, { style: { marginLeft: theme.spacing.sm }, children: tag }) : null
4170
+ tag ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_native31.View, { style: { marginLeft: theme.spacing.sm }, children: tag }) : null
4102
4171
  ] }),
4103
- rightMetric ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_native30.View, { children: rightMetric }) : null
4172
+ rightMetric ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_native31.View, { children: rightMetric }) : null
4104
4173
  ] }),
4105
4174
  subtitle ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4106
4175
  Text,
@@ -4156,9 +4225,9 @@ function PreviewMetaSection({ app, isOwner, creator, downloadsCount }) {
4156
4225
  subtitle: app.description,
4157
4226
  avatarUri: (creator == null ? void 0 : creator.avatar) ?? null,
4158
4227
  creatorName: (creator == null ? void 0 : creator.name) ?? null,
4159
- tag: isOwner || app.forkedFromAppId ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_react_native31.View, { style: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: "#3700B3" }, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Text, { variant: "caption", style: { color: "#fff", fontWeight: theme.typography.fontWeight.semibold }, children: app.forkedFromAppId ? "Remix" : "Owner" }) }) : null,
4228
+ tag: isOwner || app.forkedFromAppId ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_react_native32.View, { style: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: "#3700B3" }, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Text, { variant: "caption", style: { color: "#fff", fontWeight: theme.typography.fontWeight.semibold }, children: app.forkedFromAppId ? "Remix" : "Owner" }) }) : null,
4160
4229
  rightMetric: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
4161
- import_react_native31.View,
4230
+ import_react_native32.View,
4162
4231
  {
4163
4232
  style: {
4164
4233
  flexDirection: "row",
@@ -4192,10 +4261,10 @@ function PreviewMetaSection({ app, isOwner, creator, downloadsCount }) {
4192
4261
  }
4193
4262
 
4194
4263
  // src/studio/ui/preview-panel/PreviewCustomizeSection.tsx
4195
- var import_react_native33 = require("react-native");
4264
+ var import_react_native34 = require("react-native");
4196
4265
 
4197
4266
  // src/studio/ui/preview-panel/PressableCardRow.tsx
4198
- var import_react_native32 = require("react-native");
4267
+ var import_react_native33 = require("react-native");
4199
4268
  var import_jsx_runtime34 = require("react/jsx-runtime");
4200
4269
  function PressableCardRow({
4201
4270
  accessibilityLabel,
@@ -4208,20 +4277,20 @@ function PressableCardRow({
4208
4277
  style
4209
4278
  }) {
4210
4279
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4211
- import_react_native32.Pressable,
4280
+ import_react_native33.Pressable,
4212
4281
  {
4213
4282
  accessibilityRole: "button",
4214
4283
  accessibilityLabel,
4215
4284
  disabled,
4216
4285
  onPress,
4217
4286
  style: ({ pressed }) => ({ opacity: disabled ? 0.6 : pressed ? 0.85 : 1 }),
4218
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Card, { padded: false, border: false, style, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react_native32.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
4287
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Card, { padded: false, border: false, style, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react_native33.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
4219
4288
  left,
4220
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react_native32.View, { style: { flex: 1, minWidth: 0 }, children: [
4289
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react_native33.View, { style: { flex: 1, minWidth: 0 }, children: [
4221
4290
  title,
4222
4291
  subtitle ? subtitle : null
4223
4292
  ] }),
4224
- right ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react_native32.View, { style: { marginLeft: 16 }, children: right }) : null
4293
+ right ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react_native33.View, { style: { marginLeft: 16 }, children: right }) : null
4225
4294
  ] }) })
4226
4295
  }
4227
4296
  );
@@ -4263,7 +4332,7 @@ function PreviewCustomizeSection({
4263
4332
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
4264
4333
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SectionTitle, { children: "Customize" }),
4265
4334
  showProcessing ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
4266
- import_react_native33.View,
4335
+ import_react_native34.View,
4267
4336
  {
4268
4337
  style: {
4269
4338
  flexDirection: "row",
@@ -4277,7 +4346,7 @@ function PreviewCustomizeSection({
4277
4346
  },
4278
4347
  children: [
4279
4348
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4280
- import_react_native33.View,
4349
+ import_react_native34.View,
4281
4350
  {
4282
4351
  style: {
4283
4352
  width: 40,
@@ -4288,10 +4357,10 @@ function PreviewCustomizeSection({
4288
4357
  backgroundColor: withAlpha(theme.colors.warning, 0.1),
4289
4358
  marginRight: theme.spacing.lg
4290
4359
  },
4291
- children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native33.ActivityIndicator, { color: theme.colors.warning, size: "small" })
4360
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native34.ActivityIndicator, { color: theme.colors.warning, size: "small" })
4292
4361
  }
4293
4362
  ),
4294
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native33.View, { style: { flex: 1, minWidth: 0 }, children: [
4363
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native34.View, { style: { flex: 1, minWidth: 0 }, children: [
4295
4364
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: app.status === "error" ? "Error" : "Processing" }),
4296
4365
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: statusDescription(app.status, app.statusError) })
4297
4366
  ] })
@@ -4312,7 +4381,7 @@ function PreviewCustomizeSection({
4312
4381
  marginBottom: theme.spacing.sm
4313
4382
  },
4314
4383
  left: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4315
- import_react_native33.View,
4384
+ import_react_native34.View,
4316
4385
  {
4317
4386
  style: {
4318
4387
  width: 40,
@@ -4345,7 +4414,7 @@ function PreviewCustomizeSection({
4345
4414
  marginBottom: theme.spacing.sm
4346
4415
  },
4347
4416
  left: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4348
- import_react_native33.View,
4417
+ import_react_native34.View,
4349
4418
  {
4350
4419
  style: {
4351
4420
  width: 40,
@@ -4368,17 +4437,17 @@ function PreviewCustomizeSection({
4368
4437
  }
4369
4438
 
4370
4439
  // src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
4371
- var React28 = __toESM(require("react"));
4372
- var import_react_native39 = require("react-native");
4440
+ var React29 = __toESM(require("react"));
4441
+ var import_react_native40 = require("react-native");
4373
4442
  var import_lucide_react_native9 = require("lucide-react-native");
4374
4443
 
4375
4444
  // src/components/merge-requests/MergeRequestStatusCard.tsx
4376
- var React24 = __toESM(require("react"));
4377
- var import_react_native35 = require("react-native");
4445
+ var React25 = __toESM(require("react"));
4446
+ var import_react_native36 = require("react-native");
4378
4447
  var import_lucide_react_native7 = require("lucide-react-native");
4379
4448
 
4380
4449
  // src/components/primitives/MarkdownText.tsx
4381
- var import_react_native34 = require("react-native");
4450
+ var import_react_native35 = require("react-native");
4382
4451
  var import_react_native_markdown_display = __toESM(require("react-native-markdown-display"));
4383
4452
  var import_jsx_runtime37 = require("react/jsx-runtime");
4384
4453
  function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
@@ -4391,7 +4460,7 @@ function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
4391
4460
  const codeTextColor = isDark ? "#FFFFFF" : theme.colors.text;
4392
4461
  const paragraphBottom = variant === "mergeRequest" ? 8 : 6;
4393
4462
  const baseLineHeight = variant === "mergeRequest" ? 22 : 20;
4394
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_react_native34.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4463
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_react_native35.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4395
4464
  import_react_native_markdown_display.default,
4396
4465
  {
4397
4466
  style: {
@@ -4404,7 +4473,7 @@ function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
4404
4473
  paddingHorizontal: variant === "mergeRequest" ? 6 : 4,
4405
4474
  paddingVertical: variant === "mergeRequest" ? 2 : 0,
4406
4475
  borderRadius: variant === "mergeRequest" ? 6 : 4,
4407
- fontFamily: import_react_native34.Platform.OS === "ios" ? "Menlo" : "monospace",
4476
+ fontFamily: import_react_native35.Platform.OS === "ios" ? "Menlo" : "monospace",
4408
4477
  fontSize: 13
4409
4478
  },
4410
4479
  code_block: {
@@ -4455,11 +4524,11 @@ function toIsoString(input) {
4455
4524
  }
4456
4525
 
4457
4526
  // src/components/merge-requests/useControlledExpansion.ts
4458
- var React23 = __toESM(require("react"));
4527
+ var React24 = __toESM(require("react"));
4459
4528
  function useControlledExpansion(props) {
4460
- const [uncontrolled, setUncontrolled] = React23.useState(false);
4529
+ const [uncontrolled, setUncontrolled] = React24.useState(false);
4461
4530
  const expanded = props.expanded ?? uncontrolled;
4462
- const setExpanded = React23.useCallback(
4531
+ const setExpanded = React24.useCallback(
4463
4532
  (next) => {
4464
4533
  var _a;
4465
4534
  (_a = props.onExpandedChange) == null ? void 0 : _a.call(props, next);
@@ -4484,8 +4553,8 @@ function MergeRequestStatusCard({
4484
4553
  const isDark = theme.scheme === "dark";
4485
4554
  const textColor = isDark ? "#FFFFFF" : "#000000";
4486
4555
  const subTextColor = isDark ? "#A1A1AA" : "#71717A";
4487
- const status = React24.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
4488
- const { StatusIcon, iconColor, bgColor, statusText } = React24.useMemo(() => {
4556
+ const status = React25.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
4557
+ const { StatusIcon, iconColor, bgColor, statusText } = React25.useMemo(() => {
4489
4558
  switch (mergeRequest.status) {
4490
4559
  case "approved":
4491
4560
  case "merged":
@@ -4516,15 +4585,15 @@ function MergeRequestStatusCard({
4516
4585
  const createdIso = toIsoString(mergeRequest.createdAt ?? null);
4517
4586
  const headerTimeAgo = updatedIso ? formatTimeAgo(updatedIso) : "";
4518
4587
  const createdTimeAgo = createdIso ? formatTimeAgo(createdIso) : "";
4519
- const rotate = React24.useRef(new import_react_native35.Animated.Value(expanded ? 1 : 0)).current;
4520
- React24.useEffect(() => {
4521
- import_react_native35.Animated.timing(rotate, {
4588
+ const rotate = React25.useRef(new import_react_native36.Animated.Value(expanded ? 1 : 0)).current;
4589
+ React25.useEffect(() => {
4590
+ import_react_native36.Animated.timing(rotate, {
4522
4591
  toValue: expanded ? 1 : 0,
4523
4592
  duration: 200,
4524
4593
  useNativeDriver: true
4525
4594
  }).start();
4526
4595
  }, [expanded, rotate]);
4527
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native35.Pressable, { onPress: () => setExpanded(!expanded), style: ({ pressed }) => [{ opacity: pressed ? 0.95 : 1 }], children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
4596
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native36.Pressable, { onPress: () => setExpanded(!expanded), style: ({ pressed }) => [{ opacity: pressed ? 0.95 : 1 }], children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
4528
4597
  Card,
4529
4598
  {
4530
4599
  padded: false,
@@ -4537,10 +4606,10 @@ function MergeRequestStatusCard({
4537
4606
  style
4538
4607
  ],
4539
4608
  children: [
4540
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native35.View, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.lg }, children: [
4541
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native35.View, { style: { width: 40, height: 40, borderRadius: 999, alignItems: "center", justifyContent: "center", backgroundColor: bgColor }, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StatusIcon, { size: 20, color: iconColor }) }),
4542
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native35.View, { style: { flex: 1, minWidth: 0 }, children: [
4543
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native35.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4609
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native36.View, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.lg }, children: [
4610
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native36.View, { style: { width: 40, height: 40, borderRadius: 999, alignItems: "center", justifyContent: "center", backgroundColor: bgColor }, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StatusIcon, { size: 20, color: iconColor }) }),
4611
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native36.View, { style: { flex: 1, minWidth: 0 }, children: [
4612
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native36.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4544
4613
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4545
4614
  Text,
4546
4615
  {
@@ -4559,8 +4628,8 @@ function MergeRequestStatusCard({
4559
4628
  ] }),
4560
4629
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, numberOfLines: 1, children: mergeRequest.title ?? "Untitled merge request" })
4561
4630
  ] }),
4562
- headerRight ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native35.View, { children: headerRight }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4563
- import_react_native35.Animated.View,
4631
+ headerRight ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_native36.View, { children: headerRight }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4632
+ import_react_native36.Animated.View,
4564
4633
  {
4565
4634
  style: {
4566
4635
  transform: [
@@ -4573,7 +4642,7 @@ function MergeRequestStatusCard({
4573
4642
  }
4574
4643
  )
4575
4644
  ] }),
4576
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native35.View, { style: { marginTop: 16, marginLeft: 56 }, children: [
4645
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react_native36.View, { style: { marginTop: 16, marginLeft: 56 }, children: [
4577
4646
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4578
4647
  Text,
4579
4648
  {
@@ -4608,17 +4677,17 @@ function MergeRequestStatusCard({
4608
4677
  }
4609
4678
 
4610
4679
  // src/components/merge-requests/ReviewMergeRequestCarousel.tsx
4611
- var React27 = __toESM(require("react"));
4612
- var import_react_native38 = require("react-native");
4680
+ var React28 = __toESM(require("react"));
4681
+ var import_react_native39 = require("react-native");
4613
4682
 
4614
4683
  // src/components/merge-requests/ReviewMergeRequestCard.tsx
4615
- var React26 = __toESM(require("react"));
4616
- var import_react_native37 = require("react-native");
4684
+ var React27 = __toESM(require("react"));
4685
+ var import_react_native38 = require("react-native");
4617
4686
  var import_lucide_react_native8 = require("lucide-react-native");
4618
4687
 
4619
4688
  // src/components/merge-requests/ReviewMergeRequestActionButton.tsx
4620
- var React25 = __toESM(require("react"));
4621
- var import_react_native36 = require("react-native");
4689
+ var React26 = __toESM(require("react"));
4690
+ var import_react_native37 = require("react-native");
4622
4691
  var import_jsx_runtime39 = require("react/jsx-runtime");
4623
4692
  function ReviewMergeRequestActionButton({
4624
4693
  accessibilityLabel,
@@ -4628,14 +4697,14 @@ function ReviewMergeRequestActionButton({
4628
4697
  children,
4629
4698
  iconOnly
4630
4699
  }) {
4631
- const [pressed, setPressed] = React25.useState(false);
4700
+ const [pressed, setPressed] = React26.useState(false);
4632
4701
  const height = iconOnly ? 36 : 40;
4633
4702
  const width = iconOnly ? 36 : void 0;
4634
4703
  const paddingHorizontal = iconOnly ? 0 : 16;
4635
4704
  const paddingVertical = iconOnly ? 0 : 8;
4636
4705
  const opacity = disabled ? 0.5 : pressed ? 0.9 : 1;
4637
4706
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4638
- import_react_native36.View,
4707
+ import_react_native37.View,
4639
4708
  {
4640
4709
  style: {
4641
4710
  width,
@@ -4650,7 +4719,7 @@ function ReviewMergeRequestActionButton({
4650
4719
  justifyContent: "center"
4651
4720
  },
4652
4721
  children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4653
- import_react_native36.Pressable,
4722
+ import_react_native37.Pressable,
4654
4723
  {
4655
4724
  accessibilityRole: "button",
4656
4725
  accessibilityLabel,
@@ -4690,14 +4759,14 @@ function ReviewMergeRequestCard({
4690
4759
  onTest
4691
4760
  }) {
4692
4761
  const theme = useTheme();
4693
- const status = React26.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
4762
+ const status = React27.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
4694
4763
  const canAct = mr.status === "open";
4695
- const rotate = React26.useRef(new import_react_native37.Animated.Value(isExpanded ? 1 : 0)).current;
4696
- React26.useEffect(() => {
4697
- import_react_native37.Animated.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
4764
+ const rotate = React27.useRef(new import_react_native38.Animated.Value(isExpanded ? 1 : 0)).current;
4765
+ React27.useEffect(() => {
4766
+ import_react_native38.Animated.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
4698
4767
  }, [isExpanded, rotate]);
4699
4768
  const position = total > 1 ? `${index + 1}/${total}` : "Merge request";
4700
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native37.Pressable, { onPress: onToggle, style: ({ pressed }) => ({ opacity: pressed ? 0.95 : 1 }), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
4769
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native38.Pressable, { onPress: onToggle, style: ({ pressed }) => ({ opacity: pressed ? 0.95 : 1 }), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
4701
4770
  Card,
4702
4771
  {
4703
4772
  padded: false,
@@ -4710,9 +4779,9 @@ function ReviewMergeRequestCard({
4710
4779
  }
4711
4780
  ],
4712
4781
  children: [
4713
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
4782
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
4714
4783
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Avatar, { size: 40, uri: (creator == null ? void 0 : creator.avatar) ?? null, name: (creator == null ? void 0 : creator.name) ?? void 0 }),
4715
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flex: 1, minWidth: 0 }, children: [
4784
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flex: 1, minWidth: 0 }, children: [
4716
4785
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4717
4786
  Text,
4718
4787
  {
@@ -4728,7 +4797,7 @@ function ReviewMergeRequestCard({
4728
4797
  ] })
4729
4798
  ] }),
4730
4799
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4731
- import_react_native37.Animated.View,
4800
+ import_react_native38.Animated.View,
4732
4801
  {
4733
4802
  style: {
4734
4803
  transform: [{ rotate: rotate.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "180deg"] }) }]
@@ -4737,7 +4806,7 @@ function ReviewMergeRequestCard({
4737
4806
  }
4738
4807
  )
4739
4808
  ] }),
4740
- isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { marginTop: 16 }, children: [
4809
+ isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { marginTop: 16 }, children: [
4741
4810
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4742
4811
  Text,
4743
4812
  {
@@ -4755,9 +4824,9 @@ function ReviewMergeRequestCard({
4755
4824
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginBottom: 12 }, children: creator ? `${creator.approvedOpenedMergeRequests} approved merge${creator.approvedOpenedMergeRequests !== 1 ? "s" : ""}` : "Loading stats..." }),
4756
4825
  mr.description ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MarkdownText, { markdown: mr.description, variant: "mergeRequest" }) : null
4757
4826
  ] }) : null,
4758
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native37.View, { style: { height: 1, backgroundColor: withAlpha(theme.colors.borderStrong, 0.5), marginTop: 12, marginBottom: 12 } }),
4759
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4760
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", gap: 8 }, children: [
4827
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native38.View, { style: { height: 1, backgroundColor: withAlpha(theme.colors.borderStrong, 0.5), marginTop: 12, marginBottom: 12 } }),
4828
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4829
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", gap: 8 }, children: [
4761
4830
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4762
4831
  ReviewMergeRequestActionButton,
4763
4832
  {
@@ -4766,7 +4835,7 @@ function ReviewMergeRequestCard({
4766
4835
  disabled: !canAct || isAnyProcessing,
4767
4836
  onPress: onReject,
4768
4837
  iconOnly: !isExpanded,
4769
- children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4838
+ children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4770
4839
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react_native8.X, { size: 18, color: "#FFFFFF" }),
4771
4840
  isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Reject" }) : null
4772
4841
  ] })
@@ -4780,10 +4849,10 @@ function ReviewMergeRequestCard({
4780
4849
  disabled: !canAct || isAnyProcessing,
4781
4850
  onPress: onApprove,
4782
4851
  iconOnly: !isExpanded,
4783
- children: isProcessing ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4784
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native37.ActivityIndicator, { size: "small", color: "#FFFFFF" }),
4852
+ children: isProcessing ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4853
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native38.ActivityIndicator, { size: "small", color: "#FFFFFF" }),
4785
4854
  isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Processing" }) : null
4786
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4855
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4787
4856
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react_native8.Check, { size: 18, color: "#FFFFFF" }),
4788
4857
  isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Approve" }) : null
4789
4858
  ] })
@@ -4798,7 +4867,7 @@ function ReviewMergeRequestCard({
4798
4867
  disabled: isBuilding || isTestingThis,
4799
4868
  onPress: onTest,
4800
4869
  iconOnly: !isExpanded,
4801
- children: isTestingThis ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native37.ActivityIndicator, { size: "small", color: "#888" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native37.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4870
+ children: isTestingThis ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native38.ActivityIndicator, { size: "small", color: "#888" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native38.View, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4802
4871
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react_native8.Play, { size: 14, color: theme.colors.text }),
4803
4872
  isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Text, { style: { fontSize: 13, color: theme.colors.text, fontWeight: theme.typography.fontWeight.semibold }, children: "Test" }) : null
4804
4873
  ] })
@@ -4824,32 +4893,32 @@ function ReviewMergeRequestCarousel({
4824
4893
  style
4825
4894
  }) {
4826
4895
  const theme = useTheme();
4827
- const { width } = (0, import_react_native38.useWindowDimensions)();
4828
- const [expanded, setExpanded] = React27.useState({});
4829
- const carouselScrollX = React27.useRef(new import_react_native38.Animated.Value(0)).current;
4896
+ const { width } = (0, import_react_native39.useWindowDimensions)();
4897
+ const [expanded, setExpanded] = React28.useState({});
4898
+ const carouselScrollX = React28.useRef(new import_react_native39.Animated.Value(0)).current;
4830
4899
  const peekAmount = 24;
4831
4900
  const gap = 16;
4832
- const cardWidth = React27.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
4901
+ const cardWidth = React28.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
4833
4902
  const snapInterval = cardWidth + gap;
4834
4903
  const dotColor = theme.scheme === "dark" ? "#FFFFFF" : "#000000";
4835
4904
  if (mergeRequests.length === 0) return null;
4836
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_native38.View, { style: [{ marginHorizontal: -theme.spacing.lg }, style], children: [
4905
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_native39.View, { style: [{ marginHorizontal: -theme.spacing.lg }, style], children: [
4837
4906
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4838
- import_react_native38.FlatList,
4907
+ import_react_native39.FlatList,
4839
4908
  {
4840
4909
  horizontal: true,
4841
4910
  data: mergeRequests,
4842
4911
  keyExtractor: (mr) => mr.id,
4843
4912
  showsHorizontalScrollIndicator: false,
4844
4913
  contentContainerStyle: { paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.sm },
4845
- ItemSeparatorComponent: () => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native38.View, { style: { width: gap } }),
4914
+ ItemSeparatorComponent: () => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native39.View, { style: { width: gap } }),
4846
4915
  snapToAlignment: "start",
4847
4916
  decelerationRate: "fast",
4848
4917
  snapToInterval: snapInterval,
4849
4918
  disableIntervalMomentum: true,
4850
4919
  style: { paddingRight: peekAmount },
4851
- ListFooterComponent: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native38.View, { style: { width: peekAmount } }),
4852
- onScroll: import_react_native38.Animated.event([{ nativeEvent: { contentOffset: { x: carouselScrollX } } }], {
4920
+ ListFooterComponent: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native39.View, { style: { width: peekAmount } }),
4921
+ onScroll: import_react_native39.Animated.event([{ nativeEvent: { contentOffset: { x: carouselScrollX } } }], {
4853
4922
  useNativeDriver: false
4854
4923
  }),
4855
4924
  scrollEventThrottle: 16,
@@ -4860,7 +4929,7 @@ function ReviewMergeRequestCarousel({
4860
4929
  const isProcessing = Boolean(processingMrId && processingMrId === item.id);
4861
4930
  const isAnyProcessing = Boolean(processingMrId);
4862
4931
  const isTestingThis = Boolean(testingMrId && testingMrId === item.id);
4863
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native38.View, { style: { width: cardWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4932
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native39.View, { style: { width: cardWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4864
4933
  ReviewMergeRequestCard,
4865
4934
  {
4866
4935
  mr: item,
@@ -4881,7 +4950,7 @@ function ReviewMergeRequestCarousel({
4881
4950
  }
4882
4951
  }
4883
4952
  ),
4884
- mergeRequests.length >= 1 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native38.View, { style: { flexDirection: "row", justifyContent: "center", columnGap: 8, marginTop: theme.spacing.md }, children: mergeRequests.map((mr, index) => {
4953
+ mergeRequests.length >= 1 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_native39.View, { style: { flexDirection: "row", justifyContent: "center", columnGap: 8, marginTop: theme.spacing.md }, children: mergeRequests.map((mr, index) => {
4885
4954
  const inputRange = [(index - 1) * snapInterval, index * snapInterval, (index + 1) * snapInterval];
4886
4955
  const scale = carouselScrollX.interpolate({
4887
4956
  inputRange,
@@ -4894,7 +4963,7 @@ function ReviewMergeRequestCarousel({
4894
4963
  extrapolate: "clamp"
4895
4964
  });
4896
4965
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4897
- import_react_native38.Animated.View,
4966
+ import_react_native39.Animated.View,
4898
4967
  {
4899
4968
  style: {
4900
4969
  width: 8,
@@ -4928,7 +4997,7 @@ function PreviewCollaborateSection({
4928
4997
  onTestMr
4929
4998
  }) {
4930
4999
  const theme = useTheme();
4931
- const [submittingMr, setSubmittingMr] = React28.useState(false);
5000
+ const [submittingMr, setSubmittingMr] = React29.useState(false);
4932
5001
  const hasSection = canSubmitMergeRequest || incomingMergeRequests.length > 0 || outgoingMergeRequests.length > 0;
4933
5002
  if (!hasSection) return null;
4934
5003
  const showActionsSubtitle = canSubmitMergeRequest && onSubmitMergeRequest || onTestMr && incomingMergeRequests.length > 0;
@@ -4955,7 +5024,7 @@ function PreviewCollaborateSection({
4955
5024
  accessibilityLabel: "Submit merge request",
4956
5025
  disabled: submittingMr,
4957
5026
  onPress: () => {
4958
- import_react_native39.Alert.alert(
5027
+ import_react_native40.Alert.alert(
4959
5028
  "Submit Merge Request",
4960
5029
  "Are you sure you want to submit your changes to the original app?",
4961
5030
  [
@@ -4981,7 +5050,7 @@ function PreviewCollaborateSection({
4981
5050
  marginBottom: theme.spacing.sm
4982
5051
  },
4983
5052
  left: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4984
- import_react_native39.View,
5053
+ import_react_native40.View,
4985
5054
  {
4986
5055
  style: {
4987
5056
  width: 40,
@@ -4992,7 +5061,7 @@ function PreviewCollaborateSection({
4992
5061
  backgroundColor: withAlpha("#03DAC6", 0.1),
4993
5062
  marginRight: theme.spacing.lg
4994
5063
  },
4995
- children: submittingMr ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react_native39.ActivityIndicator, { color: "#03DAC6", size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MergeIcon, { width: 20, height: 20, color: "#03DAC6" })
5064
+ children: submittingMr ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react_native40.ActivityIndicator, { color: "#03DAC6", size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MergeIcon, { width: 20, height: 20, color: "#03DAC6" })
4996
5065
  }
4997
5066
  ),
4998
5067
  title: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: "Submit your new changes" }),
@@ -5030,13 +5099,13 @@ function PreviewCollaborateSection({
5030
5099
  children: "History"
5031
5100
  }
5032
5101
  ),
5033
- outgoingMergeRequests.map((mr) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react_native39.View, { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MergeRequestStatusCard, { mergeRequest: toMergeRequestSummary(mr) }) }, mr.id))
5102
+ outgoingMergeRequests.map((mr) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react_native40.View, { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MergeRequestStatusCard, { mergeRequest: toMergeRequestSummary(mr) }) }, mr.id))
5034
5103
  ] }) : null
5035
5104
  ] });
5036
5105
  }
5037
5106
 
5038
5107
  // src/studio/ui/preview-panel/usePreviewPanelData.ts
5039
- var React30 = __toESM(require("react"));
5108
+ var React31 = __toESM(require("react"));
5040
5109
 
5041
5110
  // src/data/apps/images/remote.ts
5042
5111
  var AppImagesRemoteDataSourceImpl = class extends BaseRemote {
@@ -5087,7 +5156,7 @@ var AppImagesRepositoryImpl = class extends BaseRepository {
5087
5156
  var appImagesRepository = new AppImagesRepositoryImpl(appImagesRemoteDataSource);
5088
5157
 
5089
5158
  // src/studio/hooks/useAppStats.ts
5090
- var React29 = __toESM(require("react"));
5159
+ var React30 = __toESM(require("react"));
5091
5160
  var Haptics2 = __toESM(require("expo-haptics"));
5092
5161
 
5093
5162
  // src/data/likes/remote.ts
@@ -5156,34 +5225,34 @@ function useAppStats({
5156
5225
  initialIsLiked = false,
5157
5226
  onOpenComments
5158
5227
  }) {
5159
- const [likeCount, setLikeCount] = React29.useState(initialLikes);
5160
- const [commentCount, setCommentCount] = React29.useState(initialComments);
5161
- const [forkCount, setForkCount] = React29.useState(initialForks);
5162
- const [isLiked, setIsLiked] = React29.useState(initialIsLiked);
5163
- const didMutateRef = React29.useRef(false);
5164
- const lastAppIdRef = React29.useRef("");
5165
- React29.useEffect(() => {
5228
+ const [likeCount, setLikeCount] = React30.useState(initialLikes);
5229
+ const [commentCount, setCommentCount] = React30.useState(initialComments);
5230
+ const [forkCount, setForkCount] = React30.useState(initialForks);
5231
+ const [isLiked, setIsLiked] = React30.useState(initialIsLiked);
5232
+ const didMutateRef = React30.useRef(false);
5233
+ const lastAppIdRef = React30.useRef("");
5234
+ React30.useEffect(() => {
5166
5235
  if (lastAppIdRef.current === appId) return;
5167
5236
  lastAppIdRef.current = appId;
5168
5237
  didMutateRef.current = false;
5169
5238
  }, [appId]);
5170
- React29.useEffect(() => {
5239
+ React30.useEffect(() => {
5171
5240
  if (didMutateRef.current) return;
5172
5241
  setLikeCount(initialLikes);
5173
5242
  }, [appId, initialLikes]);
5174
- React29.useEffect(() => {
5243
+ React30.useEffect(() => {
5175
5244
  if (didMutateRef.current) return;
5176
5245
  setCommentCount(initialComments);
5177
5246
  }, [appId, initialComments]);
5178
- React29.useEffect(() => {
5247
+ React30.useEffect(() => {
5179
5248
  if (didMutateRef.current) return;
5180
5249
  setForkCount(initialForks);
5181
5250
  }, [appId, initialForks]);
5182
- React29.useEffect(() => {
5251
+ React30.useEffect(() => {
5183
5252
  if (didMutateRef.current) return;
5184
5253
  setIsLiked(initialIsLiked);
5185
5254
  }, [appId, initialIsLiked]);
5186
- const handleLike = React29.useCallback(async () => {
5255
+ const handleLike = React30.useCallback(async () => {
5187
5256
  var _a, _b;
5188
5257
  if (!appId) return;
5189
5258
  didMutateRef.current = true;
@@ -5207,7 +5276,7 @@ function useAppStats({
5207
5276
  setLikeCount((prev) => Math.max(0, prev + (newIsLiked ? -1 : 1)));
5208
5277
  }
5209
5278
  }, [appId, isLiked, likeCount]);
5210
- const handleOpenComments = React29.useCallback(() => {
5279
+ const handleOpenComments = React30.useCallback(() => {
5211
5280
  if (!appId) return;
5212
5281
  try {
5213
5282
  void Haptics2.impactAsync(Haptics2.ImpactFeedbackStyle.Light);
@@ -5222,11 +5291,11 @@ function useAppStats({
5222
5291
  var LIKE_DEBUG_PREFIX = "[COMERGE_LIKE_DEBUG]";
5223
5292
  function usePreviewPanelData(params) {
5224
5293
  const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
5225
- const [imageUrl, setImageUrl] = React30.useState(null);
5226
- const [imageLoaded, setImageLoaded] = React30.useState(false);
5227
- const [insights, setInsights] = React30.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
5228
- const [creator, setCreator] = React30.useState(null);
5229
- React30.useEffect(() => {
5294
+ const [imageUrl, setImageUrl] = React31.useState(null);
5295
+ const [imageLoaded, setImageLoaded] = React31.useState(false);
5296
+ const [insights, setInsights] = React31.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
5297
+ const [creator, setCreator] = React31.useState(null);
5298
+ React31.useEffect(() => {
5230
5299
  if (!(app == null ? void 0 : app.id)) return;
5231
5300
  let cancelled = false;
5232
5301
  (async () => {
@@ -5241,7 +5310,7 @@ function usePreviewPanelData(params) {
5241
5310
  cancelled = true;
5242
5311
  };
5243
5312
  }, [app == null ? void 0 : app.id]);
5244
- React30.useEffect(() => {
5313
+ React31.useEffect(() => {
5245
5314
  if (!(app == null ? void 0 : app.createdBy)) return;
5246
5315
  let cancelled = false;
5247
5316
  (async () => {
@@ -5257,10 +5326,10 @@ function usePreviewPanelData(params) {
5257
5326
  cancelled = true;
5258
5327
  };
5259
5328
  }, [app == null ? void 0 : app.createdBy]);
5260
- React30.useEffect(() => {
5329
+ React31.useEffect(() => {
5261
5330
  setImageLoaded(false);
5262
5331
  }, [app == null ? void 0 : app.id]);
5263
- React30.useEffect(() => {
5332
+ React31.useEffect(() => {
5264
5333
  if (!(app == null ? void 0 : app.id)) return;
5265
5334
  let cancelled = false;
5266
5335
  (async () => {
@@ -5285,7 +5354,7 @@ function usePreviewPanelData(params) {
5285
5354
  cancelled = true;
5286
5355
  };
5287
5356
  }, [app == null ? void 0 : app.id]);
5288
- React30.useEffect(() => {
5357
+ React31.useEffect(() => {
5289
5358
  if (!(app == null ? void 0 : app.id)) return;
5290
5359
  log.debug(
5291
5360
  `${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
@@ -5299,7 +5368,7 @@ function usePreviewPanelData(params) {
5299
5368
  initialIsLiked: Boolean(app == null ? void 0 : app.isLiked),
5300
5369
  onOpenComments
5301
5370
  });
5302
- const canSubmitMergeRequest = React30.useMemo(() => {
5371
+ const canSubmitMergeRequest = React31.useMemo(() => {
5303
5372
  if (!isOwner) return false;
5304
5373
  if (!app) return false;
5305
5374
  if (!app.forkedFromAppId) return false;
@@ -5354,9 +5423,9 @@ function PreviewPanel({
5354
5423
  });
5355
5424
  const header = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(PreviewPanelHeader, { isOwner, onClose, onNavigateHome, onGoToChat });
5356
5425
  if (loading || !app) {
5357
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(PreviewPage, { header, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react_native40.View, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: [
5358
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native40.ActivityIndicator, {}),
5359
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native40.View, { style: { height: 12 } }),
5426
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(PreviewPage, { header, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react_native41.View, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: [
5427
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native41.ActivityIndicator, {}),
5428
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native41.View, { style: { height: 12 } }),
5360
5429
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Text, { variant: "bodyMuted", children: "Loading app\u2026" })
5361
5430
  ] }) });
5362
5431
  }
@@ -5412,22 +5481,21 @@ function PreviewPanel({
5412
5481
  }
5413
5482
 
5414
5483
  // src/studio/ui/ChatPanel.tsx
5415
- var React35 = __toESM(require("react"));
5416
- var import_react_native48 = require("react-native");
5484
+ var React36 = __toESM(require("react"));
5485
+ var import_react_native49 = require("react-native");
5417
5486
 
5418
5487
  // src/components/chat/ChatPage.tsx
5419
- var React33 = __toESM(require("react"));
5420
- var import_react_native44 = require("react-native");
5488
+ var React34 = __toESM(require("react"));
5489
+ var import_react_native45 = require("react-native");
5421
5490
  var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
5422
- var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
5423
5491
 
5424
5492
  // src/components/chat/ChatMessageList.tsx
5425
- var React32 = __toESM(require("react"));
5426
- var import_react_native43 = require("react-native");
5493
+ var React33 = __toESM(require("react"));
5494
+ var import_react_native44 = require("react-native");
5427
5495
  var import_bottom_sheet5 = require("@gorhom/bottom-sheet");
5428
5496
 
5429
5497
  // src/components/chat/ChatMessageBubble.tsx
5430
- var import_react_native41 = require("react-native");
5498
+ var import_react_native42 = require("react-native");
5431
5499
  var import_lucide_react_native10 = require("lucide-react-native");
5432
5500
  var import_jsx_runtime44 = require("react/jsx-runtime");
5433
5501
  function ChatMessageBubble({ message, renderContent, style }) {
@@ -5443,7 +5511,7 @@ function ChatMessageBubble({ message, renderContent, style }) {
5443
5511
  const bubbleVariant = isHuman ? "surface" : "surfaceRaised";
5444
5512
  const cornerStyle = isHuman ? { borderTopRightRadius: 0 } : { borderTopLeftRadius: 0 };
5445
5513
  const bodyColor = metaStatus === "success" ? theme.colors.success : metaStatus === "error" ? theme.colors.danger : void 0;
5446
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native41.View, { style: [align, style], children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5514
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native42.View, { style: [align, style], children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
5447
5515
  Surface,
5448
5516
  {
5449
5517
  variant: bubbleVariant,
@@ -5458,34 +5526,34 @@ function ChatMessageBubble({ message, renderContent, style }) {
5458
5526
  },
5459
5527
  cornerStyle
5460
5528
  ],
5461
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native41.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5529
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native42.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5462
5530
  isMergeCompleted ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react_native10.CheckCheck, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
5463
5531
  isMergeApproved ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react_native10.GitMerge, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
5464
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native41.View, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
5532
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native42.View, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
5465
5533
  ] })
5466
5534
  }
5467
5535
  ) });
5468
5536
  }
5469
5537
 
5470
5538
  // src/components/chat/TypingIndicator.tsx
5471
- var React31 = __toESM(require("react"));
5472
- var import_react_native42 = require("react-native");
5539
+ var React32 = __toESM(require("react"));
5540
+ var import_react_native43 = require("react-native");
5473
5541
  var import_jsx_runtime45 = require("react/jsx-runtime");
5474
5542
  function TypingIndicator({ style }) {
5475
5543
  const theme = useTheme();
5476
5544
  const dotColor = theme.colors.textSubtle;
5477
- const anims = React31.useMemo(
5478
- () => [new import_react_native42.Animated.Value(0.3), new import_react_native42.Animated.Value(0.3), new import_react_native42.Animated.Value(0.3)],
5545
+ const anims = React32.useMemo(
5546
+ () => [new import_react_native43.Animated.Value(0.3), new import_react_native43.Animated.Value(0.3), new import_react_native43.Animated.Value(0.3)],
5479
5547
  []
5480
5548
  );
5481
- React31.useEffect(() => {
5549
+ React32.useEffect(() => {
5482
5550
  const loops = [];
5483
5551
  anims.forEach((a, idx) => {
5484
- const seq = import_react_native42.Animated.sequence([
5485
- import_react_native42.Animated.timing(a, { toValue: 1, duration: 420, useNativeDriver: true, delay: idx * 140 }),
5486
- import_react_native42.Animated.timing(a, { toValue: 0.3, duration: 420, useNativeDriver: true })
5552
+ const seq = import_react_native43.Animated.sequence([
5553
+ import_react_native43.Animated.timing(a, { toValue: 1, duration: 420, useNativeDriver: true, delay: idx * 140 }),
5554
+ import_react_native43.Animated.timing(a, { toValue: 0.3, duration: 420, useNativeDriver: true })
5487
5555
  ]);
5488
- const loop = import_react_native42.Animated.loop(seq);
5556
+ const loop = import_react_native43.Animated.loop(seq);
5489
5557
  loops.push(loop);
5490
5558
  loop.start();
5491
5559
  });
@@ -5493,8 +5561,8 @@ function TypingIndicator({ style }) {
5493
5561
  loops.forEach((l) => l.stop());
5494
5562
  };
5495
5563
  }, [anims]);
5496
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_react_native42.View, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5497
- import_react_native42.Animated.View,
5564
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_react_native43.View, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
5565
+ import_react_native43.Animated.View,
5498
5566
  {
5499
5567
  style: {
5500
5568
  width: 8,
@@ -5503,7 +5571,7 @@ function TypingIndicator({ style }) {
5503
5571
  marginHorizontal: 3,
5504
5572
  backgroundColor: dotColor,
5505
5573
  opacity: a,
5506
- transform: [{ translateY: import_react_native42.Animated.multiply(import_react_native42.Animated.subtract(a, 0.3), 2) }]
5574
+ transform: [{ translateY: import_react_native43.Animated.multiply(import_react_native43.Animated.subtract(a, 0.3), 2) }]
5507
5575
  }
5508
5576
  },
5509
5577
  i
@@ -5512,39 +5580,43 @@ function TypingIndicator({ style }) {
5512
5580
 
5513
5581
  // src/components/chat/ChatMessageList.tsx
5514
5582
  var import_jsx_runtime46 = require("react/jsx-runtime");
5515
- var ChatMessageList = React32.forwardRef(
5583
+ var ChatMessageList = React33.forwardRef(
5516
5584
  ({
5517
5585
  messages,
5518
5586
  showTypingIndicator = false,
5519
5587
  renderMessageContent,
5520
5588
  contentStyle,
5589
+ bottomInset = 0,
5521
5590
  onNearBottomChange,
5522
5591
  nearBottomThreshold = 200
5523
5592
  }, ref) => {
5524
5593
  const theme = useTheme();
5525
- const listRef = React32.useRef(null);
5526
- const nearBottomRef = React32.useRef(true);
5527
- const initialScrollDoneRef = React32.useRef(false);
5528
- const lastMessageIdRef = React32.useRef(null);
5529
- const scrollToBottom = React32.useCallback((options) => {
5594
+ const listRef = React33.useRef(null);
5595
+ const nearBottomRef = React33.useRef(true);
5596
+ const initialScrollDoneRef = React33.useRef(false);
5597
+ const lastMessageIdRef = React33.useRef(null);
5598
+ const scrollToBottom = React33.useCallback((options) => {
5530
5599
  var _a;
5531
5600
  const animated = (options == null ? void 0 : options.animated) ?? true;
5532
5601
  (_a = listRef.current) == null ? void 0 : _a.scrollToEnd({ animated });
5533
5602
  }, []);
5534
- React32.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
5535
- const handleScroll = React32.useCallback(
5603
+ React33.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
5604
+ const handleScroll = React33.useCallback(
5536
5605
  (e) => {
5537
5606
  const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
5538
- const distanceFromBottom = Math.max(contentSize.height - (contentOffset.y + layoutMeasurement.height), 0);
5607
+ const distanceFromBottom = Math.max(
5608
+ contentSize.height - Math.max(bottomInset, 0) - (contentOffset.y + layoutMeasurement.height),
5609
+ 0
5610
+ );
5539
5611
  const isNear = distanceFromBottom <= nearBottomThreshold;
5540
5612
  if (nearBottomRef.current !== isNear) {
5541
5613
  nearBottomRef.current = isNear;
5542
5614
  onNearBottomChange == null ? void 0 : onNearBottomChange(isNear);
5543
5615
  }
5544
5616
  },
5545
- [nearBottomThreshold, onNearBottomChange]
5617
+ [bottomInset, nearBottomThreshold, onNearBottomChange]
5546
5618
  );
5547
- React32.useEffect(() => {
5619
+ React33.useEffect(() => {
5548
5620
  var _a;
5549
5621
  if (initialScrollDoneRef.current) return;
5550
5622
  if (messages.length === 0) return;
@@ -5553,7 +5625,7 @@ var ChatMessageList = React32.forwardRef(
5553
5625
  const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
5554
5626
  return () => cancelAnimationFrame(id);
5555
5627
  }, [messages, scrollToBottom]);
5556
- React32.useEffect(() => {
5628
+ React33.useEffect(() => {
5557
5629
  if (!initialScrollDoneRef.current) return;
5558
5630
  const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
5559
5631
  const prevLastId = lastMessageIdRef.current;
@@ -5563,19 +5635,27 @@ var ChatMessageList = React32.forwardRef(
5563
5635
  const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
5564
5636
  return () => cancelAnimationFrame(id);
5565
5637
  }, [messages, scrollToBottom]);
5566
- React32.useEffect(() => {
5638
+ React33.useEffect(() => {
5567
5639
  if (showTypingIndicator && nearBottomRef.current) {
5568
5640
  const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
5569
5641
  return () => cancelAnimationFrame(id);
5570
5642
  }
5571
5643
  return void 0;
5572
5644
  }, [showTypingIndicator, scrollToBottom]);
5645
+ React33.useEffect(() => {
5646
+ if (!initialScrollDoneRef.current) return;
5647
+ if (!nearBottomRef.current) return;
5648
+ const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
5649
+ return () => cancelAnimationFrame(id);
5650
+ }, [bottomInset, scrollToBottom]);
5573
5651
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
5574
5652
  import_bottom_sheet5.BottomSheetFlatList,
5575
5653
  {
5576
5654
  ref: listRef,
5577
5655
  data: messages,
5578
5656
  keyExtractor: (m) => m.id,
5657
+ keyboardDismissMode: import_react_native44.Platform.OS === "ios" ? "interactive" : "on-drag",
5658
+ keyboardShouldPersistTaps: "handled",
5579
5659
  onScroll: handleScroll,
5580
5660
  scrollEventThrottle: 16,
5581
5661
  showsVerticalScrollIndicator: false,
@@ -5583,13 +5663,15 @@ var ChatMessageList = React32.forwardRef(
5583
5663
  {
5584
5664
  paddingHorizontal: theme.spacing.lg,
5585
5665
  paddingTop: theme.spacing.sm,
5586
- paddingBottom: theme.spacing.xl
5666
+ paddingBottom: theme.spacing.sm
5587
5667
  },
5588
5668
  contentStyle
5589
5669
  ],
5590
- renderItem: ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react_native43.View, { style: { marginTop: index === 0 ? 0 : theme.spacing.sm }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChatMessageBubble, { message: item, renderContent: renderMessageContent }) }),
5591
- ListFooterComponent: showTypingIndicator ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react_native43.View, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(TypingIndicator, {}) }) : null,
5592
- maintainVisibleContentPosition: { minIndexForVisible: 0, autoscrollToTopThreshold: nearBottomThreshold }
5670
+ renderItem: ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react_native44.View, { style: { marginTop: index === 0 ? 0 : theme.spacing.sm }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChatMessageBubble, { message: item, renderContent: renderMessageContent }) }),
5671
+ ListFooterComponent: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_react_native44.View, { children: [
5672
+ showTypingIndicator ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react_native44.View, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(TypingIndicator, {}) }) : null,
5673
+ bottomInset > 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_react_native44.View, { style: { height: bottomInset } }) : null
5674
+ ] })
5593
5675
  }
5594
5676
  );
5595
5677
  }
@@ -5612,63 +5694,65 @@ function ChatPage({
5612
5694
  }) {
5613
5695
  const theme = useTheme();
5614
5696
  const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
5615
- const [composerHeight, setComposerHeight] = React33.useState(0);
5616
- const [keyboardVisible, setKeyboardVisible] = React33.useState(false);
5617
- const animatedKeyboard = (0, import_react_native_reanimated2.useAnimatedKeyboard)();
5618
- React33.useEffect(() => {
5619
- if (import_react_native44.Platform.OS !== "ios") return;
5620
- const show = import_react_native44.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
5621
- const hide = import_react_native44.Keyboard.addListener("keyboardWillHide", () => setKeyboardVisible(false));
5697
+ const [composerHeight, setComposerHeight] = React34.useState(0);
5698
+ const [keyboardVisible, setKeyboardVisible] = React34.useState(false);
5699
+ React34.useEffect(() => {
5700
+ if (import_react_native45.Platform.OS !== "ios") return;
5701
+ const show = import_react_native45.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
5702
+ const hide = import_react_native45.Keyboard.addListener("keyboardWillHide", () => setKeyboardVisible(false));
5622
5703
  return () => {
5623
5704
  show.remove();
5624
5705
  hide.remove();
5625
5706
  };
5626
5707
  }, []);
5627
- const footerBottomPadding = import_react_native44.Platform.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
5628
- const footerAnimatedStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => {
5629
- if (import_react_native44.Platform.OS !== "ios") return { paddingBottom: insets.bottom + 10 };
5630
- return { paddingBottom: animatedKeyboard.height.value > 0 ? 0 : insets.bottom };
5631
- });
5708
+ const footerBottomPadding = import_react_native45.Platform.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
5632
5709
  const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
5633
- const resolvedOverlay = React33.useMemo(() => {
5710
+ const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
5711
+ const resolvedOverlay = React34.useMemo(() => {
5634
5712
  var _a;
5635
5713
  if (!overlay) return null;
5636
- if (!React33.isValidElement(overlay)) return overlay;
5714
+ if (!React34.isValidElement(overlay)) return overlay;
5637
5715
  const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
5638
- return React33.cloneElement(overlay, {
5716
+ return React34.cloneElement(overlay, {
5639
5717
  style: [prevStyle, { bottom: overlayBottom }]
5640
5718
  });
5641
5719
  }, [overlay, overlayBottom]);
5642
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native44.View, { style: [{ flex: 1 }, style], children: [
5643
- header ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native44.View, { children: header }) : null,
5644
- topBanner ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native44.View, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
5645
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native44.View, { style: { flex: 1 }, children: [
5646
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5647
- ChatMessageList,
5720
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native45.View, { style: [{ flex: 1 }, style], children: [
5721
+ header ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native45.View, { children: header }) : null,
5722
+ topBanner ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native45.View, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
5723
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native45.View, { style: { flex: 1 }, children: [
5724
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
5725
+ import_react_native45.View,
5648
5726
  {
5649
- ref: listRef,
5650
- messages,
5651
- showTypingIndicator,
5652
- renderMessageContent,
5653
- onNearBottomChange,
5654
- contentStyle: { paddingBottom: theme.spacing.xl + composerHeight + footerBottomPadding }
5727
+ style: { flex: 1 },
5728
+ children: [
5729
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5730
+ ChatMessageList,
5731
+ {
5732
+ ref: listRef,
5733
+ messages,
5734
+ showTypingIndicator,
5735
+ renderMessageContent,
5736
+ onNearBottomChange,
5737
+ bottomInset
5738
+ }
5739
+ ),
5740
+ resolvedOverlay
5741
+ ]
5655
5742
  }
5656
5743
  ),
5657
- resolvedOverlay,
5658
5744
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5659
- import_react_native_reanimated2.default.View,
5745
+ import_react_native45.View,
5660
5746
  {
5661
- style: [
5662
- {
5663
- position: "absolute",
5664
- left: 0,
5665
- right: 0,
5666
- bottom: 0,
5667
- paddingHorizontal: theme.spacing.lg,
5668
- paddingTop: theme.spacing.sm
5669
- },
5670
- footerAnimatedStyle
5671
- ],
5747
+ style: {
5748
+ position: "absolute",
5749
+ left: 0,
5750
+ right: 0,
5751
+ bottom: 0,
5752
+ paddingHorizontal: theme.spacing.lg,
5753
+ paddingTop: theme.spacing.sm,
5754
+ paddingBottom: footerBottomPadding
5755
+ },
5672
5756
  children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
5673
5757
  ChatComposer,
5674
5758
  {
@@ -5684,25 +5768,25 @@ function ChatPage({
5684
5768
  }
5685
5769
 
5686
5770
  // src/components/chat/ScrollToBottomButton.tsx
5687
- var React34 = __toESM(require("react"));
5688
- var import_react_native45 = require("react-native");
5689
- var import_react_native_reanimated3 = __toESM(require("react-native-reanimated"));
5771
+ var React35 = __toESM(require("react"));
5772
+ var import_react_native46 = require("react-native");
5773
+ var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
5690
5774
  var import_jsx_runtime48 = require("react/jsx-runtime");
5691
5775
  function ScrollToBottomButton({ visible, onPress, children, style }) {
5692
5776
  const theme = useTheme();
5693
- const progress = (0, import_react_native_reanimated3.useSharedValue)(visible ? 1 : 0);
5694
- const [pressed, setPressed] = React34.useState(false);
5695
- React34.useEffect(() => {
5696
- progress.value = (0, import_react_native_reanimated3.withTiming)(visible ? 1 : 0, { duration: 200, easing: import_react_native_reanimated3.Easing.out(import_react_native_reanimated3.Easing.ease) });
5777
+ const progress = (0, import_react_native_reanimated2.useSharedValue)(visible ? 1 : 0);
5778
+ const [pressed, setPressed] = React35.useState(false);
5779
+ React35.useEffect(() => {
5780
+ progress.value = (0, import_react_native_reanimated2.withTiming)(visible ? 1 : 0, { duration: 200, easing: import_react_native_reanimated2.Easing.out(import_react_native_reanimated2.Easing.ease) });
5697
5781
  }, [progress, visible]);
5698
- const animStyle = (0, import_react_native_reanimated3.useAnimatedStyle)(() => ({
5782
+ const animStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => ({
5699
5783
  opacity: progress.value,
5700
5784
  transform: [{ translateY: (1 - progress.value) * 20 }]
5701
5785
  }));
5702
5786
  const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
5703
5787
  const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
5704
5788
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5705
- import_react_native_reanimated3.default.View,
5789
+ import_react_native_reanimated2.default.View,
5706
5790
  {
5707
5791
  pointerEvents: visible ? "auto" : "none",
5708
5792
  style: [
@@ -5716,7 +5800,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5716
5800
  animStyle
5717
5801
  ],
5718
5802
  children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5719
- import_react_native45.View,
5803
+ import_react_native46.View,
5720
5804
  {
5721
5805
  style: {
5722
5806
  width: 44,
@@ -5735,7 +5819,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5735
5819
  opacity: pressed ? 0.85 : 1
5736
5820
  },
5737
5821
  children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
5738
- import_react_native45.Pressable,
5822
+ import_react_native46.Pressable,
5739
5823
  {
5740
5824
  onPress,
5741
5825
  onPressIn: () => setPressed(true),
@@ -5752,10 +5836,10 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5752
5836
  }
5753
5837
 
5754
5838
  // src/components/chat/ChatHeader.tsx
5755
- var import_react_native46 = require("react-native");
5839
+ var import_react_native47 = require("react-native");
5756
5840
  var import_jsx_runtime49 = require("react/jsx-runtime");
5757
5841
  function ChatHeader({ left, right, center, style }) {
5758
- const flattenedStyle = import_react_native46.StyleSheet.flatten([
5842
+ const flattenedStyle = import_react_native47.StyleSheet.flatten([
5759
5843
  {
5760
5844
  paddingTop: 0
5761
5845
  },
@@ -5773,7 +5857,7 @@ function ChatHeader({ left, right, center, style }) {
5773
5857
  }
5774
5858
 
5775
5859
  // src/components/chat/ForkNoticeBanner.tsx
5776
- var import_react_native47 = require("react-native");
5860
+ var import_react_native48 = require("react-native");
5777
5861
  var import_jsx_runtime50 = require("react/jsx-runtime");
5778
5862
  function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5779
5863
  const theme = useTheme();
@@ -5794,7 +5878,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5794
5878
  },
5795
5879
  style
5796
5880
  ],
5797
- children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native47.View, { style: { minWidth: 0 }, children: [
5881
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native48.View, { style: { minWidth: 0 }, children: [
5798
5882
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
5799
5883
  Text,
5800
5884
  {
@@ -5847,32 +5931,34 @@ function ChatPanel({
5847
5931
  onStartDraw,
5848
5932
  onSend
5849
5933
  }) {
5850
- const listRef = React35.useRef(null);
5851
- const [nearBottom, setNearBottom] = React35.useState(true);
5852
- const handleSend = React35.useCallback(
5934
+ const listRef = React36.useRef(null);
5935
+ const [nearBottom, setNearBottom] = React36.useState(true);
5936
+ const handleSend = React36.useCallback(
5853
5937
  async (text, composerAttachments) => {
5854
5938
  const all = composerAttachments ?? attachments;
5855
5939
  await onSend(text, all.length > 0 ? all : void 0);
5856
5940
  onClearAttachments == null ? void 0 : onClearAttachments();
5857
- requestAnimationFrame(() => {
5858
- var _a;
5859
- return (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
5860
- });
5941
+ if (!nearBottom) {
5942
+ requestAnimationFrame(() => {
5943
+ var _a;
5944
+ return (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
5945
+ });
5946
+ }
5861
5947
  },
5862
- [attachments, onClearAttachments, onSend]
5948
+ [attachments, nearBottom, onClearAttachments, onSend]
5863
5949
  );
5864
- const handleScrollToBottom = React35.useCallback(() => {
5950
+ const handleScrollToBottom = React36.useCallback(() => {
5865
5951
  var _a;
5866
5952
  (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
5867
5953
  }, []);
5868
5954
  const header = /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
5869
5955
  ChatHeader,
5870
5956
  {
5871
- left: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native48.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5957
+ left: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native49.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5872
5958
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(IconBack, { size: 20, colorToken: "floatingContent" }) }),
5873
5959
  onNavigateHome ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
5874
5960
  ] }),
5875
- right: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native48.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5961
+ right: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native49.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
5876
5962
  onStartDraw ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
5877
5963
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(IconClose, { size: 20, colorToken: "floatingContent" }) })
5878
5964
  ] }),
@@ -5888,12 +5974,12 @@ function ChatPanel({
5888
5974
  ) : null;
5889
5975
  const showMessagesLoading = Boolean(loading) && messages.length === 0 || forking;
5890
5976
  if (showMessagesLoading) {
5891
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native48.View, { style: { flex: 1 }, children: [
5892
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native48.View, { children: header }),
5893
- topBanner ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native48.View, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
5894
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native48.View, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
5895
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native48.ActivityIndicator, {}),
5896
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native48.View, { style: { height: 12 } }),
5977
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native49.View, { style: { flex: 1 }, children: [
5978
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native49.View, { children: header }),
5979
+ topBanner ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native49.View, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
5980
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_native49.View, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
5981
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native49.ActivityIndicator, {}),
5982
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native49.View, { style: { height: 12 } }),
5897
5983
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
5898
5984
  ] })
5899
5985
  ] });
@@ -5917,7 +6003,10 @@ function ChatPanel({
5917
6003
  }
5918
6004
  ),
5919
6005
  composer: {
5920
- disabled: Boolean(loading) || Boolean(sendDisabled) || Boolean(forking),
6006
+ // Keep the input editable even when sending is disallowed (e.g. agent still working),
6007
+ // otherwise iOS will drop focus/keyboard and BottomSheet can get "stuck" with a keyboard-sized gap.
6008
+ disabled: Boolean(loading) || Boolean(forking),
6009
+ sendDisabled: Boolean(sendDisabled) || Boolean(loading) || Boolean(forking),
5921
6010
  sending: Boolean(sending),
5922
6011
  autoFocus: autoFocusComposer,
5923
6012
  onSend: handleSend,
@@ -5931,11 +6020,11 @@ function ChatPanel({
5931
6020
  }
5932
6021
 
5933
6022
  // src/components/dialogs/ConfirmMergeRequestDialog.tsx
5934
- var React36 = __toESM(require("react"));
5935
- var import_react_native50 = require("react-native");
6023
+ var React37 = __toESM(require("react"));
6024
+ var import_react_native51 = require("react-native");
5936
6025
 
5937
6026
  // src/components/primitives/Modal.tsx
5938
- var import_react_native49 = require("react-native");
6027
+ var import_react_native50 = require("react-native");
5939
6028
  var import_jsx_runtime52 = require("react/jsx-runtime");
5940
6029
  function Modal({
5941
6030
  visible,
@@ -5946,15 +6035,15 @@ function Modal({
5946
6035
  }) {
5947
6036
  const theme = useTheme();
5948
6037
  return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
5949
- import_react_native49.Modal,
6038
+ import_react_native50.Modal,
5950
6039
  {
5951
6040
  visible,
5952
6041
  transparent: true,
5953
6042
  animationType: "fade",
5954
6043
  onRequestClose,
5955
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_react_native49.View, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
6044
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_react_native50.View, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
5956
6045
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
5957
- import_react_native49.Pressable,
6046
+ import_react_native50.Pressable,
5958
6047
  {
5959
6048
  accessibilityRole: "button",
5960
6049
  onPress: dismissOnBackdropPress ? onRequestClose : void 0,
@@ -5979,14 +6068,14 @@ function ConfirmMergeRequestDialog({
5979
6068
  onTestFirst
5980
6069
  }) {
5981
6070
  const theme = useTheme();
5982
- const close = React36.useCallback(() => onOpenChange(false), [onOpenChange]);
6071
+ const close = React37.useCallback(() => onOpenChange(false), [onOpenChange]);
5983
6072
  const canConfirm = Boolean(mergeRequest) && !approveDisabled;
5984
- const handleConfirm = React36.useCallback(() => {
6073
+ const handleConfirm = React37.useCallback(() => {
5985
6074
  if (!mergeRequest) return;
5986
6075
  onOpenChange(false);
5987
6076
  void onConfirm();
5988
6077
  }, [mergeRequest, onConfirm, onOpenChange]);
5989
- const handleTestFirst = React36.useCallback(() => {
6078
+ const handleTestFirst = React37.useCallback(() => {
5990
6079
  if (!mergeRequest) return;
5991
6080
  onOpenChange(false);
5992
6081
  void onTestFirst(mergeRequest);
@@ -6009,7 +6098,7 @@ function ConfirmMergeRequestDialog({
6009
6098
  backgroundColor: theme.colors.background
6010
6099
  },
6011
6100
  children: [
6012
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native50.View, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6101
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native51.View, { children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6013
6102
  Text,
6014
6103
  {
6015
6104
  style: {
@@ -6021,9 +6110,9 @@ function ConfirmMergeRequestDialog({
6021
6110
  children: "Are you sure you want to approve this merge request?"
6022
6111
  }
6023
6112
  ) }),
6024
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native50.View, { style: { marginTop: 16 }, children: [
6113
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native51.View, { style: { marginTop: 16 }, children: [
6025
6114
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6026
- import_react_native50.View,
6115
+ import_react_native51.View,
6027
6116
  {
6028
6117
  style: [
6029
6118
  fullWidthButtonBase,
@@ -6033,7 +6122,7 @@ function ConfirmMergeRequestDialog({
6033
6122
  }
6034
6123
  ],
6035
6124
  children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6036
- import_react_native50.Pressable,
6125
+ import_react_native51.Pressable,
6037
6126
  {
6038
6127
  accessibilityRole: "button",
6039
6128
  accessibilityLabel: "Approve Merge",
@@ -6045,9 +6134,9 @@ function ConfirmMergeRequestDialog({
6045
6134
  )
6046
6135
  }
6047
6136
  ),
6048
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native50.View, { style: { height: 8 } }),
6137
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native51.View, { style: { height: 8 } }),
6049
6138
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6050
- import_react_native50.View,
6139
+ import_react_native51.View,
6051
6140
  {
6052
6141
  style: [
6053
6142
  fullWidthButtonBase,
@@ -6059,7 +6148,7 @@ function ConfirmMergeRequestDialog({
6059
6148
  }
6060
6149
  ],
6061
6150
  children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6062
- import_react_native50.Pressable,
6151
+ import_react_native51.Pressable,
6063
6152
  {
6064
6153
  accessibilityRole: "button",
6065
6154
  accessibilityLabel: isBuilding ? "Preparing\u2026" : "Test edits first",
@@ -6071,9 +6160,9 @@ function ConfirmMergeRequestDialog({
6071
6160
  )
6072
6161
  }
6073
6162
  ),
6074
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native50.View, { style: { height: 8 } }),
6163
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native51.View, { style: { height: 8 } }),
6075
6164
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6076
- import_react_native50.View,
6165
+ import_react_native51.View,
6077
6166
  {
6078
6167
  style: [
6079
6168
  fullWidthButtonBase,
@@ -6084,7 +6173,7 @@ function ConfirmMergeRequestDialog({
6084
6173
  }
6085
6174
  ],
6086
6175
  children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
6087
- import_react_native50.Pressable,
6176
+ import_react_native51.Pressable,
6088
6177
  {
6089
6178
  accessibilityRole: "button",
6090
6179
  accessibilityLabel: "Cancel",
@@ -6165,30 +6254,33 @@ function StudioOverlay({
6165
6254
  onNavigateHome
6166
6255
  }) {
6167
6256
  const theme = useTheme();
6168
- const { width } = (0, import_react_native51.useWindowDimensions)();
6169
- const [sheetOpen, setSheetOpen] = React37.useState(false);
6170
- const [activePage, setActivePage] = React37.useState("preview");
6171
- const [drawing, setDrawing] = React37.useState(false);
6172
- const [chatAttachments, setChatAttachments] = React37.useState([]);
6173
- const [commentsAppId, setCommentsAppId] = React37.useState(null);
6174
- const [commentsCount, setCommentsCount] = React37.useState(null);
6175
- const [confirmMrId, setConfirmMrId] = React37.useState(null);
6176
- const confirmMr = React37.useMemo(
6257
+ const { width } = (0, import_react_native52.useWindowDimensions)();
6258
+ const [sheetOpen, setSheetOpen] = React38.useState(false);
6259
+ const [activePage, setActivePage] = React38.useState("preview");
6260
+ const [drawing, setDrawing] = React38.useState(false);
6261
+ const [chatAttachments, setChatAttachments] = React38.useState([]);
6262
+ const [commentsAppId, setCommentsAppId] = React38.useState(null);
6263
+ const [commentsCount, setCommentsCount] = React38.useState(null);
6264
+ const [confirmMrId, setConfirmMrId] = React38.useState(null);
6265
+ const confirmMr = React38.useMemo(
6177
6266
  () => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
6178
6267
  [confirmMrId, incomingMergeRequests]
6179
6268
  );
6180
- const closeSheet = React37.useCallback(() => {
6181
- setSheetOpen(false);
6182
- import_react_native51.Keyboard.dismiss();
6269
+ const handleSheetOpenChange = React38.useCallback((open) => {
6270
+ setSheetOpen(open);
6271
+ if (!open) import_react_native52.Keyboard.dismiss();
6183
6272
  }, []);
6184
- const openSheet = React37.useCallback(() => setSheetOpen(true), []);
6185
- const goToChat = React37.useCallback(() => {
6273
+ const closeSheet = React38.useCallback(() => {
6274
+ handleSheetOpenChange(false);
6275
+ }, [handleSheetOpenChange]);
6276
+ const openSheet = React38.useCallback(() => setSheetOpen(true), []);
6277
+ const goToChat = React38.useCallback(() => {
6186
6278
  setActivePage("chat");
6187
6279
  openSheet();
6188
6280
  }, [openSheet]);
6189
- const backToPreview = React37.useCallback(() => {
6190
- if (import_react_native51.Platform.OS !== "ios") {
6191
- import_react_native51.Keyboard.dismiss();
6281
+ const backToPreview = React38.useCallback(() => {
6282
+ if (import_react_native52.Platform.OS !== "ios") {
6283
+ import_react_native52.Keyboard.dismiss();
6192
6284
  setActivePage("preview");
6193
6285
  return;
6194
6286
  }
@@ -6200,15 +6292,15 @@ function StudioOverlay({
6200
6292
  clearTimeout(t);
6201
6293
  setActivePage("preview");
6202
6294
  };
6203
- const sub = import_react_native51.Keyboard.addListener("keyboardDidHide", finalize);
6295
+ const sub = import_react_native52.Keyboard.addListener("keyboardDidHide", finalize);
6204
6296
  const t = setTimeout(finalize, 350);
6205
- import_react_native51.Keyboard.dismiss();
6297
+ import_react_native52.Keyboard.dismiss();
6206
6298
  }, []);
6207
- const startDraw = React37.useCallback(() => {
6299
+ const startDraw = React38.useCallback(() => {
6208
6300
  setDrawing(true);
6209
6301
  closeSheet();
6210
6302
  }, [closeSheet]);
6211
- const handleDrawCapture = React37.useCallback(
6303
+ const handleDrawCapture = React38.useCallback(
6212
6304
  (dataUrl) => {
6213
6305
  setChatAttachments((prev) => [...prev, dataUrl]);
6214
6306
  setDrawing(false);
@@ -6217,7 +6309,7 @@ function StudioOverlay({
6217
6309
  },
6218
6310
  [openSheet]
6219
6311
  );
6220
- const toggleSheet = React37.useCallback(async () => {
6312
+ const toggleSheet = React38.useCallback(async () => {
6221
6313
  if (!sheetOpen) {
6222
6314
  const shouldExitTest = Boolean(testingMrId) || isTesting;
6223
6315
  if (shouldExitTest) {
@@ -6229,7 +6321,7 @@ function StudioOverlay({
6229
6321
  closeSheet();
6230
6322
  }
6231
6323
  }, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
6232
- const handleTestMr = React37.useCallback(
6324
+ const handleTestMr = React38.useCallback(
6233
6325
  async (mr) => {
6234
6326
  if (!onTestMr) return;
6235
6327
  await onTestMr(mr);
@@ -6239,7 +6331,7 @@ function StudioOverlay({
6239
6331
  );
6240
6332
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
6241
6333
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
6242
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioBottomSheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
6334
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
6243
6335
  StudioSheetPager,
6244
6336
  {
6245
6337
  activePage,
@@ -6301,7 +6393,7 @@ function StudioOverlay({
6301
6393
  badgeCount: incomingMergeRequests.length,
6302
6394
  onPress: toggleSheet,
6303
6395
  isLoading: (app == null ? void 0 : app.status) === "editing",
6304
- children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native51.View, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
6396
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native52.View, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
6305
6397
  }
6306
6398
  ),
6307
6399
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
@@ -6347,16 +6439,16 @@ function ComergeStudio({
6347
6439
  onNavigateHome,
6348
6440
  style
6349
6441
  }) {
6350
- const [activeAppId, setActiveAppId] = React38.useState(appId);
6351
- const [runtimeAppId, setRuntimeAppId] = React38.useState(appId);
6352
- const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React38.useState(null);
6353
- const platform = React38.useMemo(() => import_react_native52.Platform.OS === "ios" ? "ios" : "android", []);
6354
- React38.useEffect(() => {
6442
+ const [activeAppId, setActiveAppId] = React39.useState(appId);
6443
+ const [runtimeAppId, setRuntimeAppId] = React39.useState(appId);
6444
+ const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React39.useState(null);
6445
+ const platform = React39.useMemo(() => import_react_native53.Platform.OS === "ios" ? "ios" : "android", []);
6446
+ React39.useEffect(() => {
6355
6447
  setActiveAppId(appId);
6356
6448
  setRuntimeAppId(appId);
6357
6449
  setPendingRuntimeTargetAppId(null);
6358
6450
  }, [appId]);
6359
- const captureTargetRef = React38.useRef(null);
6451
+ const captureTargetRef = React39.useRef(null);
6360
6452
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(StudioBootstrap, { apiKey, children: ({ userId }) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_bottom_sheet6.BottomSheetModalProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6361
6453
  ComergeStudioInner,
6362
6454
  {
@@ -6392,11 +6484,11 @@ function ComergeStudioInner({
6392
6484
  const { app, loading: appLoading } = useApp(activeAppId);
6393
6485
  const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
6394
6486
  const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
6395
- const sawEditingOnPendingTargetRef = React38.useRef(false);
6396
- React38.useEffect(() => {
6487
+ const sawEditingOnPendingTargetRef = React39.useRef(false);
6488
+ React39.useEffect(() => {
6397
6489
  sawEditingOnPendingTargetRef.current = false;
6398
6490
  }, [pendingRuntimeTargetAppId]);
6399
- React38.useEffect(() => {
6491
+ React39.useEffect(() => {
6400
6492
  if (!pendingRuntimeTargetAppId) return;
6401
6493
  if (activeAppId !== pendingRuntimeTargetAppId) return;
6402
6494
  if ((app == null ? void 0 : app.status) === "editing") {
@@ -6416,10 +6508,10 @@ function ComergeStudioInner({
6416
6508
  const threadId = (app == null ? void 0 : app.threadId) ?? "";
6417
6509
  const thread = useThreadMessages(threadId);
6418
6510
  const mergeRequests = useMergeRequests({ appId: activeAppId });
6419
- const hasOpenOutgoingMr = React38.useMemo(() => {
6511
+ const hasOpenOutgoingMr = React39.useMemo(() => {
6420
6512
  return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
6421
6513
  }, [mergeRequests.lists.outgoing]);
6422
- const incomingReviewMrs = React38.useMemo(() => {
6514
+ const incomingReviewMrs = React39.useMemo(() => {
6423
6515
  if (!userId) return mergeRequests.lists.incoming;
6424
6516
  return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
6425
6517
  }, [mergeRequests.lists.incoming, userId]);
@@ -6441,16 +6533,16 @@ function ComergeStudioInner({
6441
6533
  uploadAttachments: uploader.uploadBase64Images
6442
6534
  });
6443
6535
  const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
6444
- const [processingMrId, setProcessingMrId] = React38.useState(null);
6445
- const [testingMrId, setTestingMrId] = React38.useState(null);
6446
- const chatShowTypingIndicator = React38.useMemo(() => {
6536
+ const [processingMrId, setProcessingMrId] = React39.useState(null);
6537
+ const [testingMrId, setTestingMrId] = React39.useState(null);
6538
+ const chatShowTypingIndicator = React39.useMemo(() => {
6447
6539
  var _a;
6448
6540
  if (!thread.raw || thread.raw.length === 0) return false;
6449
6541
  const last = thread.raw[thread.raw.length - 1];
6450
6542
  const payloadType = typeof ((_a = last.payload) == null ? void 0 : _a.type) === "string" ? String(last.payload.type) : void 0;
6451
6543
  return payloadType !== "outcome";
6452
6544
  }, [thread.raw]);
6453
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native52.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native52.View, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
6545
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native53.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native53.View, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
6454
6546
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(RuntimeRenderer, { appKey, bundlePath: bundle.bundlePath, renderToken: bundle.renderToken }),
6455
6547
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
6456
6548
  StudioOverlay,