@comergehq/studio 0.1.9 → 0.1.11

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.mjs CHANGED
@@ -6,7 +6,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  });
7
7
 
8
8
  // src/studio/ComergeStudio.tsx
9
- import * as React39 from "react";
9
+ import * as React42 from "react";
10
10
  import { Platform as RNPlatform, View as View45 } from "react-native";
11
11
  import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
12
12
 
@@ -952,6 +952,39 @@ var BundlesRepositoryImpl = class extends BaseRepository {
952
952
  var bundlesRepository = new BundlesRepositoryImpl(bundlesRemoteDataSource);
953
953
 
954
954
  // src/studio/hooks/useBundleManager.ts
955
+ function sleep(ms) {
956
+ return new Promise((r) => setTimeout(r, ms));
957
+ }
958
+ function isRetryableNetworkError(e) {
959
+ var _a;
960
+ const err = e;
961
+ const code = typeof (err == null ? void 0 : err.code) === "string" ? err.code : "";
962
+ const message = typeof (err == null ? void 0 : err.message) === "string" ? err.message : "";
963
+ if (code === "ERR_NETWORK" || code === "ECONNABORTED") return true;
964
+ if (message.toLowerCase().includes("network error")) return true;
965
+ if (message.toLowerCase().includes("timeout")) return true;
966
+ const status = typeof ((_a = err == null ? void 0 : err.response) == null ? void 0 : _a.status) === "number" ? err.response.status : void 0;
967
+ if (status && (status === 429 || status >= 500)) return true;
968
+ return false;
969
+ }
970
+ async function withRetry(fn, opts) {
971
+ let lastErr = null;
972
+ for (let attempt = 1; attempt <= opts.attempts; attempt += 1) {
973
+ try {
974
+ return await fn();
975
+ } catch (e) {
976
+ lastErr = e;
977
+ const retryable = isRetryableNetworkError(e);
978
+ if (!retryable || attempt >= opts.attempts) {
979
+ throw e;
980
+ }
981
+ const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
982
+ const jitter = Math.floor(Math.random() * 250);
983
+ await sleep(exp + jitter);
984
+ }
985
+ }
986
+ throw lastErr;
987
+ }
955
988
  function safeName(s) {
956
989
  return s.replace(/[^a-zA-Z0-9._-]/g, "_");
957
990
  }
@@ -1009,8 +1042,16 @@ async function getExistingNonEmptyFileUri(fileUri) {
1009
1042
  async function downloadIfMissing(url, fileUri) {
1010
1043
  const existing = await getExistingNonEmptyFileUri(fileUri);
1011
1044
  if (existing) return existing;
1012
- const res = await FileSystem.downloadAsync(url, fileUri);
1013
- return res.uri;
1045
+ return await withRetry(
1046
+ async () => {
1047
+ await deleteFileIfExists(fileUri);
1048
+ const res = await FileSystem.downloadAsync(url, fileUri);
1049
+ const ok = await getExistingNonEmptyFileUri(res.uri);
1050
+ if (!ok) throw new Error("Downloaded bundle is empty.");
1051
+ return res.uri;
1052
+ },
1053
+ { attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
1054
+ );
1014
1055
  }
1015
1056
  async function deleteFileIfExists(fileUri) {
1016
1057
  try {
@@ -1024,11 +1065,15 @@ async function deleteFileIfExists(fileUri) {
1024
1065
  async function safeReplaceFileFromUrl(url, targetUri, tmpKey) {
1025
1066
  const tmpUri = toBundleFileUri(`tmp:${tmpKey}:${Date.now()}`);
1026
1067
  try {
1027
- await FileSystem.downloadAsync(url, tmpUri);
1028
- const tmpOk = await getExistingNonEmptyFileUri(tmpUri);
1029
- if (!tmpOk) {
1030
- throw new Error("Downloaded bundle is empty.");
1031
- }
1068
+ await withRetry(
1069
+ async () => {
1070
+ await deleteFileIfExists(tmpUri);
1071
+ await FileSystem.downloadAsync(url, tmpUri);
1072
+ const tmpOk = await getExistingNonEmptyFileUri(tmpUri);
1073
+ if (!tmpOk) throw new Error("Downloaded bundle is empty.");
1074
+ },
1075
+ { attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
1076
+ );
1032
1077
  await deleteFileIfExists(targetUri);
1033
1078
  await FileSystem.moveAsync({ from: tmpUri, to: targetUri });
1034
1079
  const finalOk = await getExistingNonEmptyFileUri(targetUri);
@@ -1041,28 +1086,44 @@ async function safeReplaceFileFromUrl(url, targetUri, tmpKey) {
1041
1086
  async function pollBundle(appId, bundleId, opts) {
1042
1087
  const start = Date.now();
1043
1088
  while (true) {
1044
- const bundle = await bundlesRepository.getById(appId, bundleId);
1045
- if (bundle.status === "succeeded" || bundle.status === "failed") return bundle;
1089
+ try {
1090
+ const bundle = await bundlesRepository.getById(appId, bundleId);
1091
+ if (bundle.status === "succeeded" || bundle.status === "failed") return bundle;
1092
+ } catch (e) {
1093
+ if (!isRetryableNetworkError(e)) {
1094
+ throw e;
1095
+ }
1096
+ }
1046
1097
  if (Date.now() - start > opts.timeoutMs) {
1047
1098
  throw new Error("Bundle build timed out.");
1048
1099
  }
1049
- await new Promise((r) => setTimeout(r, opts.intervalMs));
1100
+ await sleep(opts.intervalMs);
1050
1101
  }
1051
1102
  }
1052
1103
  async function resolveBundlePath(src, platform, mode) {
1053
1104
  const { appId, commitId } = src;
1054
1105
  const dir = bundlesCacheDir();
1055
1106
  await ensureDir(dir);
1056
- const initiate = await bundlesRepository.initiate(appId, {
1057
- platform,
1058
- commitId: commitId ?? void 0,
1059
- idempotencyKey: `${appId}:${commitId ?? "head"}:${platform}`
1060
- });
1107
+ const initiate = await withRetry(
1108
+ async () => {
1109
+ return await bundlesRepository.initiate(appId, {
1110
+ platform,
1111
+ commitId: commitId ?? void 0,
1112
+ idempotencyKey: `${appId}:${commitId ?? "head"}:${platform}`
1113
+ });
1114
+ },
1115
+ { attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
1116
+ );
1061
1117
  const finalBundle = initiate.status === "succeeded" || initiate.status === "failed" ? initiate : await pollBundle(appId, initiate.id, { timeoutMs: 3 * 60 * 1e3, intervalMs: 1200 });
1062
1118
  if (finalBundle.status === "failed") {
1063
1119
  throw new Error("Bundle build failed.");
1064
1120
  }
1065
- const signed = await bundlesRepository.getSignedDownloadUrl(appId, finalBundle.id, { redirect: false });
1121
+ const signed = await withRetry(
1122
+ async () => {
1123
+ return await bundlesRepository.getSignedDownloadUrl(appId, finalBundle.id, { redirect: false });
1124
+ },
1125
+ { attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
1126
+ );
1066
1127
  const bundlePath = mode === "base" ? await safeReplaceFileFromUrl(
1067
1128
  signed.url,
1068
1129
  toBundleFileUri(baseBundleKey(appId, platform)),
@@ -1078,6 +1139,7 @@ function useBundleManager({
1078
1139
  const [bundlePath, setBundlePath] = React5.useState(null);
1079
1140
  const [renderToken, setRenderToken] = React5.useState(0);
1080
1141
  const [loading, setLoading] = React5.useState(false);
1142
+ const [loadingMode, setLoadingMode] = React5.useState(null);
1081
1143
  const [statusLabel, setStatusLabel] = React5.useState(null);
1082
1144
  const [error, setError] = React5.useState(null);
1083
1145
  const [isTesting, setIsTesting] = React5.useState(false);
@@ -1093,6 +1155,7 @@ function useBundleManager({
1093
1155
  baseOpIdRef.current += 1;
1094
1156
  if (activeLoadModeRef.current === "base") {
1095
1157
  setLoading(false);
1158
+ setLoadingMode(null);
1096
1159
  setStatusLabel(null);
1097
1160
  activeLoadModeRef.current = null;
1098
1161
  }
@@ -1157,6 +1220,7 @@ function useBundleManager({
1157
1220
  const opId = mode === "base" ? ++baseOpIdRef.current : ++testOpIdRef.current;
1158
1221
  activeLoadModeRef.current = mode;
1159
1222
  setLoading(true);
1223
+ setLoadingMode(mode);
1160
1224
  setError(null);
1161
1225
  setStatusLabel(mode === "test" ? "Loading test bundle\u2026" : "Loading latest build\u2026");
1162
1226
  if (mode === "base") {
@@ -1199,6 +1263,7 @@ function useBundleManager({
1199
1263
  if (mode === "base" && opId !== baseOpIdRef.current) return;
1200
1264
  if (mode === "test" && opId !== testOpIdRef.current) return;
1201
1265
  setLoading(false);
1266
+ setLoadingMode(null);
1202
1267
  if (activeLoadModeRef.current === mode) activeLoadModeRef.current = null;
1203
1268
  }
1204
1269
  }, [activateCachedBase, platform]);
@@ -1220,7 +1285,7 @@ function useBundleManager({
1220
1285
  if (!canRequestLatest) return;
1221
1286
  void loadBase();
1222
1287
  }, [base.appId, base.commitId, platform, canRequestLatest, loadBase]);
1223
- return { bundlePath, renderToken, loading, statusLabel, error, isTesting, loadBase, loadTest, restoreBase };
1288
+ return { bundlePath, renderToken, loading, loadingMode, statusLabel, error, isTesting, loadBase, loadTest, restoreBase };
1224
1289
  }
1225
1290
 
1226
1291
  // src/studio/hooks/useMergeRequests.ts
@@ -1479,6 +1544,8 @@ function useMergeRequests(params) {
1479
1544
 
1480
1545
  // src/studio/hooks/useAttachmentUpload.ts
1481
1546
  import * as React7 from "react";
1547
+ import { Platform } from "react-native";
1548
+ import * as FileSystem2 from "expo-file-system/legacy";
1482
1549
 
1483
1550
  // src/data/attachment/remote.ts
1484
1551
  var AttachmentRemoteDataSourceImpl = class extends BaseRemote {
@@ -1518,6 +1585,40 @@ var attachmentRepository = new AttachmentRepositoryImpl(
1518
1585
  );
1519
1586
 
1520
1587
  // src/studio/hooks/useAttachmentUpload.ts
1588
+ async function dataUrlToBlobAndroid(dataUrl) {
1589
+ const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
1590
+ const comma = normalized.indexOf(",");
1591
+ if (comma === -1) {
1592
+ throw new Error("Invalid data URL (missing comma separator)");
1593
+ }
1594
+ const header = normalized.slice(0, comma);
1595
+ const base64 = normalized.slice(comma + 1);
1596
+ const mimeMatch = header.match(/data:(.*?);base64/i);
1597
+ const mimeType = (mimeMatch == null ? void 0 : mimeMatch[1]) ?? "application/octet-stream";
1598
+ const cacheDir = FileSystem2.cacheDirectory;
1599
+ if (!cacheDir) {
1600
+ throw new Error("expo-file-system cacheDirectory is unavailable");
1601
+ }
1602
+ const fileUri = `${cacheDir}attachment-${Date.now()}-${Math.random().toString(16).slice(2)}.bin`;
1603
+ await FileSystem2.writeAsStringAsync(fileUri, base64, {
1604
+ encoding: FileSystem2.EncodingType.Base64
1605
+ });
1606
+ try {
1607
+ const resp = await fetch(fileUri);
1608
+ const blob = await resp.blob();
1609
+ return blob.type ? blob : new Blob([blob], { type: mimeType });
1610
+ } finally {
1611
+ void FileSystem2.deleteAsync(fileUri, { idempotent: true }).catch(() => {
1612
+ });
1613
+ }
1614
+ }
1615
+ function getMimeTypeFromDataUrl(dataUrl) {
1616
+ const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
1617
+ const comma = normalized.indexOf(",");
1618
+ const header = comma === -1 ? normalized : normalized.slice(0, comma);
1619
+ const mimeMatch = header.match(/data:(.*?);base64/i);
1620
+ return (mimeMatch == null ? void 0 : mimeMatch[1]) ?? "image/png";
1621
+ }
1521
1622
  function useAttachmentUpload() {
1522
1623
  const [uploading, setUploading] = React7.useState(false);
1523
1624
  const [error, setError] = React7.useState(null);
@@ -1530,15 +1631,15 @@ function useAttachmentUpload() {
1530
1631
  const blobs = await Promise.all(
1531
1632
  dataUrls.map(async (dataUrl, idx) => {
1532
1633
  const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
1533
- const resp = await fetch(normalized);
1534
- const blob = await resp.blob();
1535
- return { blob, idx };
1634
+ const blob = Platform.OS === "android" ? await dataUrlToBlobAndroid(normalized) : await (await fetch(normalized)).blob();
1635
+ const mimeType = getMimeTypeFromDataUrl(normalized);
1636
+ return { blob, idx, mimeType };
1536
1637
  })
1537
1638
  );
1538
- const files = blobs.map(({ blob }, idx) => ({
1639
+ const files = blobs.map(({ blob, mimeType }, idx) => ({
1539
1640
  name: `attachment-${Date.now()}-${idx}.png`,
1540
1641
  size: blob.size,
1541
- mimeType: blob.type || "image/png"
1642
+ mimeType
1542
1643
  }));
1543
1644
  const presign = await attachmentRepository.presign({ threadId, appId, files });
1544
1645
  await Promise.all(presign.uploads.map((u, index) => attachmentRepository.upload(u, blobs[index].blob)));
@@ -1665,8 +1766,8 @@ function hasNoOutcomeAfterLastHuman(messages) {
1665
1766
  import { View as View2 } from "react-native";
1666
1767
  import { ComergeRuntimeRenderer } from "@comergehq/runtime";
1667
1768
  import { jsx as jsx3 } from "react/jsx-runtime";
1668
- function RuntimeRenderer({ appKey, bundlePath, renderToken, style }) {
1669
- if (!bundlePath) {
1769
+ function RuntimeRenderer({ appKey, bundlePath, forcePreparing, renderToken, style }) {
1770
+ if (!bundlePath || forcePreparing) {
1670
1771
  return /* @__PURE__ */ jsx3(View2, { style: [{ flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, style], children: /* @__PURE__ */ jsx3(Text, { variant: "bodyMuted", children: "Preparing app\u2026" }) });
1671
1772
  }
1672
1773
  return /* @__PURE__ */ jsx3(View2, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsx3(
@@ -1681,25 +1782,76 @@ function RuntimeRenderer({ appKey, bundlePath, renderToken, style }) {
1681
1782
  }
1682
1783
 
1683
1784
  // src/studio/ui/StudioOverlay.tsx
1684
- import * as React38 from "react";
1685
- import { Keyboard as Keyboard5, Platform as Platform8, View as View44, useWindowDimensions as useWindowDimensions4 } from "react-native";
1785
+ import * as React41 from "react";
1786
+ import { Keyboard as Keyboard5, Platform as Platform10, View as View44, useWindowDimensions as useWindowDimensions4 } from "react-native";
1686
1787
 
1687
1788
  // src/components/studio-sheet/StudioBottomSheet.tsx
1688
- import * as React9 from "react";
1689
- import { AppState as AppState2, Keyboard, View as View4 } from "react-native";
1789
+ import * as React11 from "react";
1790
+ import { AppState as AppState3, Keyboard, View as View4 } from "react-native";
1690
1791
  import BottomSheet from "@gorhom/bottom-sheet";
1691
1792
  import { useSafeAreaInsets } from "react-native-safe-area-context";
1692
1793
 
1693
1794
  // src/components/studio-sheet/StudioSheetBackground.tsx
1694
- import { Platform, View as View3 } from "react-native";
1695
- import { LiquidGlassView, isLiquidGlassSupported } from "@callstack/liquid-glass";
1696
- import { Fragment as Fragment2, jsx as jsx4, jsxs } from "react/jsx-runtime";
1795
+ import { Platform as Platform3, View as View3 } from "react-native";
1796
+ import { isLiquidGlassSupported } from "@callstack/liquid-glass";
1797
+
1798
+ // src/components/utils/ResettableLiquidGlassView.tsx
1799
+ import * as React10 from "react";
1800
+ import { LiquidGlassView } from "@callstack/liquid-glass";
1801
+
1802
+ // src/components/utils/liquidGlassReset.tsx
1803
+ import * as React9 from "react";
1804
+ import { AppState as AppState2, Platform as Platform2 } from "react-native";
1805
+ import { jsx as jsx4 } from "react/jsx-runtime";
1806
+ var LiquidGlassResetContext = React9.createContext(0);
1807
+ function LiquidGlassResetProvider({
1808
+ children,
1809
+ resetTriggers = []
1810
+ }) {
1811
+ const [token, setToken] = React9.useState(0);
1812
+ React9.useEffect(() => {
1813
+ if (Platform2.OS !== "ios") return;
1814
+ const onChange = (state) => {
1815
+ if (state === "active") setToken((t) => t + 1);
1816
+ };
1817
+ const sub = AppState2.addEventListener("change", onChange);
1818
+ return () => sub.remove();
1819
+ }, []);
1820
+ React9.useEffect(() => {
1821
+ setToken((t) => t + 1);
1822
+ }, resetTriggers);
1823
+ return /* @__PURE__ */ jsx4(LiquidGlassResetContext.Provider, { value: token, children });
1824
+ }
1825
+ function useLiquidGlassResetToken() {
1826
+ return React9.useContext(LiquidGlassResetContext);
1827
+ }
1828
+
1829
+ // src/components/utils/ResettableLiquidGlassView.tsx
1830
+ import { jsx as jsx5 } from "react/jsx-runtime";
1831
+ function ResettableLiquidGlassView({ children, ...props }) {
1832
+ const token = useLiquidGlassResetToken();
1833
+ const [layoutBootKey, setLayoutBootKey] = React10.useState(0);
1834
+ const sawNonZeroLayoutRef = React10.useRef(false);
1835
+ const onLayout = (e) => {
1836
+ var _a;
1837
+ (_a = props.onLayout) == null ? void 0 : _a.call(props, e);
1838
+ const { width, height } = e.nativeEvent.layout;
1839
+ if (width > 0 && height > 0 && !sawNonZeroLayoutRef.current) {
1840
+ sawNonZeroLayoutRef.current = true;
1841
+ setLayoutBootKey((k) => k + 1);
1842
+ }
1843
+ };
1844
+ return /* @__PURE__ */ jsx5(LiquidGlassView, { ...props, onLayout, children }, `liquid-glass-${token}-${layoutBootKey}`);
1845
+ }
1846
+
1847
+ // src/components/studio-sheet/StudioSheetBackground.tsx
1848
+ import { Fragment as Fragment2, jsx as jsx6, jsxs } from "react/jsx-runtime";
1697
1849
  function StudioSheetBackground({
1698
1850
  style,
1699
1851
  renderBackground
1700
1852
  }) {
1701
1853
  const theme = useTheme();
1702
- const radius = Platform.OS === "ios" ? 39 : 16;
1854
+ const radius = Platform3.OS === "ios" ? 39 : 16;
1703
1855
  const fallbackBgColor = theme.scheme === "dark" ? "rgba(11, 8, 15, 0.85)" : "rgba(255, 255, 255, 0.85)";
1704
1856
  const secondaryBgBaseColor = theme.scheme === "dark" ? "rgb(24, 24, 27)" : "rgb(173, 173, 173)";
1705
1857
  const containerStyle = {
@@ -1709,17 +1861,17 @@ function StudioSheetBackground({
1709
1861
  overflow: "hidden"
1710
1862
  };
1711
1863
  if (renderBackground) {
1712
- return /* @__PURE__ */ jsx4(Fragment2, { children: renderBackground({ style: containerStyle }) });
1864
+ return /* @__PURE__ */ jsx6(Fragment2, { children: renderBackground({ style: containerStyle }) });
1713
1865
  }
1714
1866
  return /* @__PURE__ */ jsxs(Fragment2, { children: [
1715
- /* @__PURE__ */ jsx4(
1716
- LiquidGlassView,
1867
+ /* @__PURE__ */ jsx6(
1868
+ ResettableLiquidGlassView,
1717
1869
  {
1718
1870
  style: [containerStyle, !isLiquidGlassSupported && { backgroundColor: fallbackBgColor }],
1719
1871
  effect: "regular"
1720
1872
  }
1721
1873
  ),
1722
- isLiquidGlassSupported && /* @__PURE__ */ jsx4(
1874
+ isLiquidGlassSupported && /* @__PURE__ */ jsx6(
1723
1875
  View3,
1724
1876
  {
1725
1877
  style: [
@@ -1741,11 +1893,11 @@ function StudioSheetBackground({
1741
1893
  }
1742
1894
 
1743
1895
  // src/components/studio-sheet/StudioBottomSheet.tsx
1744
- import { jsx as jsx5 } from "react/jsx-runtime";
1896
+ import { jsx as jsx7 } from "react/jsx-runtime";
1745
1897
  function StudioBottomSheet({
1746
1898
  open,
1747
1899
  onOpenChange,
1748
- snapPoints = ["80%", "100%"],
1900
+ snapPoints = ["100%"],
1749
1901
  sheetRef,
1750
1902
  background,
1751
1903
  children,
@@ -1753,12 +1905,12 @@ function StudioBottomSheet({
1753
1905
  }) {
1754
1906
  const theme = useTheme();
1755
1907
  const insets = useSafeAreaInsets();
1756
- const internalSheetRef = React9.useRef(null);
1908
+ const internalSheetRef = React11.useRef(null);
1757
1909
  const resolvedSheetRef = sheetRef ?? internalSheetRef;
1758
- const currentIndexRef = React9.useRef(open ? snapPoints.length - 1 : -1);
1759
- const lastAppStateRef = React9.useRef(AppState2.currentState);
1760
- React9.useEffect(() => {
1761
- const sub = AppState2.addEventListener("change", (state) => {
1910
+ const currentIndexRef = React11.useRef(open ? snapPoints.length - 1 : -1);
1911
+ const lastAppStateRef = React11.useRef(AppState3.currentState);
1912
+ React11.useEffect(() => {
1913
+ const sub = AppState3.addEventListener("change", (state) => {
1762
1914
  const prev = lastAppStateRef.current;
1763
1915
  lastAppStateRef.current = state;
1764
1916
  if (state === "background" || state === "inactive") {
@@ -1777,7 +1929,7 @@ function StudioBottomSheet({
1777
1929
  });
1778
1930
  return () => sub.remove();
1779
1931
  }, [open, resolvedSheetRef]);
1780
- React9.useEffect(() => {
1932
+ React11.useEffect(() => {
1781
1933
  const sheet = resolvedSheetRef.current;
1782
1934
  if (!sheet) return;
1783
1935
  if (open) {
@@ -1786,41 +1938,41 @@ function StudioBottomSheet({
1786
1938
  sheet.close();
1787
1939
  }
1788
1940
  }, [open, resolvedSheetRef, snapPoints.length]);
1789
- const handleChange = React9.useCallback(
1941
+ const handleChange = React11.useCallback(
1790
1942
  (index) => {
1791
1943
  currentIndexRef.current = index;
1792
1944
  onOpenChange == null ? void 0 : onOpenChange(index >= 0);
1793
1945
  },
1794
1946
  [onOpenChange]
1795
1947
  );
1796
- return /* @__PURE__ */ jsx5(
1948
+ return /* @__PURE__ */ jsx7(
1797
1949
  BottomSheet,
1798
1950
  {
1799
1951
  ref: resolvedSheetRef,
1800
1952
  index: open ? snapPoints.length - 1 : -1,
1801
1953
  snapPoints,
1954
+ enableDynamicSizing: false,
1802
1955
  enablePanDownToClose: true,
1803
- keyboardBehavior: "interactive",
1804
- keyboardBlurBehavior: "restore",
1956
+ enableContentPanningGesture: false,
1805
1957
  android_keyboardInputMode: "adjustResize",
1806
- backgroundComponent: (props) => /* @__PURE__ */ jsx5(StudioSheetBackground, { ...props, renderBackground: background == null ? void 0 : background.renderBackground }),
1958
+ backgroundComponent: (props) => /* @__PURE__ */ jsx7(StudioSheetBackground, { ...props, renderBackground: background == null ? void 0 : background.renderBackground }),
1807
1959
  topInset: insets.top,
1808
1960
  bottomInset: 0,
1809
1961
  handleIndicatorStyle: { backgroundColor: theme.colors.handleIndicator },
1810
1962
  onChange: handleChange,
1811
1963
  ...bottomSheetProps,
1812
- children: /* @__PURE__ */ jsx5(View4, { style: { flex: 1, overflow: "hidden" }, children })
1964
+ children: /* @__PURE__ */ jsx7(View4, { style: { flex: 1, overflow: "hidden" }, children })
1813
1965
  }
1814
1966
  );
1815
1967
  }
1816
1968
 
1817
1969
  // src/components/studio-sheet/StudioSheetPager.tsx
1818
- import * as React10 from "react";
1970
+ import * as React12 from "react";
1819
1971
  import { Animated } from "react-native";
1820
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
1972
+ import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
1821
1973
  function StudioSheetPager({ activePage, width, preview, chat, style }) {
1822
- const anim = React10.useRef(new Animated.Value(activePage === "chat" ? 1 : 0)).current;
1823
- React10.useEffect(() => {
1974
+ const anim = React12.useRef(new Animated.Value(activePage === "chat" ? 1 : 0)).current;
1975
+ React12.useEffect(() => {
1824
1976
  Animated.spring(anim, {
1825
1977
  toValue: activePage === "chat" ? 1 : 0,
1826
1978
  useNativeDriver: true,
@@ -1831,7 +1983,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1831
1983
  const previewTranslateX = anim.interpolate({ inputRange: [0, 1], outputRange: [0, -width] });
1832
1984
  const chatTranslateX = anim.interpolate({ inputRange: [0, 1], outputRange: [width, 0] });
1833
1985
  return /* @__PURE__ */ jsxs2(Animated.View, { style: [{ flex: 1 }, style], children: [
1834
- /* @__PURE__ */ jsx6(
1986
+ /* @__PURE__ */ jsx8(
1835
1987
  Animated.View,
1836
1988
  {
1837
1989
  style: [
@@ -1848,7 +2000,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1848
2000
  children: preview
1849
2001
  }
1850
2002
  ),
1851
- /* @__PURE__ */ jsx6(
2003
+ /* @__PURE__ */ jsx8(
1852
2004
  Animated.View,
1853
2005
  {
1854
2006
  style: [
@@ -1869,7 +2021,7 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
1869
2021
  }
1870
2022
 
1871
2023
  // src/components/floating-draggable-button/FloatingDraggableButton.tsx
1872
- import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef6 } from "react";
2024
+ import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo3, useRef as useRef7 } from "react";
1873
2025
  import {
1874
2026
  PanResponder,
1875
2027
  Pressable,
@@ -1890,7 +2042,7 @@ import Animated2, {
1890
2042
  withSpring,
1891
2043
  withTiming
1892
2044
  } from "react-native-reanimated";
1893
- import { LiquidGlassView as LiquidGlassView2, isLiquidGlassSupported as isLiquidGlassSupported2 } from "@callstack/liquid-glass";
2045
+ import { isLiquidGlassSupported as isLiquidGlassSupported2 } from "@callstack/liquid-glass";
1894
2046
 
1895
2047
  // src/components/floating-draggable-button/constants.ts
1896
2048
  var DEFAULT_SIZE = 48;
@@ -1901,11 +2053,10 @@ var DEFAULT_OFFSET = {
1901
2053
  };
1902
2054
  var ENTER_SCALE_FROM = 0.3;
1903
2055
  var ENTER_ROTATION_FROM_DEG = -180;
1904
- var HIDDEN_OPACITY = 0.3;
1905
2056
  var PULSE_DURATION_MS = 900;
1906
2057
 
1907
2058
  // src/components/floating-draggable-button/FloatingDraggableButton.tsx
1908
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
2059
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
1909
2060
  var HIDDEN_OFFSET_X = 20;
1910
2061
  var SPRING_POSITION = { damping: 12, stiffness: 100, mass: 0.8 };
1911
2062
  var SPRING_SCALE_IN = { damping: 10, stiffness: 200 };
@@ -1913,8 +2064,6 @@ var SPRING_SCALE_OUT = { damping: 12, stiffness: 150 };
1913
2064
  var SPRING_ROTATION_IN = { damping: 15, stiffness: 80 };
1914
2065
  var SPRING_ROTATION_GRAB = { damping: 20 };
1915
2066
  var SPRING_SCALE_GRAB = { damping: 15, stiffness: 200 };
1916
- var TIMING_OPACITY_IN = { duration: 300, easing: Easing.out(Easing.ease) };
1917
- var TIMING_OPACITY_OUT = { duration: 250, easing: Easing.in(Easing.ease) };
1918
2067
  function clamp(value, min, max) {
1919
2068
  "worklet";
1920
2069
  return Math.max(min, Math.min(max, value));
@@ -1948,8 +2097,8 @@ function FloatingDraggableButton({
1948
2097
  const theme = useTheme();
1949
2098
  const { width, height } = useWindowDimensions();
1950
2099
  const isDanger = variant === "danger";
1951
- const onPressRef = useRef6(onPress);
1952
- useEffect9(() => {
2100
+ const onPressRef = useRef7(onPress);
2101
+ useEffect10(() => {
1953
2102
  onPressRef.current = onPress;
1954
2103
  }, [onPress]);
1955
2104
  const fallbackBgColor = useMemo3(() => {
@@ -1961,30 +2110,20 @@ function FloatingDraggableButton({
1961
2110
  const translateY = useSharedValue(getHiddenTranslateY(height));
1962
2111
  const scale = useSharedValue(ENTER_SCALE_FROM);
1963
2112
  const rotation = useSharedValue(ENTER_ROTATION_FROM_DEG);
1964
- const opacity = useSharedValue(1);
1965
2113
  const borderPulse = useSharedValue(0);
1966
- const startPos = useRef6({ x: 0, y: 0 });
1967
- const isAnimatingOut = useRef6(false);
2114
+ const startPos = useRef7({ x: 0, y: 0 });
2115
+ const isAnimatingOut = useRef7(false);
1968
2116
  const animateToHidden = useCallback8(
1969
2117
  (options) => {
1970
- translateX.value = withSpring(getHiddenTranslateX(size), SPRING_POSITION);
2118
+ const finish = options == null ? void 0 : options.onFinish;
2119
+ translateX.value = withSpring(getHiddenTranslateX(size), SPRING_POSITION, (finished) => {
2120
+ if (finished && finish) runOnJS(finish)();
2121
+ });
1971
2122
  translateY.value = withSpring(getHiddenTranslateY(height), SPRING_POSITION);
1972
2123
  scale.value = withSpring(ENTER_SCALE_FROM, SPRING_SCALE_IN);
1973
2124
  rotation.value = withSpring(ENTER_ROTATION_FROM_DEG, SPRING_ROTATION_IN);
1974
- const finish = options == null ? void 0 : options.onFinish;
1975
- if (!finish) {
1976
- opacity.value = withTiming(HIDDEN_OPACITY, TIMING_OPACITY_OUT);
1977
- return;
1978
- }
1979
- opacity.value = withTiming(
1980
- HIDDEN_OPACITY,
1981
- TIMING_OPACITY_OUT,
1982
- (finished) => {
1983
- if (finished) runOnJS(finish)();
1984
- }
1985
- );
1986
2125
  },
1987
- [height, opacity, rotation, scale, size, translateX, translateY]
2126
+ [height, rotation, scale, size, translateX, translateY]
1988
2127
  );
1989
2128
  const animateOut = useCallback8(() => {
1990
2129
  if (isAnimatingOut.current) return;
@@ -2000,7 +2139,7 @@ function FloatingDraggableButton({
2000
2139
  }
2001
2140
  });
2002
2141
  }, [animateToHidden]);
2003
- useEffect9(() => {
2142
+ useEffect10(() => {
2004
2143
  if (isLoading) {
2005
2144
  borderPulse.value = withRepeat(
2006
2145
  withSequence(
@@ -2024,9 +2163,8 @@ function FloatingDraggableButton({
2024
2163
  withSpring(1, SPRING_SCALE_OUT)
2025
2164
  );
2026
2165
  rotation.value = withSpring(0, SPRING_ROTATION_IN);
2027
- opacity.value = withTiming(1, TIMING_OPACITY_IN);
2028
- }, [height, offset.bottom, offset.left, opacity, rotation, scale, size, translateX, translateY]);
2029
- useEffect9(() => {
2166
+ }, [height, offset.bottom, offset.left, rotation, scale, size, translateX, translateY]);
2167
+ useEffect10(() => {
2030
2168
  const timer = setTimeout(() => {
2031
2169
  if (visible) {
2032
2170
  animateIn();
@@ -2034,7 +2172,7 @@ function FloatingDraggableButton({
2034
2172
  }, 100);
2035
2173
  return () => clearTimeout(timer);
2036
2174
  }, []);
2037
- useEffect9(() => {
2175
+ useEffect10(() => {
2038
2176
  if (visible && isAnimatingOut.current) {
2039
2177
  animateIn();
2040
2178
  } else if (!visible && !isAnimatingOut.current) {
@@ -2042,13 +2180,13 @@ function FloatingDraggableButton({
2042
2180
  isAnimatingOut.current = true;
2043
2181
  }
2044
2182
  }, [visible, animateIn, animateToHidden]);
2045
- useEffect9(() => {
2183
+ useEffect10(() => {
2046
2184
  if (forceShowTrigger > 0 && visible) {
2047
2185
  isAnimatingOut.current = false;
2048
2186
  animateIn();
2049
2187
  }
2050
2188
  }, [forceShowTrigger, visible, animateIn]);
2051
- const panResponder = useRef6(
2189
+ const panResponder = useRef7(
2052
2190
  PanResponder.create({
2053
2191
  onStartShouldSetPanResponder: () => true,
2054
2192
  onMoveShouldSetPanResponder: () => true,
@@ -2081,8 +2219,7 @@ function FloatingDraggableButton({
2081
2219
  { translateY: translateY.value },
2082
2220
  { scale: scale.value },
2083
2221
  { rotate: `${rotation.value}deg` }
2084
- ],
2085
- opacity: opacity.value
2222
+ ]
2086
2223
  }));
2087
2224
  const borderAnimatedStyle = useAnimatedStyle(() => {
2088
2225
  const borderColor = interpolateColor(
@@ -2105,13 +2242,13 @@ function FloatingDraggableButton({
2105
2242
  accessibilityRole: "button",
2106
2243
  accessibilityLabel: ariaLabel,
2107
2244
  children: [
2108
- /* @__PURE__ */ jsx7(Animated2.View, { style: [{ width: size, height: size, borderRadius: size / 2 }, borderAnimatedStyle], children: /* @__PURE__ */ jsx7(
2109
- LiquidGlassView2,
2245
+ /* @__PURE__ */ jsx9(Animated2.View, { style: [{ width: size, height: size, borderRadius: size / 2 }, borderAnimatedStyle], children: /* @__PURE__ */ jsx9(
2246
+ ResettableLiquidGlassView,
2110
2247
  {
2111
2248
  style: [{ flex: 1, borderRadius: size / 2 }, !isLiquidGlassSupported2 && { backgroundColor: fallbackBgColor }],
2112
2249
  interactive: true,
2113
2250
  effect: "clear",
2114
- children: /* @__PURE__ */ jsx7(
2251
+ children: /* @__PURE__ */ jsx9(
2115
2252
  Pressable,
2116
2253
  {
2117
2254
  onPress: () => {
@@ -2119,12 +2256,12 @@ function FloatingDraggableButton({
2119
2256
  },
2120
2257
  style: styles.buttonInner,
2121
2258
  android_ripple: { color: "rgba(255, 255, 255, 0.3)", borderless: true },
2122
- children: children ?? /* @__PURE__ */ jsx7(View5, {})
2259
+ children: children ?? /* @__PURE__ */ jsx9(View5, {})
2123
2260
  }
2124
2261
  )
2125
2262
  }
2126
2263
  ) }),
2127
- badgeCount > 0 && /* @__PURE__ */ jsx7(View5, { style: [styles.badge, { backgroundColor: theme.colors.danger }], children: /* @__PURE__ */ jsx7(Text2, { style: [styles.badgeText, { color: theme.colors.onDanger }], children: badgeCount > 99 ? "99+" : badgeCount }) })
2264
+ badgeCount > 0 && /* @__PURE__ */ jsx9(View5, { style: [styles.badge, { backgroundColor: theme.colors.danger }], children: /* @__PURE__ */ jsx9(Text2, { style: [styles.badgeText, { color: theme.colors.onDanger }], children: badgeCount > 99 ? "99+" : badgeCount }) })
2128
2265
  ]
2129
2266
  }
2130
2267
  );
@@ -2165,7 +2302,7 @@ var styles = StyleSheet.create({
2165
2302
  });
2166
2303
 
2167
2304
  // src/components/overlays/EdgeGlowFrame.tsx
2168
- import * as React11 from "react";
2305
+ import * as React13 from "react";
2169
2306
  import { Animated as Animated3, View as View6 } from "react-native";
2170
2307
  import { LinearGradient } from "expo-linear-gradient";
2171
2308
 
@@ -2185,7 +2322,7 @@ function withAlpha(color, alpha) {
2185
2322
  }
2186
2323
 
2187
2324
  // src/components/overlays/EdgeGlowFrame.tsx
2188
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
2325
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
2189
2326
  function baseColor(role, theme) {
2190
2327
  switch (role) {
2191
2328
  case "danger":
@@ -2208,8 +2345,8 @@ function EdgeGlowFrame({
2208
2345
  }) {
2209
2346
  const theme = useTheme();
2210
2347
  const alpha = Math.max(0, Math.min(1, intensity));
2211
- const anim = React11.useRef(new Animated3.Value(visible ? 1 : 0)).current;
2212
- React11.useEffect(() => {
2348
+ const anim = React13.useRef(new Animated3.Value(visible ? 1 : 0)).current;
2349
+ React13.useEffect(() => {
2213
2350
  Animated3.timing(anim, {
2214
2351
  toValue: visible ? 1 : 0,
2215
2352
  duration: 300,
@@ -2220,7 +2357,7 @@ function EdgeGlowFrame({
2220
2357
  const strong = withAlpha(c, 0.6 * alpha);
2221
2358
  const soft = withAlpha(c, 0.22 * alpha);
2222
2359
  return /* @__PURE__ */ jsxs4(Animated3.View, { pointerEvents: "none", style: [{ position: "absolute", inset: 0, opacity: anim }, style], children: [
2223
- /* @__PURE__ */ jsx8(View6, { style: { position: "absolute", top: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ jsx8(
2360
+ /* @__PURE__ */ jsx10(View6, { style: { position: "absolute", top: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ jsx10(
2224
2361
  LinearGradient,
2225
2362
  {
2226
2363
  colors: [strong, soft, "transparent"],
@@ -2229,7 +2366,7 @@ function EdgeGlowFrame({
2229
2366
  style: { width: "100%", height: "100%" }
2230
2367
  }
2231
2368
  ) }),
2232
- /* @__PURE__ */ jsx8(View6, { style: { position: "absolute", bottom: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ jsx8(
2369
+ /* @__PURE__ */ jsx10(View6, { style: { position: "absolute", bottom: 0, left: 0, right: 0, height: thickness }, children: /* @__PURE__ */ jsx10(
2233
2370
  LinearGradient,
2234
2371
  {
2235
2372
  colors: ["transparent", soft, strong],
@@ -2238,7 +2375,7 @@ function EdgeGlowFrame({
2238
2375
  style: { width: "100%", height: "100%" }
2239
2376
  }
2240
2377
  ) }),
2241
- /* @__PURE__ */ jsx8(View6, { style: { position: "absolute", top: 0, bottom: 0, left: 0, width: thickness }, children: /* @__PURE__ */ jsx8(
2378
+ /* @__PURE__ */ jsx10(View6, { style: { position: "absolute", top: 0, bottom: 0, left: 0, width: thickness }, children: /* @__PURE__ */ jsx10(
2242
2379
  LinearGradient,
2243
2380
  {
2244
2381
  colors: [strong, soft, "transparent"],
@@ -2247,7 +2384,7 @@ function EdgeGlowFrame({
2247
2384
  style: { width: "100%", height: "100%" }
2248
2385
  }
2249
2386
  ) }),
2250
- /* @__PURE__ */ jsx8(View6, { style: { position: "absolute", top: 0, bottom: 0, right: 0, width: thickness }, children: /* @__PURE__ */ jsx8(
2387
+ /* @__PURE__ */ jsx10(View6, { style: { position: "absolute", top: 0, bottom: 0, right: 0, width: thickness }, children: /* @__PURE__ */ jsx10(
2251
2388
  LinearGradient,
2252
2389
  {
2253
2390
  colors: ["transparent", soft, strong],
@@ -2260,12 +2397,12 @@ function EdgeGlowFrame({
2260
2397
  }
2261
2398
 
2262
2399
  // src/components/draw/DrawModeOverlay.tsx
2263
- import * as React14 from "react";
2400
+ import * as React16 from "react";
2264
2401
  import { StyleSheet as StyleSheet3, View as View10 } from "react-native";
2265
2402
  import { captureRef } from "react-native-view-shot";
2266
2403
 
2267
2404
  // src/components/draw/DrawSurface.tsx
2268
- import * as React12 from "react";
2405
+ import * as React14 from "react";
2269
2406
  import { PanResponder as PanResponder2, StyleSheet as StyleSheet2, View as View7 } from "react-native";
2270
2407
  import Svg, { Path } from "react-native-svg";
2271
2408
 
@@ -2288,7 +2425,7 @@ function pointsToSmoothPath(points) {
2288
2425
  }
2289
2426
 
2290
2427
  // src/components/draw/DrawSurface.tsx
2291
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
2428
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
2292
2429
  function DrawSurface({
2293
2430
  color,
2294
2431
  strokeWidth,
@@ -2297,25 +2434,25 @@ function DrawSurface({
2297
2434
  style,
2298
2435
  minDistance = 1
2299
2436
  }) {
2300
- const [renderTick, setRenderTick] = React12.useState(0);
2301
- const currentPointsRef = React12.useRef([]);
2302
- const rafRef = React12.useRef(null);
2303
- const triggerRender = React12.useCallback(() => {
2437
+ const [renderTick, setRenderTick] = React14.useState(0);
2438
+ const currentPointsRef = React14.useRef([]);
2439
+ const rafRef = React14.useRef(null);
2440
+ const triggerRender = React14.useCallback(() => {
2304
2441
  if (rafRef.current !== null) return;
2305
2442
  rafRef.current = requestAnimationFrame(() => {
2306
2443
  rafRef.current = null;
2307
2444
  setRenderTick((n) => n + 1);
2308
2445
  });
2309
2446
  }, []);
2310
- React12.useEffect(() => () => {
2447
+ React14.useEffect(() => () => {
2311
2448
  if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
2312
2449
  }, []);
2313
- const onStart = React12.useCallback((e) => {
2450
+ const onStart = React14.useCallback((e) => {
2314
2451
  const { locationX, locationY } = e.nativeEvent;
2315
2452
  currentPointsRef.current = [{ x: locationX, y: locationY }];
2316
2453
  triggerRender();
2317
2454
  }, [triggerRender]);
2318
- const onMove = React12.useCallback((e, _g) => {
2455
+ const onMove = React14.useCallback((e, _g) => {
2319
2456
  const { locationX, locationY } = e.nativeEvent;
2320
2457
  const pts = currentPointsRef.current;
2321
2458
  if (pts.length > 0) {
@@ -2328,7 +2465,7 @@ function DrawSurface({
2328
2465
  currentPointsRef.current = [...pts, { x: locationX, y: locationY }];
2329
2466
  triggerRender();
2330
2467
  }, [minDistance, triggerRender]);
2331
- const onEnd = React12.useCallback(() => {
2468
+ const onEnd = React14.useCallback(() => {
2332
2469
  const points = currentPointsRef.current;
2333
2470
  if (points.length > 0) {
2334
2471
  onAddStroke({ points, color, width: strokeWidth });
@@ -2336,7 +2473,7 @@ function DrawSurface({
2336
2473
  currentPointsRef.current = [];
2337
2474
  triggerRender();
2338
2475
  }, [color, onAddStroke, strokeWidth, triggerRender]);
2339
- const panResponder = React12.useMemo(
2476
+ const panResponder = React14.useMemo(
2340
2477
  () => PanResponder2.create({
2341
2478
  onStartShouldSetPanResponder: () => true,
2342
2479
  onMoveShouldSetPanResponder: () => true,
@@ -2349,11 +2486,11 @@ function DrawSurface({
2349
2486
  );
2350
2487
  const currentPath = pointsToSmoothPath(currentPointsRef.current);
2351
2488
  void renderTick;
2352
- return /* @__PURE__ */ jsx9(View7, { style: [StyleSheet2.absoluteFill, styles2.container, style], ...panResponder.panHandlers, children: /* @__PURE__ */ jsxs5(Svg, { style: StyleSheet2.absoluteFill, width: "100%", height: "100%", children: [
2489
+ return /* @__PURE__ */ jsx11(View7, { style: [StyleSheet2.absoluteFill, styles2.container, style], ...panResponder.panHandlers, children: /* @__PURE__ */ jsxs5(Svg, { style: StyleSheet2.absoluteFill, width: "100%", height: "100%", children: [
2353
2490
  strokes.map((s, idx) => {
2354
2491
  const d = pointsToSmoothPath(s.points);
2355
2492
  if (!d) return null;
2356
- return /* @__PURE__ */ jsx9(
2493
+ return /* @__PURE__ */ jsx11(
2357
2494
  Path,
2358
2495
  {
2359
2496
  d,
@@ -2366,7 +2503,7 @@ function DrawSurface({
2366
2503
  idx
2367
2504
  );
2368
2505
  }),
2369
- currentPath ? /* @__PURE__ */ jsx9(
2506
+ currentPath ? /* @__PURE__ */ jsx11(
2370
2507
  Path,
2371
2508
  {
2372
2509
  d: currentPath,
@@ -2386,7 +2523,7 @@ var styles2 = StyleSheet2.create({
2386
2523
  });
2387
2524
 
2388
2525
  // src/components/draw/DrawToolbar.tsx
2389
- import * as React13 from "react";
2526
+ import * as React15 from "react";
2390
2527
  import {
2391
2528
  ActivityIndicator,
2392
2529
  Animated as Animated4,
@@ -2414,7 +2551,7 @@ async function impact(style) {
2414
2551
 
2415
2552
  // src/components/draw/DrawColorPicker.tsx
2416
2553
  import { Pressable as Pressable2, View as View8 } from "react-native";
2417
- import { jsx as jsx10 } from "react/jsx-runtime";
2554
+ import { jsx as jsx12 } from "react/jsx-runtime";
2418
2555
  function DrawColorPicker({
2419
2556
  colors,
2420
2557
  selected,
@@ -2448,9 +2585,9 @@ function DrawColorPicker({
2448
2585
  return { ...base, ...selectedStyle, ...whiteStyle };
2449
2586
  };
2450
2587
  if (!expanded) {
2451
- return /* @__PURE__ */ jsx10(Pressable2, { onPress: onToggle, style: [swatchStyle(selected, true), style] });
2588
+ return /* @__PURE__ */ jsx12(Pressable2, { onPress: onToggle, style: [swatchStyle(selected, true), style] });
2452
2589
  }
2453
- return /* @__PURE__ */ jsx10(View8, { style: [{ flexDirection: "row", alignItems: "center", gap: 8 }, style], children: colors.map((c, idx) => /* @__PURE__ */ jsx10(
2590
+ return /* @__PURE__ */ jsx12(View8, { style: [{ flexDirection: "row", alignItems: "center", gap: 8 }, style], children: colors.map((c, idx) => /* @__PURE__ */ jsx12(
2454
2591
  Pressable2,
2455
2592
  {
2456
2593
  onPress: () => {
@@ -2464,7 +2601,7 @@ function DrawColorPicker({
2464
2601
  }
2465
2602
 
2466
2603
  // src/components/draw/DrawToolbar.tsx
2467
- import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
2604
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
2468
2605
  function DrawToolbar({
2469
2606
  colors,
2470
2607
  selectedColor,
@@ -2483,11 +2620,11 @@ function DrawToolbar({
2483
2620
  }) {
2484
2621
  const insets = useSafeAreaInsets2();
2485
2622
  const { width: screenWidth, height: screenHeight } = useWindowDimensions2();
2486
- const [expanded, setExpanded] = React13.useState(false);
2487
- const pos = React13.useRef(new Animated4.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
2488
- const start = React13.useRef({ x: 0, y: 0 });
2489
- const currentPos = React13.useRef({ x: 0, y: 0 });
2490
- React13.useEffect(() => {
2623
+ const [expanded, setExpanded] = React15.useState(false);
2624
+ const pos = React15.useRef(new Animated4.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
2625
+ const start = React15.useRef({ x: 0, y: 0 });
2626
+ const currentPos = React15.useRef({ x: 0, y: 0 });
2627
+ React15.useEffect(() => {
2491
2628
  if (hidden) return;
2492
2629
  Animated4.spring(pos.y, {
2493
2630
  toValue: insets.top + 60,
@@ -2497,7 +2634,7 @@ function DrawToolbar({
2497
2634
  mass: 0.8
2498
2635
  }).start();
2499
2636
  }, [hidden, insets.top, pos.y]);
2500
- React13.useEffect(() => {
2637
+ React15.useEffect(() => {
2501
2638
  const id = pos.addListener((v) => {
2502
2639
  currentPos.current = { x: v.x ?? 0, y: v.y ?? 0 };
2503
2640
  });
@@ -2505,7 +2642,7 @@ function DrawToolbar({
2505
2642
  pos.removeListener(id);
2506
2643
  };
2507
2644
  }, [pos]);
2508
- const clamp2 = React13.useCallback(
2645
+ const clamp2 = React15.useCallback(
2509
2646
  (x, y) => {
2510
2647
  const minX = 10;
2511
2648
  const maxX = Math.max(10, screenWidth - 230);
@@ -2515,7 +2652,7 @@ function DrawToolbar({
2515
2652
  },
2516
2653
  [insets.top, screenHeight, screenWidth]
2517
2654
  );
2518
- const panResponder = React13.useMemo(
2655
+ const panResponder = React15.useMemo(
2519
2656
  () => PanResponder3.create({
2520
2657
  onStartShouldSetPanResponder: () => false,
2521
2658
  onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 5 || Math.abs(g.dy) > 5,
@@ -2543,8 +2680,8 @@ function DrawToolbar({
2543
2680
  children
2544
2681
  }) {
2545
2682
  const isDisabled = Boolean(disabled) || Boolean(capturingDisabled);
2546
- const [pressed, setPressed] = React13.useState(false);
2547
- return /* @__PURE__ */ jsx11(
2683
+ const [pressed, setPressed] = React15.useState(false);
2684
+ return /* @__PURE__ */ jsx13(
2548
2685
  View9,
2549
2686
  {
2550
2687
  style: {
@@ -2556,7 +2693,7 @@ function DrawToolbar({
2556
2693
  backgroundColor,
2557
2694
  opacity: isDisabled ? 0.5 : pressed ? 0.85 : 1
2558
2695
  },
2559
- children: /* @__PURE__ */ jsx11(
2696
+ children: /* @__PURE__ */ jsx13(
2560
2697
  Pressable3,
2561
2698
  {
2562
2699
  accessibilityRole: "button",
@@ -2573,7 +2710,7 @@ function DrawToolbar({
2573
2710
  }
2574
2711
  );
2575
2712
  }
2576
- return /* @__PURE__ */ jsx11(
2713
+ return /* @__PURE__ */ jsx13(
2577
2714
  Animated4.View,
2578
2715
  {
2579
2716
  style: [
@@ -2590,7 +2727,7 @@ function DrawToolbar({
2590
2727
  style
2591
2728
  ],
2592
2729
  ...panResponder.panHandlers,
2593
- children: /* @__PURE__ */ jsx11(
2730
+ children: /* @__PURE__ */ jsx13(
2594
2731
  View9,
2595
2732
  {
2596
2733
  style: {
@@ -2600,8 +2737,8 @@ function DrawToolbar({
2600
2737
  minWidth: 220
2601
2738
  },
2602
2739
  children: /* @__PURE__ */ jsxs6(View9, { style: { flexDirection: "row", alignItems: "center", gap: 8 }, children: [
2603
- renderDragHandle ? renderDragHandle() : /* @__PURE__ */ jsx11(GripVertical, { size: 20, color: "rgba(255, 255, 255, 0.6)" }),
2604
- /* @__PURE__ */ jsx11(
2740
+ renderDragHandle ? renderDragHandle() : /* @__PURE__ */ jsx13(GripVertical, { size: 20, color: "rgba(255, 255, 255, 0.6)" }),
2741
+ /* @__PURE__ */ jsx13(
2605
2742
  DrawColorPicker,
2606
2743
  {
2607
2744
  colors,
@@ -2617,8 +2754,8 @@ function DrawToolbar({
2617
2754
  }
2618
2755
  }
2619
2756
  ),
2620
- /* @__PURE__ */ jsx11(View9, { style: { width: 1, height: 20, backgroundColor: "rgba(255, 255, 255, 0.3)", marginHorizontal: 4 } }),
2621
- /* @__PURE__ */ jsx11(
2757
+ /* @__PURE__ */ jsx13(View9, { style: { width: 1, height: 20, backgroundColor: "rgba(255, 255, 255, 0.3)", marginHorizontal: 4 } }),
2758
+ /* @__PURE__ */ jsx13(
2622
2759
  CircleActionButton,
2623
2760
  {
2624
2761
  accessibilityLabel: "Undo",
@@ -2629,10 +2766,10 @@ function DrawToolbar({
2629
2766
  void impact("light");
2630
2767
  onUndo();
2631
2768
  },
2632
- children: renderUndoIcon ? renderUndoIcon() : /* @__PURE__ */ jsx11(Undo2, { size: 16, color: canUndo ? "#FFFFFF" : "rgba(255,255,255,0.4)" })
2769
+ children: renderUndoIcon ? renderUndoIcon() : /* @__PURE__ */ jsx13(Undo2, { size: 16, color: canUndo ? "#FFFFFF" : "rgba(255,255,255,0.4)" })
2633
2770
  }
2634
2771
  ),
2635
- /* @__PURE__ */ jsx11(
2772
+ /* @__PURE__ */ jsx13(
2636
2773
  CircleActionButton,
2637
2774
  {
2638
2775
  accessibilityLabel: "Cancel",
@@ -2642,10 +2779,10 @@ function DrawToolbar({
2642
2779
  void impact("medium");
2643
2780
  onCancel();
2644
2781
  },
2645
- children: renderCancelIcon ? renderCancelIcon() : /* @__PURE__ */ jsx11(X, { size: 16, color: "#FFFFFF" })
2782
+ children: renderCancelIcon ? renderCancelIcon() : /* @__PURE__ */ jsx13(X, { size: 16, color: "#FFFFFF" })
2646
2783
  }
2647
2784
  ),
2648
- /* @__PURE__ */ jsx11(
2785
+ /* @__PURE__ */ jsx13(
2649
2786
  CircleActionButton,
2650
2787
  {
2651
2788
  accessibilityLabel: "Done",
@@ -2655,7 +2792,7 @@ function DrawToolbar({
2655
2792
  void impact("medium");
2656
2793
  onDone();
2657
2794
  },
2658
- children: capturing ? /* @__PURE__ */ jsx11(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : renderDoneIcon ? renderDoneIcon() : /* @__PURE__ */ jsx11(Check, { size: 16, color: "#FFFFFF" })
2795
+ children: capturing ? /* @__PURE__ */ jsx13(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : renderDoneIcon ? renderDoneIcon() : /* @__PURE__ */ jsx13(Check, { size: 16, color: "#FFFFFF" })
2659
2796
  }
2660
2797
  )
2661
2798
  ] })
@@ -2666,7 +2803,7 @@ function DrawToolbar({
2666
2803
  }
2667
2804
 
2668
2805
  // src/components/draw/DrawModeOverlay.tsx
2669
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
2806
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
2670
2807
  function DrawModeOverlay({
2671
2808
  visible,
2672
2809
  captureTargetRef,
@@ -2681,7 +2818,7 @@ function DrawModeOverlay({
2681
2818
  renderDragHandle
2682
2819
  }) {
2683
2820
  const theme = useTheme();
2684
- const defaultPalette = React14.useMemo(
2821
+ const defaultPalette = React16.useMemo(
2685
2822
  () => [
2686
2823
  "#EF4444",
2687
2824
  // Red
@@ -2699,11 +2836,11 @@ function DrawModeOverlay({
2699
2836
  []
2700
2837
  );
2701
2838
  const colors = palette && palette.length > 0 ? palette : defaultPalette;
2702
- const [selectedColor, setSelectedColor] = React14.useState(colors[0] ?? "#EF4444");
2703
- const [strokes, setStrokes] = React14.useState([]);
2704
- const [capturing, setCapturing] = React14.useState(false);
2705
- const [hideUi, setHideUi] = React14.useState(false);
2706
- React14.useEffect(() => {
2839
+ const [selectedColor, setSelectedColor] = React16.useState(colors[0] ?? "#EF4444");
2840
+ const [strokes, setStrokes] = React16.useState([]);
2841
+ const [capturing, setCapturing] = React16.useState(false);
2842
+ const [hideUi, setHideUi] = React16.useState(false);
2843
+ React16.useEffect(() => {
2707
2844
  if (!visible) return;
2708
2845
  setStrokes([]);
2709
2846
  setSelectedColor(colors[0] ?? "#EF4444");
@@ -2711,14 +2848,14 @@ function DrawModeOverlay({
2711
2848
  setHideUi(false);
2712
2849
  }, [colors, visible]);
2713
2850
  const canUndo = strokes.length > 0;
2714
- const handleUndo = React14.useCallback(() => {
2851
+ const handleUndo = React16.useCallback(() => {
2715
2852
  setStrokes((prev) => prev.slice(0, -1));
2716
2853
  }, []);
2717
- const handleCancel = React14.useCallback(() => {
2854
+ const handleCancel = React16.useCallback(() => {
2718
2855
  setStrokes([]);
2719
2856
  onCancel();
2720
2857
  }, [onCancel]);
2721
- const handleDone = React14.useCallback(async () => {
2858
+ const handleDone = React16.useCallback(async () => {
2722
2859
  if (!captureTargetRef.current || capturing) return;
2723
2860
  try {
2724
2861
  setCapturing(true);
@@ -2741,8 +2878,8 @@ function DrawModeOverlay({
2741
2878
  }, [captureTargetRef, capturing, onCapture]);
2742
2879
  if (!visible) return null;
2743
2880
  return /* @__PURE__ */ jsxs7(View10, { style: [StyleSheet3.absoluteFill, styles3.root, style], pointerEvents: "box-none", children: [
2744
- /* @__PURE__ */ jsx12(EdgeGlowFrame, { visible: !hideUi, role: "danger", thickness: 50, intensity: 1 }),
2745
- /* @__PURE__ */ jsx12(
2881
+ /* @__PURE__ */ jsx14(EdgeGlowFrame, { visible: !hideUi, role: "danger", thickness: 50, intensity: 1 }),
2882
+ /* @__PURE__ */ jsx14(
2746
2883
  DrawSurface,
2747
2884
  {
2748
2885
  color: selectedColor,
@@ -2751,7 +2888,7 @@ function DrawModeOverlay({
2751
2888
  onAddStroke: (stroke) => setStrokes((prev) => [...prev, stroke])
2752
2889
  }
2753
2890
  ),
2754
- /* @__PURE__ */ jsx12(
2891
+ /* @__PURE__ */ jsx14(
2755
2892
  DrawToolbar,
2756
2893
  {
2757
2894
  hidden: hideUi,
@@ -2778,19 +2915,19 @@ var styles3 = StyleSheet3.create({
2778
2915
  });
2779
2916
 
2780
2917
  // src/components/comments/AppCommentsSheet.tsx
2781
- import * as React21 from "react";
2782
- import { ActivityIndicator as ActivityIndicator3, Keyboard as Keyboard3, Platform as Platform4, Pressable as Pressable5, View as View14 } from "react-native";
2918
+ import * as React23 from "react";
2919
+ import { ActivityIndicator as ActivityIndicator3, Keyboard as Keyboard3, Platform as Platform6, Pressable as Pressable5, View as View14 } from "react-native";
2783
2920
  import {
2784
2921
  BottomSheetBackdrop,
2785
2922
  BottomSheetModal,
2786
2923
  BottomSheetScrollView
2787
2924
  } from "@gorhom/bottom-sheet";
2788
2925
  import { useSafeAreaInsets as useSafeAreaInsets3 } from "react-native-safe-area-context";
2789
- import { LiquidGlassView as LiquidGlassView4, isLiquidGlassSupported as isLiquidGlassSupported4 } from "@callstack/liquid-glass";
2926
+ import { isLiquidGlassSupported as isLiquidGlassSupported4 } from "@callstack/liquid-glass";
2790
2927
  import { Play as Play2 } from "lucide-react-native";
2791
2928
 
2792
2929
  // src/components/chat/ChatComposer.tsx
2793
- import * as React16 from "react";
2930
+ import * as React18 from "react";
2794
2931
  import {
2795
2932
  ActivityIndicator as ActivityIndicator2,
2796
2933
  Animated as Animated5,
@@ -2800,15 +2937,15 @@ import {
2800
2937
  ScrollView,
2801
2938
  View as View11
2802
2939
  } from "react-native";
2803
- import { LiquidGlassView as LiquidGlassView3, isLiquidGlassSupported as isLiquidGlassSupported3 } from "@callstack/liquid-glass";
2940
+ import { isLiquidGlassSupported as isLiquidGlassSupported3 } from "@callstack/liquid-glass";
2804
2941
  import { Plus } from "lucide-react-native";
2805
2942
 
2806
2943
  // src/components/chat/MultilineTextInput.tsx
2807
- import * as React15 from "react";
2944
+ import * as React17 from "react";
2808
2945
  import { TextInput } from "react-native";
2809
2946
  import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
2810
- import { jsx as jsx13 } from "react/jsx-runtime";
2811
- var MultilineTextInput = React15.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
2947
+ import { jsx as jsx15 } from "react/jsx-runtime";
2948
+ var MultilineTextInput = React17.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
2812
2949
  const theme = useTheme();
2813
2950
  const baseStyle = {
2814
2951
  minHeight: 44,
@@ -2828,7 +2965,7 @@ var MultilineTextInput = React15.forwardRef(function MultilineTextInput2({ useBo
2828
2965
  style: [baseStyle, style],
2829
2966
  textAlignVertical: "top"
2830
2967
  };
2831
- return useBottomSheetTextInput ? /* @__PURE__ */ jsx13(BottomSheetTextInput, { ref, ...commonProps }) : /* @__PURE__ */ jsx13(TextInput, { ref, ...commonProps });
2968
+ return useBottomSheetTextInput ? /* @__PURE__ */ jsx15(BottomSheetTextInput, { ref, ...commonProps }) : /* @__PURE__ */ jsx15(TextInput, { ref, ...commonProps });
2832
2969
  });
2833
2970
 
2834
2971
  // src/components/icons/StudioIcons.tsx
@@ -2845,7 +2982,7 @@ import {
2845
2982
  X as X2,
2846
2983
  Check as Check2
2847
2984
  } from "lucide-react-native";
2848
- import { jsx as jsx14 } from "react/jsx-runtime";
2985
+ import { jsx as jsx16 } from "react/jsx-runtime";
2849
2986
  function useResolvedIconColor(token) {
2850
2987
  const theme = useTheme();
2851
2988
  switch (token) {
@@ -2869,7 +3006,7 @@ function useResolvedIconColor(token) {
2869
3006
  function makeIcon(Comp) {
2870
3007
  return function StudioIcon({ size = 20, strokeWidth = 2, colorToken = "floatingContent", ...rest }) {
2871
3008
  const color = useResolvedIconColor(colorToken);
2872
- return /* @__PURE__ */ jsx14(Comp, { size, strokeWidth, color, ...rest });
3009
+ return /* @__PURE__ */ jsx16(Comp, { size, strokeWidth, color, ...rest });
2873
3010
  };
2874
3011
  }
2875
3012
  var IconHome = makeIcon(Home);
@@ -2885,16 +3022,16 @@ var IconArrowDown = makeIcon(ArrowDown);
2885
3022
  var IconApprove = makeIcon(Check2);
2886
3023
 
2887
3024
  // src/components/chat/ChatComposer.tsx
2888
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
3025
+ import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
2889
3026
  var THUMBNAIL_HEIGHT = 90;
2890
3027
  function AspectRatioThumbnail({
2891
3028
  uri,
2892
3029
  onRemove,
2893
3030
  renderRemoveIcon
2894
3031
  }) {
2895
- const [aspectRatio, setAspectRatio] = React16.useState(1);
3032
+ const [aspectRatio, setAspectRatio] = React18.useState(1);
2896
3033
  return /* @__PURE__ */ jsxs8(View11, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
2897
- /* @__PURE__ */ jsx15(View11, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx15(
3034
+ /* @__PURE__ */ jsx17(View11, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx17(
2898
3035
  Image,
2899
3036
  {
2900
3037
  source: { uri },
@@ -2907,7 +3044,7 @@ function AspectRatioThumbnail({
2907
3044
  }
2908
3045
  }
2909
3046
  ) }),
2910
- onRemove ? /* @__PURE__ */ jsx15(
3047
+ onRemove ? /* @__PURE__ */ jsx17(
2911
3048
  Pressable4,
2912
3049
  {
2913
3050
  style: {
@@ -2924,7 +3061,7 @@ function AspectRatioThumbnail({
2924
3061
  },
2925
3062
  onPress: onRemove,
2926
3063
  hitSlop: 10,
2927
- children: renderRemoveIcon ? renderRemoveIcon() : /* @__PURE__ */ jsx15(IconClose, { size: 12, colorToken: "onPrimary" })
3064
+ children: renderRemoveIcon ? renderRemoveIcon() : /* @__PURE__ */ jsx17(IconClose, { size: 12, colorToken: "onPrimary" })
2928
3065
  }
2929
3066
  ) : null
2930
3067
  ] });
@@ -2949,19 +3086,19 @@ function ChatComposer({
2949
3086
  style
2950
3087
  }) {
2951
3088
  const theme = useTheme();
2952
- const [internal, setInternal] = React16.useState("");
3089
+ const [internal, setInternal] = React18.useState("");
2953
3090
  const text = value ?? internal;
2954
3091
  const setText = onChangeValue ?? setInternal;
2955
3092
  const hasAttachments = attachments.length > 0;
2956
3093
  const hasText = text.trim().length > 0;
2957
3094
  const composerMinHeight = hasAttachments ? THUMBNAIL_HEIGHT + 44 + 24 : 44;
2958
3095
  const isButtonDisabled = sending || disabled || sendDisabled;
2959
- const maxInputHeight = React16.useMemo(() => Dimensions.get("window").height * 0.5, []);
2960
- const shakeAnim = React16.useRef(new Animated5.Value(0)).current;
2961
- const [sendPressed, setSendPressed] = React16.useState(false);
2962
- const inputRef = React16.useRef(null);
2963
- const prevAutoFocusRef = React16.useRef(false);
2964
- React16.useEffect(() => {
3096
+ const maxInputHeight = React18.useMemo(() => Dimensions.get("window").height * 0.5, []);
3097
+ const shakeAnim = React18.useRef(new Animated5.Value(0)).current;
3098
+ const [sendPressed, setSendPressed] = React18.useState(false);
3099
+ const inputRef = React18.useRef(null);
3100
+ const prevAutoFocusRef = React18.useRef(false);
3101
+ React18.useEffect(() => {
2965
3102
  const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
2966
3103
  prevAutoFocusRef.current = autoFocus;
2967
3104
  if (!shouldFocus) return;
@@ -2971,7 +3108,7 @@ function ChatComposer({
2971
3108
  }, 75);
2972
3109
  return () => clearTimeout(t);
2973
3110
  }, [autoFocus, disabled, sending]);
2974
- const triggerShake = React16.useCallback(() => {
3111
+ const triggerShake = React18.useCallback(() => {
2975
3112
  shakeAnim.setValue(0);
2976
3113
  Animated5.sequence([
2977
3114
  Animated5.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
@@ -2981,7 +3118,7 @@ function ChatComposer({
2981
3118
  Animated5.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
2982
3119
  ]).start();
2983
3120
  }, [shakeAnim]);
2984
- const handleSend = React16.useCallback(async () => {
3121
+ const handleSend = React18.useCallback(async () => {
2985
3122
  if (isButtonDisabled) return;
2986
3123
  if (!hasText) {
2987
3124
  triggerShake();
@@ -2993,14 +3130,15 @@ function ChatComposer({
2993
3130
  }, [attachments, hasText, isButtonDisabled, onSend, setText, text, triggerShake]);
2994
3131
  const textareaBgColor = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
2995
3132
  const placeholderTextColor = theme.scheme === "dark" ? "#A1A1AA" : "#71717A";
2996
- return /* @__PURE__ */ jsx15(
3133
+ const sendBg = withAlpha(theme.colors.primary, isButtonDisabled ? 0.6 : sendPressed ? 0.9 : 1);
3134
+ return /* @__PURE__ */ jsx17(
2997
3135
  View11,
2998
3136
  {
2999
3137
  style: [{ paddingHorizontal: 16, paddingBottom: 12, paddingTop: 8 }, style],
3000
3138
  onLayout: (e) => onLayout == null ? void 0 : onLayout({ height: e.nativeEvent.layout.height }),
3001
3139
  children: /* @__PURE__ */ jsxs8(View11, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8 }, children: [
3002
- /* @__PURE__ */ jsx15(Animated5.View, { style: { flex: 1, transform: [{ translateX: shakeAnim }] }, children: /* @__PURE__ */ jsxs8(
3003
- LiquidGlassView3,
3140
+ /* @__PURE__ */ jsx17(Animated5.View, { style: { flex: 1, transform: [{ translateX: shakeAnim }] }, children: /* @__PURE__ */ jsxs8(
3141
+ ResettableLiquidGlassView,
3004
3142
  {
3005
3143
  style: [
3006
3144
  // LiquidGlassView doesn't reliably auto-size to children; ensure enough height for the
@@ -3019,7 +3157,7 @@ function ChatComposer({
3019
3157
  keyboardShouldPersistTaps: "handled",
3020
3158
  contentContainerStyle: { gap: 8, paddingHorizontal: 12, paddingTop: 12 },
3021
3159
  children: [
3022
- attachments.map((uri, index) => /* @__PURE__ */ jsx15(
3160
+ attachments.map((uri, index) => /* @__PURE__ */ jsx17(
3023
3161
  AspectRatioThumbnail,
3024
3162
  {
3025
3163
  uri,
@@ -3028,7 +3166,7 @@ function ChatComposer({
3028
3166
  },
3029
3167
  `attachment-${index}`
3030
3168
  )),
3031
- onAddAttachment ? renderAddAttachment ? renderAddAttachment() : /* @__PURE__ */ jsx15(
3169
+ onAddAttachment ? renderAddAttachment ? renderAddAttachment() : /* @__PURE__ */ jsx17(
3032
3170
  Pressable4,
3033
3171
  {
3034
3172
  style: {
@@ -3043,13 +3181,13 @@ function ChatComposer({
3043
3181
  backgroundColor: "rgba(255, 255, 255, 0.05)"
3044
3182
  },
3045
3183
  onPress: onAddAttachment,
3046
- children: /* @__PURE__ */ jsx15(Plus, { size: 24, color: "rgba(255, 255, 255, 0.5)" })
3184
+ children: /* @__PURE__ */ jsx17(Plus, { size: 24, color: "rgba(255, 255, 255, 0.5)" })
3047
3185
  }
3048
3186
  ) : null
3049
3187
  ]
3050
3188
  }
3051
3189
  ) : null,
3052
- /* @__PURE__ */ jsx15(
3190
+ /* @__PURE__ */ jsx17(
3053
3191
  MultilineTextInput,
3054
3192
  {
3055
3193
  ref: inputRef,
@@ -3074,13 +3212,13 @@ function ChatComposer({
3074
3212
  ]
3075
3213
  }
3076
3214
  ) }),
3077
- /* @__PURE__ */ jsx15(
3078
- LiquidGlassView3,
3215
+ /* @__PURE__ */ jsx17(
3216
+ ResettableLiquidGlassView,
3079
3217
  {
3080
3218
  style: [{ borderRadius: 100 }, !isLiquidGlassSupported3 && { backgroundColor: textareaBgColor }],
3081
3219
  interactive: true,
3082
3220
  effect: "clear",
3083
- children: /* @__PURE__ */ jsx15(
3221
+ children: /* @__PURE__ */ jsx17(
3084
3222
  View11,
3085
3223
  {
3086
3224
  style: {
@@ -3088,10 +3226,9 @@ function ChatComposer({
3088
3226
  height: 44,
3089
3227
  borderRadius: 22,
3090
3228
  overflow: "hidden",
3091
- backgroundColor: theme.colors.primary,
3092
- opacity: isButtonDisabled ? 0.6 : sendPressed ? 0.9 : 1
3229
+ backgroundColor: sendBg
3093
3230
  },
3094
- children: /* @__PURE__ */ jsx15(
3231
+ children: /* @__PURE__ */ jsx17(
3095
3232
  Pressable4,
3096
3233
  {
3097
3234
  accessibilityRole: "button",
@@ -3101,7 +3238,7 @@ function ChatComposer({
3101
3238
  onPressIn: () => setSendPressed(true),
3102
3239
  onPressOut: () => setSendPressed(false),
3103
3240
  style: { flex: 1, alignItems: "center", justifyContent: "center" },
3104
- children: sending ? /* @__PURE__ */ jsx15(ActivityIndicator2, {}) : renderSendIcon ? renderSendIcon() : /* @__PURE__ */ jsx15(IconChevronRight, { size: 20, colorToken: "onPrimary" })
3241
+ children: sending ? /* @__PURE__ */ jsx17(ActivityIndicator2, {}) : renderSendIcon ? renderSendIcon() : /* @__PURE__ */ jsx17(IconChevronRight, { size: 20, colorToken: "onPrimary" })
3105
3242
  }
3106
3243
  )
3107
3244
  }
@@ -3114,12 +3251,12 @@ function ChatComposer({
3114
3251
  }
3115
3252
 
3116
3253
  // src/components/comments/CommentRow.tsx
3117
- import * as React17 from "react";
3254
+ import * as React19 from "react";
3118
3255
  import { View as View13 } from "react-native";
3119
3256
 
3120
3257
  // src/components/primitives/Avatar.tsx
3121
3258
  import { Image as Image2, View as View12 } from "react-native";
3122
- import { jsx as jsx16 } from "react/jsx-runtime";
3259
+ import { jsx as jsx18 } from "react/jsx-runtime";
3123
3260
  function initialsFrom(name) {
3124
3261
  var _a, _b;
3125
3262
  const trimmed = (name ?? "").trim();
@@ -3137,7 +3274,7 @@ function Avatar({
3137
3274
  const theme = useTheme();
3138
3275
  const radius = size / 2;
3139
3276
  const fallbackBg = fallbackBackgroundColor ?? theme.colors.neutral;
3140
- return /* @__PURE__ */ jsx16(
3277
+ return /* @__PURE__ */ jsx18(
3141
3278
  View12,
3142
3279
  {
3143
3280
  style: [
@@ -3152,14 +3289,14 @@ function Avatar({
3152
3289
  },
3153
3290
  style
3154
3291
  ],
3155
- children: uri ? /* @__PURE__ */ jsx16(
3292
+ children: uri ? /* @__PURE__ */ jsx18(
3156
3293
  Image2,
3157
3294
  {
3158
3295
  source: { uri },
3159
3296
  style: [{ width: size, height: size }, imageStyle],
3160
3297
  resizeMode: "cover"
3161
3298
  }
3162
- ) : /* @__PURE__ */ jsx16(Text, { variant: "caption", style: { color: theme.colors.onNeutral }, children: initialsFrom(name) })
3299
+ ) : /* @__PURE__ */ jsx18(Text, { variant: "caption", style: { color: theme.colors.onNeutral }, children: initialsFrom(name) })
3163
3300
  }
3164
3301
  );
3165
3302
  }
@@ -3183,12 +3320,12 @@ function formatTimeAgo(iso) {
3183
3320
  }
3184
3321
 
3185
3322
  // src/components/comments/CommentRow.tsx
3186
- import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
3323
+ import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
3187
3324
  function CommentRow({ comment, showDivider }) {
3188
3325
  const theme = useTheme();
3189
- const [authorName, setAuthorName] = React17.useState(null);
3190
- const [authorAvatar, setAuthorAvatar] = React17.useState(null);
3191
- React17.useEffect(() => {
3326
+ const [authorName, setAuthorName] = React19.useState(null);
3327
+ const [authorAvatar, setAuthorAvatar] = React19.useState(null);
3328
+ React19.useEffect(() => {
3192
3329
  let cancelled = false;
3193
3330
  (async () => {
3194
3331
  try {
@@ -3214,13 +3351,13 @@ function CommentRow({ comment, showDivider }) {
3214
3351
  borderBottomColor: withAlpha(theme.colors.border, 0.5)
3215
3352
  },
3216
3353
  children: [
3217
- /* @__PURE__ */ jsx17(Avatar, { size: 32, uri: authorAvatar, name: authorName ?? comment.authorId, style: { marginTop: 6 } }),
3354
+ /* @__PURE__ */ jsx19(Avatar, { size: 32, uri: authorAvatar, name: authorName ?? comment.authorId, style: { marginTop: 6 } }),
3218
3355
  /* @__PURE__ */ jsxs9(View13, { style: { flex: 1, minWidth: 0, gap: 4 }, children: [
3219
3356
  /* @__PURE__ */ jsxs9(View13, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.sm }, children: [
3220
- /* @__PURE__ */ jsx17(Text, { style: { fontSize: 14, lineHeight: 18, fontWeight: theme.typography.fontWeight.bold, color: theme.colors.text }, children: authorName ?? "Unknown User" }),
3221
- /* @__PURE__ */ jsx17(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, children: formatTimeAgo(comment.createdAt) })
3357
+ /* @__PURE__ */ jsx19(Text, { style: { fontSize: 14, lineHeight: 18, fontWeight: theme.typography.fontWeight.bold, color: theme.colors.text }, children: authorName ?? "Unknown User" }),
3358
+ /* @__PURE__ */ jsx19(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, children: formatTimeAgo(comment.createdAt) })
3222
3359
  ] }),
3223
- /* @__PURE__ */ jsx17(Text, { style: { fontSize: 14, lineHeight: 20, color: theme.colors.text }, children: comment.body ?? comment.description ?? "" })
3360
+ /* @__PURE__ */ jsx19(Text, { style: { fontSize: 14, lineHeight: 20, color: theme.colors.text }, children: comment.body ?? comment.description ?? "" })
3224
3361
  ] })
3225
3362
  ]
3226
3363
  }
@@ -3228,7 +3365,7 @@ function CommentRow({ comment, showDivider }) {
3228
3365
  }
3229
3366
 
3230
3367
  // src/components/comments/useAppComments.ts
3231
- import * as React18 from "react";
3368
+ import * as React20 from "react";
3232
3369
 
3233
3370
  // src/data/comments/remote.ts
3234
3371
  var AppCommentsRemoteDataSourceImpl = class extends BaseRemote {
@@ -3300,18 +3437,18 @@ var appCommentsRepository = new AppCommentsRepositoryImpl(appCommentsRemoteDataS
3300
3437
 
3301
3438
  // src/components/comments/useAppComments.ts
3302
3439
  function useAppComments(appId) {
3303
- const [comments, setComments] = React18.useState([]);
3304
- const [loading, setLoading] = React18.useState(false);
3305
- const [sending, setSending] = React18.useState(false);
3306
- const [error, setError] = React18.useState(null);
3307
- const sortByCreatedAtAsc = React18.useCallback((items) => {
3440
+ const [comments, setComments] = React20.useState([]);
3441
+ const [loading, setLoading] = React20.useState(false);
3442
+ const [sending, setSending] = React20.useState(false);
3443
+ const [error, setError] = React20.useState(null);
3444
+ const sortByCreatedAtAsc = React20.useCallback((items) => {
3308
3445
  return [...items].sort((a, b) => {
3309
3446
  const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
3310
3447
  const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
3311
3448
  return at - bt;
3312
3449
  });
3313
3450
  }, []);
3314
- const refresh = React18.useCallback(async () => {
3451
+ const refresh = React20.useCallback(async () => {
3315
3452
  if (!appId) {
3316
3453
  setComments([]);
3317
3454
  return;
@@ -3328,10 +3465,10 @@ function useAppComments(appId) {
3328
3465
  setLoading(false);
3329
3466
  }
3330
3467
  }, [appId, sortByCreatedAtAsc]);
3331
- React18.useEffect(() => {
3468
+ React20.useEffect(() => {
3332
3469
  void refresh();
3333
3470
  }, [refresh]);
3334
- const create = React18.useCallback(
3471
+ const create = React20.useCallback(
3335
3472
  async (text) => {
3336
3473
  if (!appId) return;
3337
3474
  const trimmed = text.trim();
@@ -3354,11 +3491,11 @@ function useAppComments(appId) {
3354
3491
  }
3355
3492
 
3356
3493
  // src/components/comments/useAppDetails.ts
3357
- import * as React19 from "react";
3494
+ import * as React21 from "react";
3358
3495
  function useAppDetails(appId) {
3359
- const [app, setApp] = React19.useState(null);
3360
- const [loading, setLoading] = React19.useState(false);
3361
- React19.useEffect(() => {
3496
+ const [app, setApp] = React21.useState(null);
3497
+ const [loading, setLoading] = React21.useState(false);
3498
+ React21.useEffect(() => {
3362
3499
  if (!appId) {
3363
3500
  setApp(null);
3364
3501
  return;
@@ -3383,12 +3520,12 @@ function useAppDetails(appId) {
3383
3520
  }
3384
3521
 
3385
3522
  // src/components/comments/useIosKeyboardSnapFix.ts
3386
- import * as React20 from "react";
3387
- import { Keyboard as Keyboard2, Platform as Platform3 } from "react-native";
3523
+ import * as React22 from "react";
3524
+ import { Keyboard as Keyboard2, Platform as Platform5 } from "react-native";
3388
3525
  function useIosKeyboardSnapFix(sheetRef, options) {
3389
- const [keyboardVisible, setKeyboardVisible] = React20.useState(false);
3390
- React20.useEffect(() => {
3391
- if (Platform3.OS !== "ios") return;
3526
+ const [keyboardVisible, setKeyboardVisible] = React22.useState(false);
3527
+ React22.useEffect(() => {
3528
+ if (Platform5.OS !== "ios") return;
3392
3529
  const show = Keyboard2.addListener("keyboardWillShow", () => setKeyboardVisible(true));
3393
3530
  const hide = Keyboard2.addListener("keyboardWillHide", () => {
3394
3531
  var _a;
@@ -3411,20 +3548,20 @@ function useIosKeyboardSnapFix(sheetRef, options) {
3411
3548
  }
3412
3549
 
3413
3550
  // src/components/comments/AppCommentsSheet.tsx
3414
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
3551
+ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
3415
3552
  function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3416
3553
  const theme = useTheme();
3417
3554
  const insets = useSafeAreaInsets3();
3418
- const sheetRef = React21.useRef(null);
3419
- const snapPoints = React21.useMemo(() => ["50%", "90%"], []);
3420
- const currentIndexRef = React21.useRef(1);
3555
+ const sheetRef = React23.useRef(null);
3556
+ const snapPoints = React23.useMemo(() => ["50%", "90%"], []);
3557
+ const currentIndexRef = React23.useRef(1);
3421
3558
  const { comments, loading, sending, error, create, refresh } = useAppComments(appId);
3422
3559
  const { app, loading: loadingApp } = useAppDetails(appId);
3423
3560
  const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef, {
3424
3561
  getCurrentIndex: () => currentIndexRef.current,
3425
3562
  targetIndex: 1
3426
3563
  });
3427
- React21.useEffect(() => {
3564
+ React23.useEffect(() => {
3428
3565
  var _a, _b;
3429
3566
  if (appId) {
3430
3567
  (_a = sheetRef.current) == null ? void 0 : _a.present();
@@ -3433,29 +3570,29 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3433
3570
  (_b = sheetRef.current) == null ? void 0 : _b.dismiss();
3434
3571
  }
3435
3572
  }, [appId, refresh]);
3436
- React21.useEffect(() => {
3573
+ React23.useEffect(() => {
3437
3574
  if (!appId) return;
3438
3575
  onCountChange == null ? void 0 : onCountChange(comments.length);
3439
3576
  }, [appId, comments.length, onCountChange]);
3440
- const renderBackdrop = React21.useCallback(
3441
- (props) => /* @__PURE__ */ jsx18(BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
3577
+ const renderBackdrop = React23.useCallback(
3578
+ (props) => /* @__PURE__ */ jsx20(BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
3442
3579
  []
3443
3580
  );
3444
- const handleChange = React21.useCallback(
3581
+ const handleChange = React23.useCallback(
3445
3582
  (index) => {
3446
3583
  currentIndexRef.current = index;
3447
3584
  if (index === -1) onClose();
3448
3585
  },
3449
3586
  [onClose]
3450
3587
  );
3451
- const handlePlay = React21.useCallback(async () => {
3588
+ const handlePlay = React23.useCallback(async () => {
3452
3589
  var _a;
3453
3590
  if (!appId) return;
3454
3591
  (_a = sheetRef.current) == null ? void 0 : _a.dismiss();
3455
3592
  await (onPlayApp == null ? void 0 : onPlayApp(appId));
3456
3593
  onClose();
3457
3594
  }, [appId, onClose, onPlayApp]);
3458
- return /* @__PURE__ */ jsx18(
3595
+ return /* @__PURE__ */ jsx20(
3459
3596
  BottomSheetModal,
3460
3597
  {
3461
3598
  ref: sheetRef,
@@ -3466,8 +3603,8 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3466
3603
  onChange: handleChange,
3467
3604
  backgroundStyle: {
3468
3605
  backgroundColor: theme.scheme === "dark" ? "#0B080F" : "#FFFFFF",
3469
- borderTopLeftRadius: Platform4.OS === "ios" ? 39 : 16,
3470
- borderTopRightRadius: Platform4.OS === "ios" ? 39 : 16
3606
+ borderTopLeftRadius: Platform6.OS === "ios" ? 39 : 16,
3607
+ borderTopRightRadius: Platform6.OS === "ios" ? 39 : 16
3471
3608
  },
3472
3609
  handleIndicatorStyle: { backgroundColor: theme.colors.handleIndicator },
3473
3610
  keyboardBehavior: "interactive",
@@ -3488,7 +3625,7 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3488
3625
  borderBottomColor: withAlpha(theme.colors.border, 0.1)
3489
3626
  },
3490
3627
  children: [
3491
- /* @__PURE__ */ jsx18(
3628
+ /* @__PURE__ */ jsx20(
3492
3629
  Text,
3493
3630
  {
3494
3631
  numberOfLines: 1,
@@ -3502,8 +3639,8 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3502
3639
  children: loadingApp ? "Loading..." : (app == null ? void 0 : app.name) || "Comments"
3503
3640
  }
3504
3641
  ),
3505
- /* @__PURE__ */ jsx18(
3506
- LiquidGlassView4,
3642
+ /* @__PURE__ */ jsx20(
3643
+ ResettableLiquidGlassView,
3507
3644
  {
3508
3645
  style: [
3509
3646
  { borderRadius: 24 },
@@ -3511,19 +3648,18 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3511
3648
  ],
3512
3649
  interactive: true,
3513
3650
  effect: "clear",
3514
- children: /* @__PURE__ */ jsx18(
3651
+ children: /* @__PURE__ */ jsx20(
3515
3652
  View14,
3516
3653
  {
3517
3654
  style: {
3518
3655
  width: 32,
3519
3656
  height: 32,
3520
3657
  borderRadius: 999,
3521
- backgroundColor: theme.colors.primary,
3658
+ backgroundColor: withAlpha(theme.colors.primary, appId ? 1 : 0.5),
3522
3659
  alignItems: "center",
3523
- justifyContent: "center",
3524
- opacity: appId ? 1 : 0.5
3660
+ justifyContent: "center"
3525
3661
  },
3526
- children: /* @__PURE__ */ jsx18(
3662
+ children: /* @__PURE__ */ jsx20(
3527
3663
  Pressable5,
3528
3664
  {
3529
3665
  disabled: !appId,
@@ -3536,9 +3672,9 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3536
3672
  alignItems: "center",
3537
3673
  justifyContent: "center"
3538
3674
  },
3539
- pressed ? { opacity: 0.85 } : null
3675
+ pressed ? { transform: [{ scale: 0.96 }] } : null
3540
3676
  ],
3541
- children: /* @__PURE__ */ jsx18(Play2, { size: 16, color: theme.colors.onPrimary })
3677
+ children: /* @__PURE__ */ jsx20(Play2, { size: 16, color: theme.colors.onPrimary })
3542
3678
  }
3543
3679
  )
3544
3680
  }
@@ -3559,12 +3695,12 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3559
3695
  },
3560
3696
  keyboardShouldPersistTaps: "handled",
3561
3697
  children: [
3562
- loading && comments.length === 0 ? /* @__PURE__ */ jsx18(View14, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx18(ActivityIndicator3, {}) }) : comments.length === 0 ? /* @__PURE__ */ jsx18(View14, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx18(Text, { variant: "bodyMuted", style: { textAlign: "center" }, children: "No comments yet" }) }) : comments.map((c, idx) => /* @__PURE__ */ jsx18(CommentRow, { comment: c, showDivider: idx < comments.length - 1 }, c.id)),
3563
- error ? /* @__PURE__ */ jsx18(Text, { variant: "captionMuted", style: { marginTop: theme.spacing.lg }, children: "Failed to load comments." }) : null
3698
+ loading && comments.length === 0 ? /* @__PURE__ */ jsx20(View14, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx20(ActivityIndicator3, {}) }) : comments.length === 0 ? /* @__PURE__ */ jsx20(View14, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx20(Text, { variant: "bodyMuted", style: { textAlign: "center" }, children: "No comments yet" }) }) : comments.map((c, idx) => /* @__PURE__ */ jsx20(CommentRow, { comment: c, showDivider: idx < comments.length - 1 }, c.id)),
3699
+ error ? /* @__PURE__ */ jsx20(Text, { variant: "captionMuted", style: { marginTop: theme.spacing.lg }, children: "Failed to load comments." }) : null
3564
3700
  ]
3565
3701
  }
3566
3702
  ),
3567
- /* @__PURE__ */ jsx18(
3703
+ /* @__PURE__ */ jsx20(
3568
3704
  View14,
3569
3705
  {
3570
3706
  style: {
@@ -3574,12 +3710,12 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
3574
3710
  bottom: 0,
3575
3711
  paddingHorizontal: theme.spacing.lg,
3576
3712
  paddingTop: theme.spacing.sm,
3577
- paddingBottom: Platform4.OS === "ios" ? keyboardVisible ? theme.spacing.lg : insets.bottom : insets.bottom + 10,
3713
+ paddingBottom: Platform6.OS === "ios" ? keyboardVisible ? theme.spacing.lg : insets.bottom : insets.bottom + 10,
3578
3714
  borderTopWidth: 1,
3579
3715
  borderTopColor: withAlpha(theme.colors.border, 0.1),
3580
3716
  backgroundColor: withAlpha(theme.colors.background, 0.8)
3581
3717
  },
3582
- children: /* @__PURE__ */ jsx18(
3718
+ children: /* @__PURE__ */ jsx20(
3583
3719
  ChatComposer,
3584
3720
  {
3585
3721
  placeholder: "Write a comment...",
@@ -3605,12 +3741,12 @@ import { ActivityIndicator as ActivityIndicator7, View as View33 } from "react-n
3605
3741
  // src/components/preview/PreviewPage.tsx
3606
3742
  import { View as View15 } from "react-native";
3607
3743
  import { BottomSheetScrollView as BottomSheetScrollView2 } from "@gorhom/bottom-sheet";
3608
- import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
3744
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
3609
3745
  function PreviewPage({ header, children, contentStyle }) {
3610
3746
  const theme = useTheme();
3611
3747
  return /* @__PURE__ */ jsxs11(View15, { style: { flex: 1 }, children: [
3612
- header ? /* @__PURE__ */ jsx19(View15, { children: header }) : null,
3613
- /* @__PURE__ */ jsx19(
3748
+ header ? /* @__PURE__ */ jsx21(View15, { children: header }) : null,
3749
+ /* @__PURE__ */ jsx21(
3614
3750
  BottomSheetScrollView2,
3615
3751
  {
3616
3752
  style: { flex: 1 },
@@ -3633,7 +3769,7 @@ import { View as View18 } from "react-native";
3633
3769
 
3634
3770
  // src/components/studio-sheet/StudioSheetHeader.tsx
3635
3771
  import { View as View16 } from "react-native";
3636
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
3772
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
3637
3773
  function StudioSheetHeader({ left, center, right, style }) {
3638
3774
  const theme = useTheme();
3639
3775
  return /* @__PURE__ */ jsxs12(
@@ -3650,19 +3786,19 @@ function StudioSheetHeader({ left, center, right, style }) {
3650
3786
  style
3651
3787
  ],
3652
3788
  children: [
3653
- /* @__PURE__ */ jsx20(View16, { style: { flexDirection: "row", alignItems: "center" }, children: left }),
3654
- /* @__PURE__ */ jsx20(View16, { style: { flex: 1, alignItems: "center" }, children: center }),
3655
- /* @__PURE__ */ jsx20(View16, { style: { flexDirection: "row", alignItems: "center" }, children: right })
3789
+ /* @__PURE__ */ jsx22(View16, { style: { flexDirection: "row", alignItems: "center" }, children: left }),
3790
+ /* @__PURE__ */ jsx22(View16, { style: { flex: 1, alignItems: "center" }, children: center }),
3791
+ /* @__PURE__ */ jsx22(View16, { style: { flexDirection: "row", alignItems: "center" }, children: right })
3656
3792
  ]
3657
3793
  }
3658
3794
  );
3659
3795
  }
3660
3796
 
3661
3797
  // src/components/studio-sheet/StudioSheetHeaderIconButton.tsx
3662
- import * as React22 from "react";
3798
+ import * as React24 from "react";
3663
3799
  import { Pressable as Pressable6, View as View17 } from "react-native";
3664
- import { LiquidGlassView as LiquidGlassView5, isLiquidGlassSupported as isLiquidGlassSupported5 } from "@callstack/liquid-glass";
3665
- import { jsx as jsx21 } from "react/jsx-runtime";
3800
+ import { isLiquidGlassSupported as isLiquidGlassSupported5 } from "@callstack/liquid-glass";
3801
+ import { jsx as jsx23 } from "react/jsx-runtime";
3666
3802
  function StudioSheetHeaderIconButton({
3667
3803
  onPress,
3668
3804
  disabled,
@@ -3674,18 +3810,19 @@ function StudioSheetHeaderIconButton({
3674
3810
  }) {
3675
3811
  const theme = useTheme();
3676
3812
  const size = 44;
3677
- const [pressed, setPressed] = React22.useState(false);
3813
+ const [pressed, setPressed] = React24.useState(false);
3678
3814
  const solidBg = intent === "danger" ? theme.colors.danger : intent === "primary" ? theme.colors.primary : theme.colors.neutral;
3679
3815
  const glassFallbackBg = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
3680
3816
  const glassInnerBg = intent === "danger" ? theme.colors.danger : theme.colors.primary;
3681
3817
  const resolvedOpacity = disabled ? 0.6 : pressed ? 0.9 : 1;
3682
- return /* @__PURE__ */ jsx21(View17, { style, children: appearance === "glass" ? /* @__PURE__ */ jsx21(
3683
- LiquidGlassView5,
3818
+ const glassBg = withAlpha(glassInnerBg, resolvedOpacity);
3819
+ return /* @__PURE__ */ jsx23(View17, { style, children: appearance === "glass" ? /* @__PURE__ */ jsx23(
3820
+ ResettableLiquidGlassView,
3684
3821
  {
3685
3822
  style: [{ borderRadius: 100 }, !isLiquidGlassSupported5 && { backgroundColor: glassFallbackBg }],
3686
3823
  interactive: true,
3687
3824
  effect: "clear",
3688
- children: /* @__PURE__ */ jsx21(
3825
+ children: /* @__PURE__ */ jsx23(
3689
3826
  View17,
3690
3827
  {
3691
3828
  style: {
@@ -3694,10 +3831,9 @@ function StudioSheetHeaderIconButton({
3694
3831
  borderRadius: 100,
3695
3832
  alignItems: "center",
3696
3833
  justifyContent: "center",
3697
- backgroundColor: glassInnerBg,
3698
- opacity: resolvedOpacity
3834
+ backgroundColor: glassBg
3699
3835
  },
3700
- children: /* @__PURE__ */ jsx21(
3836
+ children: /* @__PURE__ */ jsx23(
3701
3837
  Pressable6,
3702
3838
  {
3703
3839
  accessibilityRole: "button",
@@ -3716,7 +3852,7 @@ function StudioSheetHeaderIconButton({
3716
3852
  }
3717
3853
  )
3718
3854
  }
3719
- ) : /* @__PURE__ */ jsx21(
3855
+ ) : /* @__PURE__ */ jsx23(
3720
3856
  View17,
3721
3857
  {
3722
3858
  style: {
@@ -3728,7 +3864,7 @@ function StudioSheetHeaderIconButton({
3728
3864
  backgroundColor: solidBg,
3729
3865
  opacity: resolvedOpacity
3730
3866
  },
3731
- children: /* @__PURE__ */ jsx21(
3867
+ children: /* @__PURE__ */ jsx23(
3732
3868
  Pressable6,
3733
3869
  {
3734
3870
  accessibilityRole: "button",
@@ -3749,15 +3885,15 @@ function StudioSheetHeaderIconButton({
3749
3885
  }
3750
3886
 
3751
3887
  // src/studio/ui/preview-panel/PreviewPanelHeader.tsx
3752
- import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
3888
+ import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
3753
3889
  function PreviewPanelHeader({ isOwner, onClose, onNavigateHome, onGoToChat }) {
3754
- return /* @__PURE__ */ jsx22(
3890
+ return /* @__PURE__ */ jsx24(
3755
3891
  StudioSheetHeader,
3756
3892
  {
3757
- left: onNavigateHome ? /* @__PURE__ */ jsx22(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", appearance: "glass", intent: "primary", children: /* @__PURE__ */ jsx22(IconHome, { size: 20, colorToken: "onPrimary" }) }) : null,
3893
+ left: onNavigateHome ? /* @__PURE__ */ jsx24(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", appearance: "glass", intent: "primary", children: /* @__PURE__ */ jsx24(IconHome, { size: 20, colorToken: "onPrimary" }) }) : null,
3758
3894
  center: null,
3759
3895
  right: /* @__PURE__ */ jsxs13(View18, { style: { flexDirection: "row", alignItems: "center" }, children: [
3760
- isOwner ? /* @__PURE__ */ jsx22(
3896
+ isOwner ? /* @__PURE__ */ jsx24(
3761
3897
  StudioSheetHeaderIconButton,
3762
3898
  {
3763
3899
  onPress: onGoToChat,
@@ -3765,10 +3901,10 @@ function PreviewPanelHeader({ isOwner, onClose, onNavigateHome, onGoToChat }) {
3765
3901
  intent: "primary",
3766
3902
  appearance: "glass",
3767
3903
  style: { marginRight: 8 },
3768
- children: /* @__PURE__ */ jsx22(IconChat, { size: 20, colorToken: "onPrimary" })
3904
+ children: /* @__PURE__ */ jsx24(IconChat, { size: 20, colorToken: "onPrimary" })
3769
3905
  }
3770
3906
  ) : null,
3771
- /* @__PURE__ */ jsx22(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", appearance: "glass", intent: "primary", children: /* @__PURE__ */ jsx22(IconClose, { size: 20, colorToken: "onPrimary" }) })
3907
+ /* @__PURE__ */ jsx24(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", appearance: "glass", intent: "primary", children: /* @__PURE__ */ jsx24(IconClose, { size: 20, colorToken: "onPrimary" }) })
3772
3908
  ] })
3773
3909
  }
3774
3910
  );
@@ -3779,7 +3915,7 @@ import { View as View20 } from "react-native";
3779
3915
 
3780
3916
  // src/components/primitives/Surface.tsx
3781
3917
  import { View as View19 } from "react-native";
3782
- import { jsx as jsx23 } from "react/jsx-runtime";
3918
+ import { jsx as jsx25 } from "react/jsx-runtime";
3783
3919
  function backgroundFor(variant, theme) {
3784
3920
  const { colors } = theme;
3785
3921
  switch (variant) {
@@ -3796,7 +3932,7 @@ function backgroundFor(variant, theme) {
3796
3932
  }
3797
3933
  function Surface({ variant = "surface", border = false, style, ...props }) {
3798
3934
  const theme = useTheme();
3799
- return /* @__PURE__ */ jsx23(
3935
+ return /* @__PURE__ */ jsx25(
3800
3936
  View19,
3801
3937
  {
3802
3938
  ...props,
@@ -3810,12 +3946,12 @@ function Surface({ variant = "surface", border = false, style, ...props }) {
3810
3946
  }
3811
3947
 
3812
3948
  // src/components/primitives/Card.tsx
3813
- import { jsx as jsx24 } from "react/jsx-runtime";
3949
+ import { jsx as jsx26 } from "react/jsx-runtime";
3814
3950
  function Card({ variant = "surface", padded = true, border = true, style, ...props }) {
3815
3951
  const theme = useTheme();
3816
3952
  const radius = theme.radii.lg;
3817
3953
  const padding = padded ? theme.spacing.lg : 0;
3818
- return /* @__PURE__ */ jsx24(
3954
+ return /* @__PURE__ */ jsx26(
3819
3955
  Surface,
3820
3956
  {
3821
3957
  ...props,
@@ -3827,7 +3963,7 @@ function Card({ variant = "surface", padded = true, border = true, style, ...pro
3827
3963
  }
3828
3964
 
3829
3965
  // src/components/preview/PreviewHeroCard.tsx
3830
- import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
3966
+ import { jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
3831
3967
  function PreviewHeroCard({
3832
3968
  aspectRatio = 4 / 3,
3833
3969
  overlayTopLeft,
@@ -3838,7 +3974,7 @@ function PreviewHeroCard({
3838
3974
  }) {
3839
3975
  const theme = useTheme();
3840
3976
  const radius = 16;
3841
- return /* @__PURE__ */ jsx25(
3977
+ return /* @__PURE__ */ jsx27(
3842
3978
  Card,
3843
3979
  {
3844
3980
  variant: "surfaceRaised",
@@ -3854,24 +3990,24 @@ function PreviewHeroCard({
3854
3990
  style
3855
3991
  ],
3856
3992
  children: /* @__PURE__ */ jsxs14(View20, { style: { flex: 1 }, children: [
3857
- background ? /* @__PURE__ */ jsx25(View20, { style: { position: "absolute", inset: 0 }, children: background }) : null,
3858
- image ? /* @__PURE__ */ jsx25(View20, { style: { position: "absolute", inset: 0 }, children: image }) : null,
3859
- overlayTopLeft ? /* @__PURE__ */ jsx25(View20, { style: { position: "absolute", top: theme.spacing.sm, left: theme.spacing.sm, zIndex: 2 }, children: overlayTopLeft }) : null,
3860
- overlayBottom ? /* @__PURE__ */ jsx25(View20, { style: { flex: 1, justifyContent: "flex-end" }, children: overlayBottom }) : null
3993
+ background ? /* @__PURE__ */ jsx27(View20, { style: { position: "absolute", inset: 0 }, children: background }) : null,
3994
+ image ? /* @__PURE__ */ jsx27(View20, { style: { position: "absolute", inset: 0 }, children: image }) : null,
3995
+ overlayTopLeft ? /* @__PURE__ */ jsx27(View20, { style: { position: "absolute", top: theme.spacing.sm, left: theme.spacing.sm, zIndex: 2 }, children: overlayTopLeft }) : null,
3996
+ overlayBottom ? /* @__PURE__ */ jsx27(View20, { style: { flex: 1, justifyContent: "flex-end" }, children: overlayBottom }) : null
3861
3997
  ] })
3862
3998
  }
3863
3999
  );
3864
4000
  }
3865
4001
 
3866
4002
  // src/components/preview/PreviewPlaceholder.tsx
3867
- import * as React23 from "react";
4003
+ import * as React25 from "react";
3868
4004
  import { Animated as Animated6 } from "react-native";
3869
4005
  import { LinearGradient as LinearGradient2 } from "expo-linear-gradient";
3870
- import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
4006
+ import { Fragment as Fragment3, jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
3871
4007
  function PreviewPlaceholder({ visible, style }) {
3872
4008
  if (!visible) return null;
3873
- const opacityAnim = React23.useRef(new Animated6.Value(0)).current;
3874
- React23.useEffect(() => {
4009
+ const opacityAnim = React25.useRef(new Animated6.Value(0)).current;
4010
+ React25.useEffect(() => {
3875
4011
  if (!visible) return;
3876
4012
  const animation = Animated6.loop(
3877
4013
  Animated6.sequence([
@@ -3889,7 +4025,7 @@ function PreviewPlaceholder({ visible, style }) {
3889
4025
  const opacity3 = opacityAnim.interpolate({ inputRange: [0, 1, 2, 3], outputRange: [0, 0, 1, 0] });
3890
4026
  const opacity4 = opacityAnim.interpolate({ inputRange: [0, 1, 2, 3], outputRange: [0, 0, 0, 1] });
3891
4027
  return /* @__PURE__ */ jsxs15(Fragment3, { children: [
3892
- /* @__PURE__ */ jsx26(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity1 }, style], children: /* @__PURE__ */ jsx26(
4028
+ /* @__PURE__ */ jsx28(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity1 }, style], children: /* @__PURE__ */ jsx28(
3893
4029
  LinearGradient2,
3894
4030
  {
3895
4031
  colors: ["rgba(98, 0, 238, 0.45)", "rgba(168, 85, 247, 0.35)"],
@@ -3898,7 +4034,7 @@ function PreviewPlaceholder({ visible, style }) {
3898
4034
  style: { width: "100%", height: "100%" }
3899
4035
  }
3900
4036
  ) }),
3901
- /* @__PURE__ */ jsx26(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity2 }, style], children: /* @__PURE__ */ jsx26(
4037
+ /* @__PURE__ */ jsx28(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity2 }, style], children: /* @__PURE__ */ jsx28(
3902
4038
  LinearGradient2,
3903
4039
  {
3904
4040
  colors: ["rgba(168, 85, 247, 0.45)", "rgba(139, 92, 246, 0.35)"],
@@ -3907,7 +4043,7 @@ function PreviewPlaceholder({ visible, style }) {
3907
4043
  style: { width: "100%", height: "100%" }
3908
4044
  }
3909
4045
  ) }),
3910
- /* @__PURE__ */ jsx26(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity3 }, style], children: /* @__PURE__ */ jsx26(
4046
+ /* @__PURE__ */ jsx28(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity3 }, style], children: /* @__PURE__ */ jsx28(
3911
4047
  LinearGradient2,
3912
4048
  {
3913
4049
  colors: ["rgba(139, 92, 246, 0.45)", "rgba(126, 34, 206, 0.35)"],
@@ -3916,7 +4052,7 @@ function PreviewPlaceholder({ visible, style }) {
3916
4052
  style: { width: "100%", height: "100%" }
3917
4053
  }
3918
4054
  ) }),
3919
- /* @__PURE__ */ jsx26(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity4 }, style], children: /* @__PURE__ */ jsx26(
4055
+ /* @__PURE__ */ jsx28(Animated6.View, { style: [{ position: "absolute", inset: 0, opacity: opacity4 }, style], children: /* @__PURE__ */ jsx28(
3920
4056
  LinearGradient2,
3921
4057
  {
3922
4058
  colors: ["rgba(126, 34, 206, 0.45)", "rgba(98, 0, 238, 0.35)"],
@@ -3930,10 +4066,10 @@ function PreviewPlaceholder({ visible, style }) {
3930
4066
 
3931
4067
  // src/components/preview/PreviewImage.tsx
3932
4068
  import { Image as Image3 } from "react-native";
3933
- import { jsx as jsx27 } from "react/jsx-runtime";
4069
+ import { jsx as jsx29 } from "react/jsx-runtime";
3934
4070
  function PreviewImage({ uri, onLoad, style }) {
3935
4071
  if (!uri) return null;
3936
- return /* @__PURE__ */ jsx27(
4072
+ return /* @__PURE__ */ jsx29(
3937
4073
  Image3,
3938
4074
  {
3939
4075
  source: { uri },
@@ -3946,14 +4082,14 @@ function PreviewImage({ uri, onLoad, style }) {
3946
4082
 
3947
4083
  // src/components/preview/StatsBar.tsx
3948
4084
  import { Pressable as Pressable7, View as View21 } from "react-native";
3949
- import { LiquidGlassView as LiquidGlassView6, isLiquidGlassSupported as isLiquidGlassSupported6 } from "@callstack/liquid-glass";
4085
+ import { isLiquidGlassSupported as isLiquidGlassSupported6 } from "@callstack/liquid-glass";
3950
4086
  import { Heart, MessageCircle } from "lucide-react-native";
3951
4087
 
3952
4088
  // src/components/icons/MergeIcon.tsx
3953
4089
  import Svg2, { Path as Path2 } from "react-native-svg";
3954
- import { jsx as jsx28 } from "react/jsx-runtime";
4090
+ import { jsx as jsx30 } from "react/jsx-runtime";
3955
4091
  function MergeIcon({ color = "currentColor", width = 24, height = 24, ...props }) {
3956
- return /* @__PURE__ */ jsx28(Svg2, { viewBox: "0 0 486 486", width, height, ...props, children: /* @__PURE__ */ jsx28(
4092
+ return /* @__PURE__ */ jsx30(Svg2, { viewBox: "0 0 486 486", width, height, ...props, children: /* @__PURE__ */ jsx30(
3957
4093
  Path2,
3958
4094
  {
3959
4095
  d: "M237.025 0H243.664C254.876 95.0361 275.236 175.597 304.743 241.684C334.249 307.478 367.002 357.774 403 392.572L389.722 486C361.691 458.22 338.233 429.417 319.349 399.59C300.464 369.764 284.531 335.843 271.548 297.829C258.565 259.522 246.615 214.343 235.697 162.292L237.91 161.415C228.468 214.928 217.993 261.569 206.485 301.338C194.978 341.107 179.634 375.904 160.455 405.731C141.571 435.265 115.752 462.022 83 486L96.278 392.572C124.014 369.179 147.62 336.72 167.094 295.197C186.864 253.381 202.65 206.886 214.452 155.713C226.255 104.247 233.779 52.343 237.025 0Z",
@@ -3963,7 +4099,7 @@ function MergeIcon({ color = "currentColor", width = 24, height = 24, ...props }
3963
4099
  }
3964
4100
 
3965
4101
  // src/components/preview/StatsBar.tsx
3966
- import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
4102
+ import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
3967
4103
  function StatsBar({
3968
4104
  likeCount,
3969
4105
  commentCount,
@@ -3977,7 +4113,7 @@ function StatsBar({
3977
4113
  }) {
3978
4114
  const theme = useTheme();
3979
4115
  const statsBgColor = theme.scheme === "dark" ? "rgba(24, 24, 27, 0.5)" : "rgba(255, 255, 255, 0.5)";
3980
- return /* @__PURE__ */ jsx29(
4116
+ return /* @__PURE__ */ jsx31(
3981
4117
  View21,
3982
4118
  {
3983
4119
  style: [
@@ -3985,8 +4121,8 @@ function StatsBar({
3985
4121
  centered && { alignItems: "center" },
3986
4122
  style
3987
4123
  ],
3988
- children: /* @__PURE__ */ jsx29(
3989
- LiquidGlassView6,
4124
+ children: /* @__PURE__ */ jsx31(
4125
+ ResettableLiquidGlassView,
3990
4126
  {
3991
4127
  style: [
3992
4128
  { borderRadius: 100, overflow: "hidden" },
@@ -3995,7 +4131,7 @@ function StatsBar({
3995
4131
  ],
3996
4132
  effect: "clear",
3997
4133
  children: /* @__PURE__ */ jsxs16(View21, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 16 }, children: [
3998
- /* @__PURE__ */ jsx29(
4134
+ /* @__PURE__ */ jsx31(
3999
4135
  Pressable7,
4000
4136
  {
4001
4137
  disabled: !onPressLike,
@@ -4003,7 +4139,7 @@ function StatsBar({
4003
4139
  hitSlop: 8,
4004
4140
  style: { paddingVertical: 8 },
4005
4141
  children: /* @__PURE__ */ jsxs16(View21, { style: { flexDirection: "row", alignItems: "center" }, children: [
4006
- /* @__PURE__ */ jsx29(
4142
+ /* @__PURE__ */ jsx31(
4007
4143
  Heart,
4008
4144
  {
4009
4145
  size: 16,
@@ -4012,8 +4148,8 @@ function StatsBar({
4012
4148
  fill: isLiked ? theme.colors.danger : "transparent"
4013
4149
  }
4014
4150
  ),
4015
- /* @__PURE__ */ jsx29(View21, { style: { width: 4 } }),
4016
- /* @__PURE__ */ jsx29(
4151
+ /* @__PURE__ */ jsx31(View21, { style: { width: 4 } }),
4152
+ /* @__PURE__ */ jsx31(
4017
4153
  Text,
4018
4154
  {
4019
4155
  variant: "caption",
@@ -4027,7 +4163,7 @@ function StatsBar({
4027
4163
  ] })
4028
4164
  }
4029
4165
  ),
4030
- /* @__PURE__ */ jsx29(
4166
+ /* @__PURE__ */ jsx31(
4031
4167
  Pressable7,
4032
4168
  {
4033
4169
  disabled: !onPressComments,
@@ -4035,16 +4171,16 @@ function StatsBar({
4035
4171
  hitSlop: 8,
4036
4172
  style: { paddingVertical: 8 },
4037
4173
  children: /* @__PURE__ */ jsxs16(View21, { style: { flexDirection: "row", alignItems: "center" }, children: [
4038
- /* @__PURE__ */ jsx29(MessageCircle, { size: 16, strokeWidth: 2.5, color: "#FFFFFF" }),
4039
- /* @__PURE__ */ jsx29(View21, { style: { width: 4 } }),
4040
- /* @__PURE__ */ jsx29(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: commentCount })
4174
+ /* @__PURE__ */ jsx31(MessageCircle, { size: 16, strokeWidth: 2.5, color: "#FFFFFF" }),
4175
+ /* @__PURE__ */ jsx31(View21, { style: { width: 4 } }),
4176
+ /* @__PURE__ */ jsx31(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: commentCount })
4041
4177
  ] })
4042
4178
  }
4043
4179
  ),
4044
4180
  /* @__PURE__ */ jsxs16(View21, { style: { flexDirection: "row", alignItems: "center", paddingVertical: 8 }, children: [
4045
- /* @__PURE__ */ jsx29(View21, { style: { transform: [{ scaleY: -1 }] }, children: /* @__PURE__ */ jsx29(MergeIcon, { width: 14, height: 14, color: "#FFFFFF" }) }),
4046
- /* @__PURE__ */ jsx29(View21, { style: { width: 4 } }),
4047
- /* @__PURE__ */ jsx29(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: forkCount })
4181
+ /* @__PURE__ */ jsx31(View21, { style: { transform: [{ scaleY: -1 }] }, children: /* @__PURE__ */ jsx31(MergeIcon, { width: 14, height: 14, color: "#FFFFFF" }) }),
4182
+ /* @__PURE__ */ jsx31(View21, { style: { width: 4 } }),
4183
+ /* @__PURE__ */ jsx31(Text, { variant: "caption", style: { color: "#FFFFFF", fontWeight: theme.typography.fontWeight.bold }, children: forkCount })
4048
4184
  ] })
4049
4185
  ] })
4050
4186
  }
@@ -4077,7 +4213,7 @@ var APP_STATUS_LABEL = {
4077
4213
  };
4078
4214
 
4079
4215
  // src/components/preview/PreviewStatusBadge.tsx
4080
- import { jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
4216
+ import { jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
4081
4217
  var STATUS_BG = {
4082
4218
  ready: "#10B981",
4083
4219
  // emerald-500
@@ -4118,15 +4254,15 @@ function PreviewStatusBadge({ status }) {
4118
4254
  backgroundColor: STATUS_BG[status]
4119
4255
  },
4120
4256
  children: [
4121
- /* @__PURE__ */ jsx30(IconComp, { size: 12, color: "#FFFFFF", style: { marginRight: 4 } }),
4122
- /* @__PURE__ */ jsx30(Text, { style: { color: "#FFFFFF", fontSize: 11, lineHeight: 14 }, children: label })
4257
+ /* @__PURE__ */ jsx32(IconComp, { size: 12, color: "#FFFFFF", style: { marginRight: 4 } }),
4258
+ /* @__PURE__ */ jsx32(Text, { style: { color: "#FFFFFF", fontSize: 11, lineHeight: 14 }, children: label })
4123
4259
  ]
4124
4260
  }
4125
4261
  );
4126
4262
  }
4127
4263
 
4128
4264
  // src/studio/ui/preview-panel/PreviewHeroSection.tsx
4129
- import { jsx as jsx31 } from "react/jsx-runtime";
4265
+ import { jsx as jsx33 } from "react/jsx-runtime";
4130
4266
  function PreviewHeroSection({
4131
4267
  appStatus,
4132
4268
  showProcessing,
@@ -4135,13 +4271,13 @@ function PreviewHeroSection({
4135
4271
  onImageLoad,
4136
4272
  stats
4137
4273
  }) {
4138
- return /* @__PURE__ */ jsx31(
4274
+ return /* @__PURE__ */ jsx33(
4139
4275
  PreviewHeroCard,
4140
4276
  {
4141
- overlayTopLeft: showProcessing ? /* @__PURE__ */ jsx31(PreviewStatusBadge, { status: appStatus }) : null,
4142
- background: /* @__PURE__ */ jsx31(PreviewPlaceholder, { visible: !imageLoaded }),
4143
- image: /* @__PURE__ */ jsx31(PreviewImage, { uri: imageUrl, onLoad: onImageLoad }),
4144
- overlayBottom: /* @__PURE__ */ jsx31(
4277
+ overlayTopLeft: showProcessing ? /* @__PURE__ */ jsx33(PreviewStatusBadge, { status: appStatus }) : null,
4278
+ background: /* @__PURE__ */ jsx33(PreviewPlaceholder, { visible: !imageLoaded }),
4279
+ image: /* @__PURE__ */ jsx33(PreviewImage, { uri: imageUrl, onLoad: onImageLoad }),
4280
+ overlayBottom: /* @__PURE__ */ jsx33(
4145
4281
  StatsBar,
4146
4282
  {
4147
4283
  likeCount: stats.likeCount,
@@ -4164,7 +4300,7 @@ import { View as View24 } from "react-native";
4164
4300
 
4165
4301
  // src/components/preview/PreviewMetaRow.tsx
4166
4302
  import { View as View23 } from "react-native";
4167
- import { jsx as jsx32, jsxs as jsxs18 } from "react/jsx-runtime";
4303
+ import { jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
4168
4304
  function PreviewMetaRow({
4169
4305
  avatarUri,
4170
4306
  creatorName,
@@ -4177,9 +4313,9 @@ function PreviewMetaRow({
4177
4313
  const theme = useTheme();
4178
4314
  return /* @__PURE__ */ jsxs18(View23, { style: [{ alignSelf: "stretch" }, style], children: [
4179
4315
  /* @__PURE__ */ jsxs18(View23, { style: { flexDirection: "row", alignItems: "center" }, children: [
4180
- /* @__PURE__ */ jsx32(Avatar, { uri: avatarUri, name: creatorName, size: 24, style: { marginRight: theme.spacing.sm } }),
4316
+ /* @__PURE__ */ jsx34(Avatar, { uri: avatarUri, name: creatorName, size: 24, style: { marginRight: theme.spacing.sm } }),
4181
4317
  /* @__PURE__ */ jsxs18(View23, { style: { flexDirection: "row", alignItems: "center", flex: 1, minWidth: 0, marginRight: theme.spacing.sm }, children: [
4182
- /* @__PURE__ */ jsx32(
4318
+ /* @__PURE__ */ jsx34(
4183
4319
  Text,
4184
4320
  {
4185
4321
  numberOfLines: 1,
@@ -4193,11 +4329,11 @@ function PreviewMetaRow({
4193
4329
  children: title
4194
4330
  }
4195
4331
  ),
4196
- tag ? /* @__PURE__ */ jsx32(View23, { style: { marginLeft: theme.spacing.sm }, children: tag }) : null
4332
+ tag ? /* @__PURE__ */ jsx34(View23, { style: { marginLeft: theme.spacing.sm }, children: tag }) : null
4197
4333
  ] }),
4198
- rightMetric ? /* @__PURE__ */ jsx32(View23, { children: rightMetric }) : null
4334
+ rightMetric ? /* @__PURE__ */ jsx34(View23, { children: rightMetric }) : null
4199
4335
  ] }),
4200
- subtitle ? /* @__PURE__ */ jsx32(
4336
+ subtitle ? /* @__PURE__ */ jsx34(
4201
4337
  Text,
4202
4338
  {
4203
4339
  numberOfLines: 2,
@@ -4240,18 +4376,18 @@ function statusDescription(status, statusError) {
4240
4376
  }
4241
4377
 
4242
4378
  // src/studio/ui/preview-panel/PreviewMetaSection.tsx
4243
- import { jsx as jsx33, jsxs as jsxs19 } from "react/jsx-runtime";
4379
+ import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
4244
4380
  function PreviewMetaSection({ app, isOwner, creator, downloadsCount }) {
4245
4381
  var _a;
4246
4382
  const theme = useTheme();
4247
- return /* @__PURE__ */ jsx33(
4383
+ return /* @__PURE__ */ jsx35(
4248
4384
  PreviewMetaRow,
4249
4385
  {
4250
4386
  title: app.name,
4251
4387
  subtitle: app.description,
4252
4388
  avatarUri: (creator == null ? void 0 : creator.avatar) ?? null,
4253
4389
  creatorName: (creator == null ? void 0 : creator.name) ?? null,
4254
- tag: isOwner || app.forkedFromAppId ? /* @__PURE__ */ jsx33(View24, { style: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: "#3700B3" }, children: /* @__PURE__ */ jsx33(Text, { variant: "caption", style: { color: "#fff", fontWeight: theme.typography.fontWeight.semibold }, children: app.forkedFromAppId ? "Remix" : "Owner" }) }) : null,
4390
+ tag: isOwner || app.forkedFromAppId ? /* @__PURE__ */ jsx35(View24, { style: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: "#3700B3" }, children: /* @__PURE__ */ jsx35(Text, { variant: "caption", style: { color: "#fff", fontWeight: theme.typography.fontWeight.semibold }, children: app.forkedFromAppId ? "Remix" : "Owner" }) }) : null,
4255
4391
  rightMetric: /* @__PURE__ */ jsxs19(
4256
4392
  View24,
4257
4393
  {
@@ -4264,7 +4400,7 @@ function PreviewMetaSection({ app, isOwner, creator, downloadsCount }) {
4264
4400
  backgroundColor: withAlpha(theme.colors.neutral, 0.3)
4265
4401
  },
4266
4402
  children: [
4267
- /* @__PURE__ */ jsx33(
4403
+ /* @__PURE__ */ jsx35(
4268
4404
  Text,
4269
4405
  {
4270
4406
  style: {
@@ -4277,7 +4413,7 @@ function PreviewMetaSection({ app, isOwner, creator, downloadsCount }) {
4277
4413
  children: formatCount(downloadsCount ?? ((_a = app.insights) == null ? void 0 : _a.totalDownloads) ?? 0)
4278
4414
  }
4279
4415
  ),
4280
- /* @__PURE__ */ jsx33(IconPlay, { size: 14, colorToken: "textMuted", fill: theme.colors.textMuted })
4416
+ /* @__PURE__ */ jsx35(IconPlay, { size: 14, colorToken: "textMuted", fill: theme.colors.textMuted })
4281
4417
  ]
4282
4418
  }
4283
4419
  ),
@@ -4291,7 +4427,7 @@ import { ActivityIndicator as ActivityIndicator4, View as View26 } from "react-n
4291
4427
 
4292
4428
  // src/studio/ui/preview-panel/PressableCardRow.tsx
4293
4429
  import { Pressable as Pressable8, View as View25 } from "react-native";
4294
- import { jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
4430
+ import { jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
4295
4431
  function PressableCardRow({
4296
4432
  accessibilityLabel,
4297
4433
  onPress,
@@ -4302,7 +4438,7 @@ function PressableCardRow({
4302
4438
  right,
4303
4439
  style
4304
4440
  }) {
4305
- return /* @__PURE__ */ jsx34(
4441
+ return /* @__PURE__ */ jsx36(
4306
4442
  Pressable8,
4307
4443
  {
4308
4444
  accessibilityRole: "button",
@@ -4310,23 +4446,23 @@ function PressableCardRow({
4310
4446
  disabled,
4311
4447
  onPress,
4312
4448
  style: ({ pressed }) => ({ opacity: disabled ? 0.6 : pressed ? 0.85 : 1 }),
4313
- children: /* @__PURE__ */ jsx34(Card, { padded: false, border: false, style, children: /* @__PURE__ */ jsxs20(View25, { style: { flexDirection: "row", alignItems: "center" }, children: [
4449
+ children: /* @__PURE__ */ jsx36(Card, { padded: false, border: false, style, children: /* @__PURE__ */ jsxs20(View25, { style: { flexDirection: "row", alignItems: "center" }, children: [
4314
4450
  left,
4315
4451
  /* @__PURE__ */ jsxs20(View25, { style: { flex: 1, minWidth: 0 }, children: [
4316
4452
  title,
4317
4453
  subtitle ? subtitle : null
4318
4454
  ] }),
4319
- right ? /* @__PURE__ */ jsx34(View25, { style: { marginLeft: 16 }, children: right }) : null
4455
+ right ? /* @__PURE__ */ jsx36(View25, { style: { marginLeft: 16 }, children: right }) : null
4320
4456
  ] }) })
4321
4457
  }
4322
4458
  );
4323
4459
  }
4324
4460
 
4325
4461
  // src/studio/ui/preview-panel/SectionTitle.tsx
4326
- import { jsx as jsx35 } from "react/jsx-runtime";
4462
+ import { jsx as jsx37 } from "react/jsx-runtime";
4327
4463
  function SectionTitle({ children, marginTop }) {
4328
4464
  const theme = useTheme();
4329
- return /* @__PURE__ */ jsx35(
4465
+ return /* @__PURE__ */ jsx37(
4330
4466
  Text,
4331
4467
  {
4332
4468
  style: {
@@ -4345,7 +4481,7 @@ function SectionTitle({ children, marginTop }) {
4345
4481
  }
4346
4482
 
4347
4483
  // src/studio/ui/preview-panel/PreviewCustomizeSection.tsx
4348
- import { Fragment as Fragment4, jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
4484
+ import { Fragment as Fragment4, jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
4349
4485
  function PreviewCustomizeSection({
4350
4486
  app,
4351
4487
  isOwner,
@@ -4356,7 +4492,7 @@ function PreviewCustomizeSection({
4356
4492
  }) {
4357
4493
  const theme = useTheme();
4358
4494
  return /* @__PURE__ */ jsxs21(Fragment4, { children: [
4359
- /* @__PURE__ */ jsx36(SectionTitle, { children: "Customize" }),
4495
+ /* @__PURE__ */ jsx38(SectionTitle, { children: "Customize" }),
4360
4496
  showProcessing ? /* @__PURE__ */ jsxs21(
4361
4497
  View26,
4362
4498
  {
@@ -4371,7 +4507,7 @@ function PreviewCustomizeSection({
4371
4507
  marginBottom: theme.spacing.sm
4372
4508
  },
4373
4509
  children: [
4374
- /* @__PURE__ */ jsx36(
4510
+ /* @__PURE__ */ jsx38(
4375
4511
  View26,
4376
4512
  {
4377
4513
  style: {
@@ -4383,17 +4519,17 @@ function PreviewCustomizeSection({
4383
4519
  backgroundColor: withAlpha(theme.colors.warning, 0.1),
4384
4520
  marginRight: theme.spacing.lg
4385
4521
  },
4386
- children: /* @__PURE__ */ jsx36(ActivityIndicator4, { color: theme.colors.warning, size: "small" })
4522
+ children: /* @__PURE__ */ jsx38(ActivityIndicator4, { color: theme.colors.warning, size: "small" })
4387
4523
  }
4388
4524
  ),
4389
4525
  /* @__PURE__ */ jsxs21(View26, { style: { flex: 1, minWidth: 0 }, children: [
4390
- /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: app.status === "error" ? "Error" : "Processing" }),
4391
- /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: statusDescription(app.status, app.statusError) })
4526
+ /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: app.status === "error" ? "Error" : "Processing" }),
4527
+ /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: statusDescription(app.status, app.statusError) })
4392
4528
  ] })
4393
4529
  ]
4394
4530
  }
4395
4531
  ) : null,
4396
- /* @__PURE__ */ jsx36(
4532
+ /* @__PURE__ */ jsx38(
4397
4533
  PressableCardRow,
4398
4534
  {
4399
4535
  accessibilityLabel: isOwner ? "Edit app" : "Remix app",
@@ -4406,7 +4542,7 @@ function PreviewCustomizeSection({
4406
4542
  borderColor: withAlpha(theme.colors.primary, 0.1),
4407
4543
  marginBottom: theme.spacing.sm
4408
4544
  },
4409
- left: /* @__PURE__ */ jsx36(
4545
+ left: /* @__PURE__ */ jsx38(
4410
4546
  View26,
4411
4547
  {
4412
4548
  style: {
@@ -4418,15 +4554,15 @@ function PreviewCustomizeSection({
4418
4554
  backgroundColor: withAlpha(theme.colors.primary, 0.1),
4419
4555
  marginRight: theme.spacing.lg
4420
4556
  },
4421
- children: /* @__PURE__ */ jsx36(IconChat, { size: 20, colorToken: "primary" })
4557
+ children: /* @__PURE__ */ jsx38(IconChat, { size: 20, colorToken: "primary" })
4422
4558
  }
4423
4559
  ),
4424
- title: /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: isOwner ? app.forkedFromAppId ? "Edit your Remix" : "Edit Your App" : "Remix App" }),
4425
- subtitle: /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: isOwner && app.forkedFromAppId ? "Make changes to your remix with chat" : shouldForkOnEdit ? "Chat to create your own copy and edit it" : "Chat to apply changes" }),
4426
- right: /* @__PURE__ */ jsx36(IconChevronRight, { size: 20, colorToken: "textMuted" })
4560
+ title: /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: isOwner ? app.forkedFromAppId ? "Edit your Remix" : "Edit Your App" : "Remix App" }),
4561
+ subtitle: /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: isOwner && app.forkedFromAppId ? "Make changes to your remix with chat" : shouldForkOnEdit ? "Chat to create your own copy and edit it" : "Chat to apply changes" }),
4562
+ right: /* @__PURE__ */ jsx38(IconChevronRight, { size: 20, colorToken: "textMuted" })
4427
4563
  }
4428
4564
  ),
4429
- isOwner && onStartDraw ? /* @__PURE__ */ jsx36(
4565
+ isOwner && onStartDraw ? /* @__PURE__ */ jsx38(
4430
4566
  PressableCardRow,
4431
4567
  {
4432
4568
  accessibilityLabel: "Draw changes",
@@ -4439,7 +4575,7 @@ function PreviewCustomizeSection({
4439
4575
  borderColor: withAlpha(theme.colors.danger, 0.1),
4440
4576
  marginBottom: theme.spacing.sm
4441
4577
  },
4442
- left: /* @__PURE__ */ jsx36(
4578
+ left: /* @__PURE__ */ jsx38(
4443
4579
  View26,
4444
4580
  {
4445
4581
  style: {
@@ -4451,31 +4587,31 @@ function PreviewCustomizeSection({
4451
4587
  backgroundColor: withAlpha(theme.colors.danger, 0.1),
4452
4588
  marginRight: theme.spacing.lg
4453
4589
  },
4454
- children: /* @__PURE__ */ jsx36(IconDraw, { size: 20, colorToken: "danger" })
4590
+ children: /* @__PURE__ */ jsx38(IconDraw, { size: 20, colorToken: "danger" })
4455
4591
  }
4456
4592
  ),
4457
- title: /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: "Draw Changes" }),
4458
- subtitle: /* @__PURE__ */ jsx36(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: "Annotate the app with drawings" }),
4459
- right: /* @__PURE__ */ jsx36(IconChevronRight, { size: 20, colorToken: "textMuted" })
4593
+ title: /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: "Draw Changes" }),
4594
+ subtitle: /* @__PURE__ */ jsx38(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: "Annotate the app with drawings" }),
4595
+ right: /* @__PURE__ */ jsx38(IconChevronRight, { size: 20, colorToken: "textMuted" })
4460
4596
  }
4461
4597
  ) : null
4462
4598
  ] });
4463
4599
  }
4464
4600
 
4465
4601
  // src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
4466
- import * as React29 from "react";
4602
+ import * as React31 from "react";
4467
4603
  import { ActivityIndicator as ActivityIndicator6, Alert, View as View32 } from "react-native";
4468
4604
  import { Send as Send2 } from "lucide-react-native";
4469
4605
 
4470
4606
  // src/components/merge-requests/MergeRequestStatusCard.tsx
4471
- import * as React25 from "react";
4607
+ import * as React27 from "react";
4472
4608
  import { Animated as Animated7, Pressable as Pressable9, View as View28 } from "react-native";
4473
4609
  import { Ban, Check as Check3, CheckCheck, ChevronDown as ChevronDown2 } from "lucide-react-native";
4474
4610
 
4475
4611
  // src/components/primitives/MarkdownText.tsx
4476
- import { Platform as Platform5, View as View27 } from "react-native";
4612
+ import { Platform as Platform7, View as View27 } from "react-native";
4477
4613
  import Markdown from "react-native-markdown-display";
4478
- import { jsx as jsx37 } from "react/jsx-runtime";
4614
+ import { jsx as jsx39 } from "react/jsx-runtime";
4479
4615
  function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
4480
4616
  const theme = useTheme();
4481
4617
  const isDark = theme.scheme === "dark";
@@ -4486,7 +4622,7 @@ function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
4486
4622
  const codeTextColor = isDark ? "#FFFFFF" : theme.colors.text;
4487
4623
  const paragraphBottom = variant === "mergeRequest" ? 8 : 6;
4488
4624
  const baseLineHeight = variant === "mergeRequest" ? 22 : 20;
4489
- return /* @__PURE__ */ jsx37(View27, { style, children: /* @__PURE__ */ jsx37(
4625
+ return /* @__PURE__ */ jsx39(View27, { style, children: /* @__PURE__ */ jsx39(
4490
4626
  Markdown,
4491
4627
  {
4492
4628
  style: {
@@ -4499,7 +4635,7 @@ function MarkdownText({ markdown, variant = "chat", bodyColor, style }) {
4499
4635
  paddingHorizontal: variant === "mergeRequest" ? 6 : 4,
4500
4636
  paddingVertical: variant === "mergeRequest" ? 2 : 0,
4501
4637
  borderRadius: variant === "mergeRequest" ? 6 : 4,
4502
- fontFamily: Platform5.OS === "ios" ? "Menlo" : "monospace",
4638
+ fontFamily: Platform7.OS === "ios" ? "Menlo" : "monospace",
4503
4639
  fontSize: 13
4504
4640
  },
4505
4641
  code_block: {
@@ -4550,11 +4686,11 @@ function toIsoString(input) {
4550
4686
  }
4551
4687
 
4552
4688
  // src/components/merge-requests/useControlledExpansion.ts
4553
- import * as React24 from "react";
4689
+ import * as React26 from "react";
4554
4690
  function useControlledExpansion(props) {
4555
- const [uncontrolled, setUncontrolled] = React24.useState(false);
4691
+ const [uncontrolled, setUncontrolled] = React26.useState(false);
4556
4692
  const expanded = props.expanded ?? uncontrolled;
4557
- const setExpanded = React24.useCallback(
4693
+ const setExpanded = React26.useCallback(
4558
4694
  (next) => {
4559
4695
  var _a;
4560
4696
  (_a = props.onExpandedChange) == null ? void 0 : _a.call(props, next);
@@ -4566,7 +4702,7 @@ function useControlledExpansion(props) {
4566
4702
  }
4567
4703
 
4568
4704
  // src/components/merge-requests/MergeRequestStatusCard.tsx
4569
- import { jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
4705
+ import { jsx as jsx40, jsxs as jsxs22 } from "react/jsx-runtime";
4570
4706
  function MergeRequestStatusCard({
4571
4707
  mergeRequest,
4572
4708
  expanded: expandedProp,
@@ -4579,8 +4715,8 @@ function MergeRequestStatusCard({
4579
4715
  const isDark = theme.scheme === "dark";
4580
4716
  const textColor = isDark ? "#FFFFFF" : "#000000";
4581
4717
  const subTextColor = isDark ? "#A1A1AA" : "#71717A";
4582
- const status = React25.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
4583
- const { StatusIcon, iconColor, bgColor, statusText } = React25.useMemo(() => {
4718
+ const status = React27.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
4719
+ const { StatusIcon, iconColor, bgColor, statusText } = React27.useMemo(() => {
4584
4720
  switch (mergeRequest.status) {
4585
4721
  case "approved":
4586
4722
  case "merged":
@@ -4611,15 +4747,15 @@ function MergeRequestStatusCard({
4611
4747
  const createdIso = toIsoString(mergeRequest.createdAt ?? null);
4612
4748
  const headerTimeAgo = updatedIso ? formatTimeAgo(updatedIso) : "";
4613
4749
  const createdTimeAgo = createdIso ? formatTimeAgo(createdIso) : "";
4614
- const rotate = React25.useRef(new Animated7.Value(expanded ? 1 : 0)).current;
4615
- React25.useEffect(() => {
4750
+ const rotate = React27.useRef(new Animated7.Value(expanded ? 1 : 0)).current;
4751
+ React27.useEffect(() => {
4616
4752
  Animated7.timing(rotate, {
4617
4753
  toValue: expanded ? 1 : 0,
4618
4754
  duration: 200,
4619
4755
  useNativeDriver: true
4620
4756
  }).start();
4621
4757
  }, [expanded, rotate]);
4622
- return /* @__PURE__ */ jsx38(Pressable9, { onPress: () => setExpanded(!expanded), style: ({ pressed }) => [{ opacity: pressed ? 0.95 : 1 }], children: /* @__PURE__ */ jsxs22(
4758
+ return /* @__PURE__ */ jsx40(Pressable9, { onPress: () => setExpanded(!expanded), style: ({ pressed }) => [{ opacity: pressed ? 0.95 : 1 }], children: /* @__PURE__ */ jsxs22(
4623
4759
  Card,
4624
4760
  {
4625
4761
  padded: false,
@@ -4633,10 +4769,10 @@ function MergeRequestStatusCard({
4633
4769
  ],
4634
4770
  children: [
4635
4771
  /* @__PURE__ */ jsxs22(View28, { style: { flexDirection: "row", alignItems: "center", gap: theme.spacing.lg }, children: [
4636
- /* @__PURE__ */ jsx38(View28, { style: { width: 40, height: 40, borderRadius: 999, alignItems: "center", justifyContent: "center", backgroundColor: bgColor }, children: /* @__PURE__ */ jsx38(StatusIcon, { size: 20, color: iconColor }) }),
4772
+ /* @__PURE__ */ jsx40(View28, { style: { width: 40, height: 40, borderRadius: 999, alignItems: "center", justifyContent: "center", backgroundColor: bgColor }, children: /* @__PURE__ */ jsx40(StatusIcon, { size: 20, color: iconColor }) }),
4637
4773
  /* @__PURE__ */ jsxs22(View28, { style: { flex: 1, minWidth: 0 }, children: [
4638
4774
  /* @__PURE__ */ jsxs22(View28, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4639
- /* @__PURE__ */ jsx38(
4775
+ /* @__PURE__ */ jsx40(
4640
4776
  Text,
4641
4777
  {
4642
4778
  style: {
@@ -4650,11 +4786,11 @@ function MergeRequestStatusCard({
4650
4786
  children: statusText
4651
4787
  }
4652
4788
  ),
4653
- headerTimeAgo ? /* @__PURE__ */ jsx38(Text, { style: { fontSize: 10, lineHeight: 14, marginLeft: theme.spacing.sm, color: withAlpha(theme.colors.textMuted, 0.6) }, children: headerTimeAgo }) : null
4789
+ headerTimeAgo ? /* @__PURE__ */ jsx40(Text, { style: { fontSize: 10, lineHeight: 14, marginLeft: theme.spacing.sm, color: withAlpha(theme.colors.textMuted, 0.6) }, children: headerTimeAgo }) : null
4654
4790
  ] }),
4655
- /* @__PURE__ */ jsx38(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, numberOfLines: 1, children: mergeRequest.title ?? "Untitled merge request" })
4791
+ /* @__PURE__ */ jsx40(Text, { style: { fontSize: 12, lineHeight: 16, color: theme.colors.textMuted }, numberOfLines: 1, children: mergeRequest.title ?? "Untitled merge request" })
4656
4792
  ] }),
4657
- headerRight ? /* @__PURE__ */ jsx38(View28, { children: headerRight }) : /* @__PURE__ */ jsx38(
4793
+ headerRight ? /* @__PURE__ */ jsx40(View28, { children: headerRight }) : /* @__PURE__ */ jsx40(
4658
4794
  Animated7.View,
4659
4795
  {
4660
4796
  style: {
@@ -4664,12 +4800,12 @@ function MergeRequestStatusCard({
4664
4800
  }
4665
4801
  ]
4666
4802
  },
4667
- children: /* @__PURE__ */ jsx38(ChevronDown2, { size: 20, color: withAlpha(theme.colors.textMuted, 0.4) })
4803
+ children: /* @__PURE__ */ jsx40(ChevronDown2, { size: 20, color: withAlpha(theme.colors.textMuted, 0.4) })
4668
4804
  }
4669
4805
  )
4670
4806
  ] }),
4671
4807
  expanded ? /* @__PURE__ */ jsxs22(View28, { style: { marginTop: 16, marginLeft: 56 }, children: [
4672
- /* @__PURE__ */ jsx38(
4808
+ /* @__PURE__ */ jsx40(
4673
4809
  Text,
4674
4810
  {
4675
4811
  style: {
@@ -4683,7 +4819,7 @@ function MergeRequestStatusCard({
4683
4819
  children: status.text
4684
4820
  }
4685
4821
  ),
4686
- createdTimeAgo ? /* @__PURE__ */ jsx38(
4822
+ createdTimeAgo ? /* @__PURE__ */ jsx40(
4687
4823
  Text,
4688
4824
  {
4689
4825
  style: {
@@ -4694,8 +4830,8 @@ function MergeRequestStatusCard({
4694
4830
  children: createdTimeAgo
4695
4831
  }
4696
4832
  ) : null,
4697
- /* @__PURE__ */ jsx38(Text, { style: { fontSize: 16, fontWeight: "600", color: textColor, marginBottom: 8 }, children: mergeRequest.title ?? "Untitled merge request" }),
4698
- mergeRequest.description ? /* @__PURE__ */ jsx38(MarkdownText, { markdown: mergeRequest.description, variant: "mergeRequest" }) : null
4833
+ /* @__PURE__ */ jsx40(Text, { style: { fontSize: 16, fontWeight: "600", color: textColor, marginBottom: 8 }, children: mergeRequest.title ?? "Untitled merge request" }),
4834
+ mergeRequest.description ? /* @__PURE__ */ jsx40(MarkdownText, { markdown: mergeRequest.description, variant: "mergeRequest" }) : null
4699
4835
  ] }) : null
4700
4836
  ]
4701
4837
  }
@@ -4703,18 +4839,18 @@ function MergeRequestStatusCard({
4703
4839
  }
4704
4840
 
4705
4841
  // src/components/merge-requests/ReviewMergeRequestCarousel.tsx
4706
- import * as React28 from "react";
4842
+ import * as React30 from "react";
4707
4843
  import { Animated as Animated9, FlatList, View as View31, useWindowDimensions as useWindowDimensions3 } from "react-native";
4708
4844
 
4709
4845
  // src/components/merge-requests/ReviewMergeRequestCard.tsx
4710
- import * as React27 from "react";
4846
+ import * as React29 from "react";
4711
4847
  import { ActivityIndicator as ActivityIndicator5, Animated as Animated8, Pressable as Pressable11, View as View30 } from "react-native";
4712
4848
  import { Check as Check4, ChevronDown as ChevronDown3, Play as Play3, X as X3 } from "lucide-react-native";
4713
4849
 
4714
4850
  // src/components/merge-requests/ReviewMergeRequestActionButton.tsx
4715
- import * as React26 from "react";
4851
+ import * as React28 from "react";
4716
4852
  import { Pressable as Pressable10, View as View29 } from "react-native";
4717
- import { jsx as jsx39 } from "react/jsx-runtime";
4853
+ import { jsx as jsx41 } from "react/jsx-runtime";
4718
4854
  function ReviewMergeRequestActionButton({
4719
4855
  accessibilityLabel,
4720
4856
  backgroundColor,
@@ -4723,13 +4859,13 @@ function ReviewMergeRequestActionButton({
4723
4859
  children,
4724
4860
  iconOnly
4725
4861
  }) {
4726
- const [pressed, setPressed] = React26.useState(false);
4862
+ const [pressed, setPressed] = React28.useState(false);
4727
4863
  const height = iconOnly ? 36 : 40;
4728
4864
  const width = iconOnly ? 36 : void 0;
4729
4865
  const paddingHorizontal = iconOnly ? 0 : 16;
4730
4866
  const paddingVertical = iconOnly ? 0 : 8;
4731
4867
  const opacity = disabled ? 0.5 : pressed ? 0.9 : 1;
4732
- return /* @__PURE__ */ jsx39(
4868
+ return /* @__PURE__ */ jsx41(
4733
4869
  View29,
4734
4870
  {
4735
4871
  style: {
@@ -4744,7 +4880,7 @@ function ReviewMergeRequestActionButton({
4744
4880
  paddingVertical,
4745
4881
  justifyContent: "center"
4746
4882
  },
4747
- children: /* @__PURE__ */ jsx39(
4883
+ children: /* @__PURE__ */ jsx41(
4748
4884
  Pressable10,
4749
4885
  {
4750
4886
  accessibilityRole: "button",
@@ -4768,7 +4904,7 @@ function ReviewMergeRequestActionButton({
4768
4904
  }
4769
4905
 
4770
4906
  // src/components/merge-requests/ReviewMergeRequestCard.tsx
4771
- import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
4907
+ import { jsx as jsx42, jsxs as jsxs23 } from "react/jsx-runtime";
4772
4908
  function ReviewMergeRequestCard({
4773
4909
  mr,
4774
4910
  index,
@@ -4785,14 +4921,14 @@ function ReviewMergeRequestCard({
4785
4921
  onTest
4786
4922
  }) {
4787
4923
  const theme = useTheme();
4788
- const status = React27.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
4924
+ const status = React29.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
4789
4925
  const canAct = mr.status === "open";
4790
- const rotate = React27.useRef(new Animated8.Value(isExpanded ? 1 : 0)).current;
4791
- React27.useEffect(() => {
4926
+ const rotate = React29.useRef(new Animated8.Value(isExpanded ? 1 : 0)).current;
4927
+ React29.useEffect(() => {
4792
4928
  Animated8.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
4793
4929
  }, [isExpanded, rotate]);
4794
4930
  const position = total > 1 ? `${index + 1}/${total}` : "Merge request";
4795
- return /* @__PURE__ */ jsx40(Pressable11, { onPress: onToggle, style: ({ pressed }) => ({ opacity: pressed ? 0.95 : 1 }), children: /* @__PURE__ */ jsxs23(
4931
+ return /* @__PURE__ */ jsx42(Pressable11, { onPress: onToggle, style: ({ pressed }) => ({ opacity: pressed ? 0.95 : 1 }), children: /* @__PURE__ */ jsxs23(
4796
4932
  Card,
4797
4933
  {
4798
4934
  padded: false,
@@ -4806,9 +4942,9 @@ function ReviewMergeRequestCard({
4806
4942
  ],
4807
4943
  children: [
4808
4944
  /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
4809
- /* @__PURE__ */ jsx40(Avatar, { size: 40, uri: (creator == null ? void 0 : creator.avatar) ?? null, name: (creator == null ? void 0 : creator.name) ?? void 0 }),
4945
+ /* @__PURE__ */ jsx42(Avatar, { size: 40, uri: (creator == null ? void 0 : creator.avatar) ?? null, name: (creator == null ? void 0 : creator.name) ?? void 0 }),
4810
4946
  /* @__PURE__ */ jsxs23(View30, { style: { flex: 1, minWidth: 0 }, children: [
4811
- /* @__PURE__ */ jsx40(
4947
+ /* @__PURE__ */ jsx42(
4812
4948
  Text,
4813
4949
  {
4814
4950
  style: { fontWeight: theme.typography.fontWeight.semibold, color: theme.colors.text, fontSize: 16, lineHeight: 20 },
@@ -4822,18 +4958,18 @@ function ReviewMergeRequestCard({
4822
4958
  position
4823
4959
  ] })
4824
4960
  ] }),
4825
- /* @__PURE__ */ jsx40(
4961
+ /* @__PURE__ */ jsx42(
4826
4962
  Animated8.View,
4827
4963
  {
4828
4964
  style: {
4829
4965
  transform: [{ rotate: rotate.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "180deg"] }) }]
4830
4966
  },
4831
- children: /* @__PURE__ */ jsx40(ChevronDown3, { size: 20, color: withAlpha(theme.colors.textMuted, 0.4) })
4967
+ children: /* @__PURE__ */ jsx42(ChevronDown3, { size: 20, color: withAlpha(theme.colors.textMuted, 0.4) })
4832
4968
  }
4833
4969
  )
4834
4970
  ] }),
4835
4971
  isExpanded ? /* @__PURE__ */ jsxs23(View30, { style: { marginTop: 16 }, children: [
4836
- /* @__PURE__ */ jsx40(
4972
+ /* @__PURE__ */ jsx42(
4837
4973
  Text,
4838
4974
  {
4839
4975
  style: {
@@ -4847,13 +4983,13 @@ function ReviewMergeRequestCard({
4847
4983
  children: status.text
4848
4984
  }
4849
4985
  ),
4850
- /* @__PURE__ */ jsx40(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginBottom: 12 }, children: creator ? `${creator.approvedOpenedMergeRequests} approved merge${creator.approvedOpenedMergeRequests !== 1 ? "s" : ""}` : "Loading stats..." }),
4851
- mr.description ? /* @__PURE__ */ jsx40(MarkdownText, { markdown: mr.description, variant: "mergeRequest" }) : null
4986
+ /* @__PURE__ */ jsx42(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginBottom: 12 }, children: creator ? `${creator.approvedOpenedMergeRequests} approved merge${creator.approvedOpenedMergeRequests !== 1 ? "s" : ""}` : "Loading stats..." }),
4987
+ mr.description ? /* @__PURE__ */ jsx42(MarkdownText, { markdown: mr.description, variant: "mergeRequest" }) : null
4852
4988
  ] }) : null,
4853
- /* @__PURE__ */ jsx40(View30, { style: { height: 1, backgroundColor: withAlpha(theme.colors.borderStrong, 0.5), marginTop: 12, marginBottom: 12 } }),
4989
+ /* @__PURE__ */ jsx42(View30, { style: { height: 1, backgroundColor: withAlpha(theme.colors.borderStrong, 0.5), marginTop: 12, marginBottom: 12 } }),
4854
4990
  /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, children: [
4855
4991
  /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", gap: 8 }, children: [
4856
- /* @__PURE__ */ jsx40(
4992
+ /* @__PURE__ */ jsx42(
4857
4993
  ReviewMergeRequestActionButton,
4858
4994
  {
4859
4995
  accessibilityLabel: "Reject",
@@ -4862,12 +4998,12 @@ function ReviewMergeRequestCard({
4862
4998
  onPress: onReject,
4863
4999
  iconOnly: !isExpanded,
4864
5000
  children: /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4865
- /* @__PURE__ */ jsx40(X3, { size: 18, color: "#FFFFFF" }),
4866
- isExpanded ? /* @__PURE__ */ jsx40(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Reject" }) : null
5001
+ /* @__PURE__ */ jsx42(X3, { size: 18, color: "#FFFFFF" }),
5002
+ isExpanded ? /* @__PURE__ */ jsx42(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Reject" }) : null
4867
5003
  ] })
4868
5004
  }
4869
5005
  ),
4870
- /* @__PURE__ */ jsx40(
5006
+ /* @__PURE__ */ jsx42(
4871
5007
  ReviewMergeRequestActionButton,
4872
5008
  {
4873
5009
  accessibilityLabel: !canAct ? "Not actionable" : isProcessing ? "Processing" : "Approve",
@@ -4876,16 +5012,16 @@ function ReviewMergeRequestCard({
4876
5012
  onPress: onApprove,
4877
5013
  iconOnly: !isExpanded,
4878
5014
  children: isProcessing ? /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4879
- /* @__PURE__ */ jsx40(ActivityIndicator5, { size: "small", color: "#FFFFFF" }),
4880
- isExpanded ? /* @__PURE__ */ jsx40(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Processing" }) : null
5015
+ /* @__PURE__ */ jsx42(ActivityIndicator5, { size: "small", color: "#FFFFFF" }),
5016
+ isExpanded ? /* @__PURE__ */ jsx42(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Processing" }) : null
4881
5017
  ] }) : /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4882
- /* @__PURE__ */ jsx40(Check4, { size: 18, color: "#FFFFFF" }),
4883
- isExpanded ? /* @__PURE__ */ jsx40(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Approve" }) : null
5018
+ /* @__PURE__ */ jsx42(Check4, { size: 18, color: "#FFFFFF" }),
5019
+ isExpanded ? /* @__PURE__ */ jsx42(Text, { style: { fontSize: 13, color: "#FFFFFF", fontWeight: theme.typography.fontWeight.semibold }, children: "Approve" }) : null
4884
5020
  ] })
4885
5021
  }
4886
5022
  )
4887
5023
  ] }),
4888
- /* @__PURE__ */ jsx40(
5024
+ /* @__PURE__ */ jsx42(
4889
5025
  ReviewMergeRequestActionButton,
4890
5026
  {
4891
5027
  accessibilityLabel: "Test",
@@ -4893,9 +5029,9 @@ function ReviewMergeRequestCard({
4893
5029
  disabled: isBuilding || isTestingThis,
4894
5030
  onPress: onTest,
4895
5031
  iconOnly: !isExpanded,
4896
- children: isTestingThis ? /* @__PURE__ */ jsx40(ActivityIndicator5, { size: "small", color: "#888" }) : /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
4897
- /* @__PURE__ */ jsx40(Play3, { size: 14, color: theme.colors.text }),
4898
- isExpanded ? /* @__PURE__ */ jsx40(Text, { style: { fontSize: 13, color: theme.colors.text, fontWeight: theme.typography.fontWeight.semibold }, children: "Test" }) : null
5032
+ children: isTestingThis ? /* @__PURE__ */ jsx42(ActivityIndicator5, { size: "small", color: "#888" }) : /* @__PURE__ */ jsxs23(View30, { style: { flexDirection: "row", alignItems: "center", gap: isExpanded ? 4 : 0 }, children: [
5033
+ /* @__PURE__ */ jsx42(Play3, { size: 14, color: theme.colors.text }),
5034
+ isExpanded ? /* @__PURE__ */ jsx42(Text, { style: { fontSize: 13, color: theme.colors.text, fontWeight: theme.typography.fontWeight.semibold }, children: "Test" }) : null
4899
5035
  ] })
4900
5036
  }
4901
5037
  )
@@ -4906,7 +5042,7 @@ function ReviewMergeRequestCard({
4906
5042
  }
4907
5043
 
4908
5044
  // src/components/merge-requests/ReviewMergeRequestCarousel.tsx
4909
- import { jsx as jsx41, jsxs as jsxs24 } from "react/jsx-runtime";
5045
+ import { jsx as jsx43, jsxs as jsxs24 } from "react/jsx-runtime";
4910
5046
  function ReviewMergeRequestCarousel({
4911
5047
  mergeRequests,
4912
5048
  creatorStatsById,
@@ -4920,16 +5056,16 @@ function ReviewMergeRequestCarousel({
4920
5056
  }) {
4921
5057
  const theme = useTheme();
4922
5058
  const { width } = useWindowDimensions3();
4923
- const [expanded, setExpanded] = React28.useState({});
4924
- const carouselScrollX = React28.useRef(new Animated9.Value(0)).current;
5059
+ const [expanded, setExpanded] = React30.useState({});
5060
+ const carouselScrollX = React30.useRef(new Animated9.Value(0)).current;
4925
5061
  const peekAmount = 24;
4926
5062
  const gap = 16;
4927
- const cardWidth = React28.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
5063
+ const cardWidth = React30.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
4928
5064
  const snapInterval = cardWidth + gap;
4929
5065
  const dotColor = theme.scheme === "dark" ? "#FFFFFF" : "#000000";
4930
5066
  if (mergeRequests.length === 0) return null;
4931
5067
  return /* @__PURE__ */ jsxs24(View31, { style: [{ marginHorizontal: -theme.spacing.lg }, style], children: [
4932
- /* @__PURE__ */ jsx41(
5068
+ /* @__PURE__ */ jsx43(
4933
5069
  FlatList,
4934
5070
  {
4935
5071
  horizontal: true,
@@ -4937,13 +5073,13 @@ function ReviewMergeRequestCarousel({
4937
5073
  keyExtractor: (mr) => mr.id,
4938
5074
  showsHorizontalScrollIndicator: false,
4939
5075
  contentContainerStyle: { paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.sm },
4940
- ItemSeparatorComponent: () => /* @__PURE__ */ jsx41(View31, { style: { width: gap } }),
5076
+ ItemSeparatorComponent: () => /* @__PURE__ */ jsx43(View31, { style: { width: gap } }),
4941
5077
  snapToAlignment: "start",
4942
5078
  decelerationRate: "fast",
4943
5079
  snapToInterval: snapInterval,
4944
5080
  disableIntervalMomentum: true,
4945
5081
  style: { paddingRight: peekAmount },
4946
- ListFooterComponent: /* @__PURE__ */ jsx41(View31, { style: { width: peekAmount } }),
5082
+ ListFooterComponent: /* @__PURE__ */ jsx43(View31, { style: { width: peekAmount } }),
4947
5083
  onScroll: Animated9.event([{ nativeEvent: { contentOffset: { x: carouselScrollX } } }], {
4948
5084
  useNativeDriver: false
4949
5085
  }),
@@ -4955,7 +5091,7 @@ function ReviewMergeRequestCarousel({
4955
5091
  const isProcessing = Boolean(processingMrId && processingMrId === item.id);
4956
5092
  const isAnyProcessing = Boolean(processingMrId);
4957
5093
  const isTestingThis = Boolean(testingMrId && testingMrId === item.id);
4958
- return /* @__PURE__ */ jsx41(View31, { style: { width: cardWidth }, children: /* @__PURE__ */ jsx41(
5094
+ return /* @__PURE__ */ jsx43(View31, { style: { width: cardWidth }, children: /* @__PURE__ */ jsx43(
4959
5095
  ReviewMergeRequestCard,
4960
5096
  {
4961
5097
  mr: item,
@@ -4976,7 +5112,7 @@ function ReviewMergeRequestCarousel({
4976
5112
  }
4977
5113
  }
4978
5114
  ),
4979
- mergeRequests.length >= 1 ? /* @__PURE__ */ jsx41(View31, { style: { flexDirection: "row", justifyContent: "center", columnGap: 8, marginTop: theme.spacing.md }, children: mergeRequests.map((mr, index) => {
5115
+ mergeRequests.length >= 1 ? /* @__PURE__ */ jsx43(View31, { style: { flexDirection: "row", justifyContent: "center", columnGap: 8, marginTop: theme.spacing.md }, children: mergeRequests.map((mr, index) => {
4980
5116
  const inputRange = [(index - 1) * snapInterval, index * snapInterval, (index + 1) * snapInterval];
4981
5117
  const scale = carouselScrollX.interpolate({
4982
5118
  inputRange,
@@ -4988,7 +5124,7 @@ function ReviewMergeRequestCarousel({
4988
5124
  outputRange: [0.4, 1, 0.4],
4989
5125
  extrapolate: "clamp"
4990
5126
  });
4991
- return /* @__PURE__ */ jsx41(
5127
+ return /* @__PURE__ */ jsx43(
4992
5128
  Animated9.View,
4993
5129
  {
4994
5130
  style: {
@@ -5007,7 +5143,7 @@ function ReviewMergeRequestCarousel({
5007
5143
  }
5008
5144
 
5009
5145
  // src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
5010
- import { Fragment as Fragment5, jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
5146
+ import { Fragment as Fragment5, jsx as jsx44, jsxs as jsxs25 } from "react/jsx-runtime";
5011
5147
  function PreviewCollaborateSection({
5012
5148
  canSubmitMergeRequest,
5013
5149
  incomingMergeRequests,
@@ -5023,13 +5159,13 @@ function PreviewCollaborateSection({
5023
5159
  onTestMr
5024
5160
  }) {
5025
5161
  const theme = useTheme();
5026
- const [submittingMr, setSubmittingMr] = React29.useState(false);
5162
+ const [submittingMr, setSubmittingMr] = React31.useState(false);
5027
5163
  const hasSection = canSubmitMergeRequest || incomingMergeRequests.length > 0 || outgoingMergeRequests.length > 0;
5028
5164
  if (!hasSection) return null;
5029
5165
  const showActionsSubtitle = canSubmitMergeRequest && onSubmitMergeRequest || onTestMr && incomingMergeRequests.length > 0;
5030
5166
  return /* @__PURE__ */ jsxs25(Fragment5, { children: [
5031
- /* @__PURE__ */ jsx42(SectionTitle, { marginTop: theme.spacing.xl, children: "Collaborate" }),
5032
- showActionsSubtitle ? /* @__PURE__ */ jsx42(
5167
+ /* @__PURE__ */ jsx44(SectionTitle, { marginTop: theme.spacing.xl, children: "Collaborate" }),
5168
+ showActionsSubtitle ? /* @__PURE__ */ jsx44(
5033
5169
  Text,
5034
5170
  {
5035
5171
  style: {
@@ -5044,7 +5180,7 @@ function PreviewCollaborateSection({
5044
5180
  children: "Actions"
5045
5181
  }
5046
5182
  ) : null,
5047
- canSubmitMergeRequest && onSubmitMergeRequest ? /* @__PURE__ */ jsx42(
5183
+ canSubmitMergeRequest && onSubmitMergeRequest ? /* @__PURE__ */ jsx44(
5048
5184
  PressableCardRow,
5049
5185
  {
5050
5186
  accessibilityLabel: "Submit merge request",
@@ -5075,7 +5211,7 @@ function PreviewCollaborateSection({
5075
5211
  borderColor: withAlpha("#03DAC6", 0.2),
5076
5212
  marginBottom: theme.spacing.sm
5077
5213
  },
5078
- left: /* @__PURE__ */ jsx42(
5214
+ left: /* @__PURE__ */ jsx44(
5079
5215
  View32,
5080
5216
  {
5081
5217
  style: {
@@ -5087,15 +5223,15 @@ function PreviewCollaborateSection({
5087
5223
  backgroundColor: withAlpha("#03DAC6", 0.1),
5088
5224
  marginRight: theme.spacing.lg
5089
5225
  },
5090
- children: submittingMr ? /* @__PURE__ */ jsx42(ActivityIndicator6, { color: "#03DAC6", size: "small" }) : /* @__PURE__ */ jsx42(MergeIcon, { width: 20, height: 20, color: "#03DAC6" })
5226
+ children: submittingMr ? /* @__PURE__ */ jsx44(ActivityIndicator6, { color: "#03DAC6", size: "small" }) : /* @__PURE__ */ jsx44(MergeIcon, { width: 20, height: 20, color: "#03DAC6" })
5091
5227
  }
5092
5228
  ),
5093
- title: /* @__PURE__ */ jsx42(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: "Submit your new changes" }),
5094
- subtitle: /* @__PURE__ */ jsx42(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: "Ask to merge this remix to the original app" }),
5095
- right: /* @__PURE__ */ jsx42(Send2, { size: 16, color: "#03DAC6" })
5229
+ title: /* @__PURE__ */ jsx44(Text, { style: { color: theme.colors.text, fontSize: 16, lineHeight: 20, fontWeight: theme.typography.fontWeight.semibold }, children: "Submit your new changes" }),
5230
+ subtitle: /* @__PURE__ */ jsx44(Text, { style: { color: theme.colors.textMuted, fontSize: 12, lineHeight: 16, marginTop: 2 }, children: "Ask to merge this remix to the original app" }),
5231
+ right: /* @__PURE__ */ jsx44(Send2, { size: 16, color: "#03DAC6" })
5096
5232
  }
5097
5233
  ) : null,
5098
- onTestMr && incomingMergeRequests.length > 0 ? /* @__PURE__ */ jsx42(
5234
+ onTestMr && incomingMergeRequests.length > 0 ? /* @__PURE__ */ jsx44(
5099
5235
  ReviewMergeRequestCarousel,
5100
5236
  {
5101
5237
  mergeRequests: incomingMergeRequests,
@@ -5109,7 +5245,7 @@ function PreviewCollaborateSection({
5109
5245
  }
5110
5246
  ) : null,
5111
5247
  outgoingMergeRequests.length > 0 ? /* @__PURE__ */ jsxs25(Fragment5, { children: [
5112
- /* @__PURE__ */ jsx42(
5248
+ /* @__PURE__ */ jsx44(
5113
5249
  Text,
5114
5250
  {
5115
5251
  style: {
@@ -5125,13 +5261,13 @@ function PreviewCollaborateSection({
5125
5261
  children: "History"
5126
5262
  }
5127
5263
  ),
5128
- outgoingMergeRequests.map((mr) => /* @__PURE__ */ jsx42(View32, { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsx42(MergeRequestStatusCard, { mergeRequest: toMergeRequestSummary(mr) }) }, mr.id))
5264
+ outgoingMergeRequests.map((mr) => /* @__PURE__ */ jsx44(View32, { style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ jsx44(MergeRequestStatusCard, { mergeRequest: toMergeRequestSummary(mr) }) }, mr.id))
5129
5265
  ] }) : null
5130
5266
  ] });
5131
5267
  }
5132
5268
 
5133
5269
  // src/studio/ui/preview-panel/usePreviewPanelData.ts
5134
- import * as React31 from "react";
5270
+ import * as React33 from "react";
5135
5271
 
5136
5272
  // src/data/apps/images/remote.ts
5137
5273
  var AppImagesRemoteDataSourceImpl = class extends BaseRemote {
@@ -5182,7 +5318,7 @@ var AppImagesRepositoryImpl = class extends BaseRepository {
5182
5318
  var appImagesRepository = new AppImagesRepositoryImpl(appImagesRemoteDataSource);
5183
5319
 
5184
5320
  // src/studio/hooks/useAppStats.ts
5185
- import * as React30 from "react";
5321
+ import * as React32 from "react";
5186
5322
  import * as Haptics2 from "expo-haptics";
5187
5323
 
5188
5324
  // src/data/likes/remote.ts
@@ -5251,34 +5387,34 @@ function useAppStats({
5251
5387
  initialIsLiked = false,
5252
5388
  onOpenComments
5253
5389
  }) {
5254
- const [likeCount, setLikeCount] = React30.useState(initialLikes);
5255
- const [commentCount, setCommentCount] = React30.useState(initialComments);
5256
- const [forkCount, setForkCount] = React30.useState(initialForks);
5257
- const [isLiked, setIsLiked] = React30.useState(initialIsLiked);
5258
- const didMutateRef = React30.useRef(false);
5259
- const lastAppIdRef = React30.useRef("");
5260
- React30.useEffect(() => {
5390
+ const [likeCount, setLikeCount] = React32.useState(initialLikes);
5391
+ const [commentCount, setCommentCount] = React32.useState(initialComments);
5392
+ const [forkCount, setForkCount] = React32.useState(initialForks);
5393
+ const [isLiked, setIsLiked] = React32.useState(initialIsLiked);
5394
+ const didMutateRef = React32.useRef(false);
5395
+ const lastAppIdRef = React32.useRef("");
5396
+ React32.useEffect(() => {
5261
5397
  if (lastAppIdRef.current === appId) return;
5262
5398
  lastAppIdRef.current = appId;
5263
5399
  didMutateRef.current = false;
5264
5400
  }, [appId]);
5265
- React30.useEffect(() => {
5401
+ React32.useEffect(() => {
5266
5402
  if (didMutateRef.current) return;
5267
5403
  setLikeCount(initialLikes);
5268
5404
  }, [appId, initialLikes]);
5269
- React30.useEffect(() => {
5405
+ React32.useEffect(() => {
5270
5406
  if (didMutateRef.current) return;
5271
5407
  setCommentCount(initialComments);
5272
5408
  }, [appId, initialComments]);
5273
- React30.useEffect(() => {
5409
+ React32.useEffect(() => {
5274
5410
  if (didMutateRef.current) return;
5275
5411
  setForkCount(initialForks);
5276
5412
  }, [appId, initialForks]);
5277
- React30.useEffect(() => {
5413
+ React32.useEffect(() => {
5278
5414
  if (didMutateRef.current) return;
5279
5415
  setIsLiked(initialIsLiked);
5280
5416
  }, [appId, initialIsLiked]);
5281
- const handleLike = React30.useCallback(async () => {
5417
+ const handleLike = React32.useCallback(async () => {
5282
5418
  var _a, _b;
5283
5419
  if (!appId) return;
5284
5420
  didMutateRef.current = true;
@@ -5302,7 +5438,7 @@ function useAppStats({
5302
5438
  setLikeCount((prev) => Math.max(0, prev + (newIsLiked ? -1 : 1)));
5303
5439
  }
5304
5440
  }, [appId, isLiked, likeCount]);
5305
- const handleOpenComments = React30.useCallback(() => {
5441
+ const handleOpenComments = React32.useCallback(() => {
5306
5442
  if (!appId) return;
5307
5443
  try {
5308
5444
  void Haptics2.impactAsync(Haptics2.ImpactFeedbackStyle.Light);
@@ -5317,11 +5453,11 @@ function useAppStats({
5317
5453
  var LIKE_DEBUG_PREFIX = "[COMERGE_LIKE_DEBUG]";
5318
5454
  function usePreviewPanelData(params) {
5319
5455
  const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
5320
- const [imageUrl, setImageUrl] = React31.useState(null);
5321
- const [imageLoaded, setImageLoaded] = React31.useState(false);
5322
- const [insights, setInsights] = React31.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
5323
- const [creator, setCreator] = React31.useState(null);
5324
- React31.useEffect(() => {
5456
+ const [imageUrl, setImageUrl] = React33.useState(null);
5457
+ const [imageLoaded, setImageLoaded] = React33.useState(false);
5458
+ const [insights, setInsights] = React33.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
5459
+ const [creator, setCreator] = React33.useState(null);
5460
+ React33.useEffect(() => {
5325
5461
  if (!(app == null ? void 0 : app.id)) return;
5326
5462
  let cancelled = false;
5327
5463
  (async () => {
@@ -5336,7 +5472,7 @@ function usePreviewPanelData(params) {
5336
5472
  cancelled = true;
5337
5473
  };
5338
5474
  }, [app == null ? void 0 : app.id]);
5339
- React31.useEffect(() => {
5475
+ React33.useEffect(() => {
5340
5476
  if (!(app == null ? void 0 : app.createdBy)) return;
5341
5477
  let cancelled = false;
5342
5478
  (async () => {
@@ -5352,10 +5488,10 @@ function usePreviewPanelData(params) {
5352
5488
  cancelled = true;
5353
5489
  };
5354
5490
  }, [app == null ? void 0 : app.createdBy]);
5355
- React31.useEffect(() => {
5491
+ React33.useEffect(() => {
5356
5492
  setImageLoaded(false);
5357
5493
  }, [app == null ? void 0 : app.id]);
5358
- React31.useEffect(() => {
5494
+ React33.useEffect(() => {
5359
5495
  if (!(app == null ? void 0 : app.id)) return;
5360
5496
  let cancelled = false;
5361
5497
  (async () => {
@@ -5380,7 +5516,7 @@ function usePreviewPanelData(params) {
5380
5516
  cancelled = true;
5381
5517
  };
5382
5518
  }, [app == null ? void 0 : app.id]);
5383
- React31.useEffect(() => {
5519
+ React33.useEffect(() => {
5384
5520
  if (!(app == null ? void 0 : app.id)) return;
5385
5521
  log.debug(
5386
5522
  `${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
@@ -5394,7 +5530,7 @@ function usePreviewPanelData(params) {
5394
5530
  initialIsLiked: Boolean(app == null ? void 0 : app.isLiked),
5395
5531
  onOpenComments
5396
5532
  });
5397
- const canSubmitMergeRequest = React31.useMemo(() => {
5533
+ const canSubmitMergeRequest = React33.useMemo(() => {
5398
5534
  if (!isOwner) return false;
5399
5535
  if (!app) return false;
5400
5536
  if (!app.forkedFromAppId) return false;
@@ -5416,7 +5552,7 @@ function usePreviewPanelData(params) {
5416
5552
  }
5417
5553
 
5418
5554
  // src/studio/ui/PreviewPanel.tsx
5419
- import { jsx as jsx43, jsxs as jsxs26 } from "react/jsx-runtime";
5555
+ import { jsx as jsx45, jsxs as jsxs26 } from "react/jsx-runtime";
5420
5556
  function PreviewPanel({
5421
5557
  app,
5422
5558
  loading,
@@ -5447,16 +5583,16 @@ function PreviewPanel({
5447
5583
  onOpenComments,
5448
5584
  commentCountOverride
5449
5585
  });
5450
- const header = /* @__PURE__ */ jsx43(PreviewPanelHeader, { isOwner, onClose, onNavigateHome, onGoToChat });
5586
+ const header = /* @__PURE__ */ jsx45(PreviewPanelHeader, { isOwner, onClose, onNavigateHome, onGoToChat });
5451
5587
  if (loading || !app) {
5452
- return /* @__PURE__ */ jsx43(PreviewPage, { header, children: /* @__PURE__ */ jsxs26(View33, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: [
5453
- /* @__PURE__ */ jsx43(ActivityIndicator7, {}),
5454
- /* @__PURE__ */ jsx43(View33, { style: { height: 12 } }),
5455
- /* @__PURE__ */ jsx43(Text, { variant: "bodyMuted", children: "Loading app\u2026" })
5588
+ return /* @__PURE__ */ jsx45(PreviewPage, { header, children: /* @__PURE__ */ jsxs26(View33, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: [
5589
+ /* @__PURE__ */ jsx45(ActivityIndicator7, {}),
5590
+ /* @__PURE__ */ jsx45(View33, { style: { height: 12 } }),
5591
+ /* @__PURE__ */ jsx45(Text, { variant: "bodyMuted", children: "Loading app\u2026" })
5456
5592
  ] }) });
5457
5593
  }
5458
5594
  return /* @__PURE__ */ jsxs26(PreviewPage, { header, children: [
5459
- /* @__PURE__ */ jsx43(
5595
+ /* @__PURE__ */ jsx45(
5460
5596
  PreviewHeroSection,
5461
5597
  {
5462
5598
  appStatus: app.status,
@@ -5474,8 +5610,8 @@ function PreviewPanel({
5474
5610
  }
5475
5611
  }
5476
5612
  ),
5477
- /* @__PURE__ */ jsx43(PreviewMetaSection, { app, isOwner, creator, downloadsCount: insights.downloads }),
5478
- /* @__PURE__ */ jsx43(
5613
+ /* @__PURE__ */ jsx45(PreviewMetaSection, { app, isOwner, creator, downloadsCount: insights.downloads }),
5614
+ /* @__PURE__ */ jsx45(
5479
5615
  PreviewCustomizeSection,
5480
5616
  {
5481
5617
  app,
@@ -5486,7 +5622,7 @@ function PreviewPanel({
5486
5622
  onStartDraw
5487
5623
  }
5488
5624
  ),
5489
- /* @__PURE__ */ jsx43(
5625
+ /* @__PURE__ */ jsx45(
5490
5626
  PreviewCollaborateSection,
5491
5627
  {
5492
5628
  canSubmitMergeRequest,
@@ -5507,23 +5643,23 @@ function PreviewPanel({
5507
5643
  }
5508
5644
 
5509
5645
  // src/studio/ui/ChatPanel.tsx
5510
- import * as React36 from "react";
5646
+ import * as React38 from "react";
5511
5647
  import { ActivityIndicator as ActivityIndicator8, View as View41 } from "react-native";
5512
5648
 
5513
5649
  // src/components/chat/ChatPage.tsx
5514
- import * as React34 from "react";
5515
- import { Keyboard as Keyboard4, Platform as Platform7, View as View37 } from "react-native";
5650
+ import * as React36 from "react";
5651
+ import { Keyboard as Keyboard4, Platform as Platform9, View as View37 } from "react-native";
5516
5652
  import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
5517
5653
 
5518
5654
  // src/components/chat/ChatMessageList.tsx
5519
- import * as React33 from "react";
5520
- import { Platform as Platform6, View as View36 } from "react-native";
5655
+ import * as React35 from "react";
5656
+ import { View as View36 } from "react-native";
5521
5657
  import { BottomSheetFlatList } from "@gorhom/bottom-sheet";
5522
5658
 
5523
5659
  // src/components/chat/ChatMessageBubble.tsx
5524
5660
  import { View as View34 } from "react-native";
5525
5661
  import { CheckCheck as CheckCheck2, GitMerge as GitMerge2 } from "lucide-react-native";
5526
- import { jsx as jsx44, jsxs as jsxs27 } from "react/jsx-runtime";
5662
+ import { jsx as jsx46, jsxs as jsxs27 } from "react/jsx-runtime";
5527
5663
  function ChatMessageBubble({ message, renderContent, style }) {
5528
5664
  var _a, _b;
5529
5665
  const theme = useTheme();
@@ -5537,7 +5673,7 @@ function ChatMessageBubble({ message, renderContent, style }) {
5537
5673
  const bubbleVariant = isHuman ? "surface" : "surfaceRaised";
5538
5674
  const cornerStyle = isHuman ? { borderTopRightRadius: 0 } : { borderTopLeftRadius: 0 };
5539
5675
  const bodyColor = metaStatus === "success" ? theme.colors.success : metaStatus === "error" ? theme.colors.danger : void 0;
5540
- return /* @__PURE__ */ jsx44(View34, { style: [align, style], children: /* @__PURE__ */ jsx44(
5676
+ return /* @__PURE__ */ jsx46(View34, { style: [align, style], children: /* @__PURE__ */ jsx46(
5541
5677
  Surface,
5542
5678
  {
5543
5679
  variant: bubbleVariant,
@@ -5553,26 +5689,26 @@ function ChatMessageBubble({ message, renderContent, style }) {
5553
5689
  cornerStyle
5554
5690
  ],
5555
5691
  children: /* @__PURE__ */ jsxs27(View34, { style: { flexDirection: "row", alignItems: "center" }, children: [
5556
- isMergeCompleted ? /* @__PURE__ */ jsx44(CheckCheck2, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
5557
- isMergeApproved ? /* @__PURE__ */ jsx44(GitMerge2, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
5558
- /* @__PURE__ */ jsx44(View34, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ jsx44(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
5692
+ isMergeCompleted ? /* @__PURE__ */ jsx46(CheckCheck2, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
5693
+ isMergeApproved ? /* @__PURE__ */ jsx46(GitMerge2, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
5694
+ /* @__PURE__ */ jsx46(View34, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ jsx46(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
5559
5695
  ] })
5560
5696
  }
5561
5697
  ) });
5562
5698
  }
5563
5699
 
5564
5700
  // src/components/chat/TypingIndicator.tsx
5565
- import * as React32 from "react";
5701
+ import * as React34 from "react";
5566
5702
  import { Animated as Animated10, View as View35 } from "react-native";
5567
- import { jsx as jsx45 } from "react/jsx-runtime";
5703
+ import { jsx as jsx47 } from "react/jsx-runtime";
5568
5704
  function TypingIndicator({ style }) {
5569
5705
  const theme = useTheme();
5570
5706
  const dotColor = theme.colors.textSubtle;
5571
- const anims = React32.useMemo(
5707
+ const anims = React34.useMemo(
5572
5708
  () => [new Animated10.Value(0.3), new Animated10.Value(0.3), new Animated10.Value(0.3)],
5573
5709
  []
5574
5710
  );
5575
- React32.useEffect(() => {
5711
+ React34.useEffect(() => {
5576
5712
  const loops = [];
5577
5713
  anims.forEach((a, idx) => {
5578
5714
  const seq = Animated10.sequence([
@@ -5587,7 +5723,7 @@ function TypingIndicator({ style }) {
5587
5723
  loops.forEach((l) => l.stop());
5588
5724
  };
5589
5725
  }, [anims]);
5590
- return /* @__PURE__ */ jsx45(View35, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ jsx45(
5726
+ return /* @__PURE__ */ jsx47(View35, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ jsx47(
5591
5727
  Animated10.View,
5592
5728
  {
5593
5729
  style: {
@@ -5605,8 +5741,8 @@ function TypingIndicator({ style }) {
5605
5741
  }
5606
5742
 
5607
5743
  // src/components/chat/ChatMessageList.tsx
5608
- import { jsx as jsx46, jsxs as jsxs28 } from "react/jsx-runtime";
5609
- var ChatMessageList = React33.forwardRef(
5744
+ import { jsx as jsx48, jsxs as jsxs28 } from "react/jsx-runtime";
5745
+ var ChatMessageList = React35.forwardRef(
5610
5746
  ({
5611
5747
  messages,
5612
5748
  showTypingIndicator = false,
@@ -5617,23 +5753,23 @@ var ChatMessageList = React33.forwardRef(
5617
5753
  nearBottomThreshold = 200
5618
5754
  }, ref) => {
5619
5755
  const theme = useTheme();
5620
- const listRef = React33.useRef(null);
5621
- const nearBottomRef = React33.useRef(true);
5622
- const initialScrollDoneRef = React33.useRef(false);
5623
- const lastMessageIdRef = React33.useRef(null);
5624
- const scrollToBottom = React33.useCallback((options) => {
5756
+ const listRef = React35.useRef(null);
5757
+ const nearBottomRef = React35.useRef(true);
5758
+ const initialScrollDoneRef = React35.useRef(false);
5759
+ const lastMessageIdRef = React35.useRef(null);
5760
+ const data = React35.useMemo(() => {
5761
+ return [...messages].reverse();
5762
+ }, [messages]);
5763
+ const scrollToBottom = React35.useCallback((options) => {
5625
5764
  var _a;
5626
5765
  const animated = (options == null ? void 0 : options.animated) ?? true;
5627
- (_a = listRef.current) == null ? void 0 : _a.scrollToEnd({ animated });
5766
+ (_a = listRef.current) == null ? void 0 : _a.scrollToOffset({ offset: 0, animated });
5628
5767
  }, []);
5629
- React33.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
5630
- const handleScroll = React33.useCallback(
5768
+ React35.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
5769
+ const handleScroll = React35.useCallback(
5631
5770
  (e) => {
5632
5771
  const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
5633
- const distanceFromBottom = Math.max(
5634
- contentSize.height - Math.max(bottomInset, 0) - (contentOffset.y + layoutMeasurement.height),
5635
- 0
5636
- );
5772
+ const distanceFromBottom = Math.max(contentOffset.y - Math.max(bottomInset, 0), 0);
5637
5773
  const isNear = distanceFromBottom <= nearBottomThreshold;
5638
5774
  if (nearBottomRef.current !== isNear) {
5639
5775
  nearBottomRef.current = isNear;
@@ -5642,16 +5778,7 @@ var ChatMessageList = React33.forwardRef(
5642
5778
  },
5643
5779
  [bottomInset, nearBottomThreshold, onNearBottomChange]
5644
5780
  );
5645
- React33.useEffect(() => {
5646
- var _a;
5647
- if (initialScrollDoneRef.current) return;
5648
- if (messages.length === 0) return;
5649
- initialScrollDoneRef.current = true;
5650
- lastMessageIdRef.current = ((_a = messages[messages.length - 1]) == null ? void 0 : _a.id) ?? null;
5651
- const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
5652
- return () => cancelAnimationFrame(id);
5653
- }, [messages, scrollToBottom]);
5654
- React33.useEffect(() => {
5781
+ React35.useEffect(() => {
5655
5782
  if (!initialScrollDoneRef.current) return;
5656
5783
  const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
5657
5784
  const prevLastId = lastMessageIdRef.current;
@@ -5661,42 +5788,44 @@ var ChatMessageList = React33.forwardRef(
5661
5788
  const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
5662
5789
  return () => cancelAnimationFrame(id);
5663
5790
  }, [messages, scrollToBottom]);
5664
- React33.useEffect(() => {
5791
+ React35.useEffect(() => {
5665
5792
  if (showTypingIndicator && nearBottomRef.current) {
5666
5793
  const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
5667
5794
  return () => cancelAnimationFrame(id);
5668
5795
  }
5669
5796
  return void 0;
5670
5797
  }, [showTypingIndicator, scrollToBottom]);
5671
- React33.useEffect(() => {
5672
- if (!initialScrollDoneRef.current) return;
5673
- if (!nearBottomRef.current) return;
5674
- const id = requestAnimationFrame(() => scrollToBottom({ animated: false }));
5675
- return () => cancelAnimationFrame(id);
5676
- }, [bottomInset, scrollToBottom]);
5677
- return /* @__PURE__ */ jsx46(
5798
+ return /* @__PURE__ */ jsx48(
5678
5799
  BottomSheetFlatList,
5679
5800
  {
5680
5801
  ref: listRef,
5681
- data: messages,
5802
+ inverted: true,
5803
+ data,
5682
5804
  keyExtractor: (m) => m.id,
5683
- keyboardDismissMode: Platform6.OS === "ios" ? "interactive" : "on-drag",
5684
5805
  keyboardShouldPersistTaps: "handled",
5685
5806
  onScroll: handleScroll,
5686
5807
  scrollEventThrottle: 16,
5687
5808
  showsVerticalScrollIndicator: false,
5809
+ onContentSizeChange: () => {
5810
+ if (initialScrollDoneRef.current) return;
5811
+ initialScrollDoneRef.current = true;
5812
+ lastMessageIdRef.current = messages.length > 0 ? messages[messages.length - 1].id : null;
5813
+ nearBottomRef.current = true;
5814
+ onNearBottomChange == null ? void 0 : onNearBottomChange(true);
5815
+ requestAnimationFrame(() => scrollToBottom({ animated: false }));
5816
+ },
5688
5817
  contentContainerStyle: [
5689
5818
  {
5690
5819
  paddingHorizontal: theme.spacing.lg,
5691
- paddingTop: theme.spacing.sm,
5692
- paddingBottom: theme.spacing.sm
5820
+ paddingVertical: theme.spacing.sm
5693
5821
  },
5694
5822
  contentStyle
5695
5823
  ],
5696
- renderItem: ({ item, index }) => /* @__PURE__ */ jsx46(View36, { style: { marginTop: index === 0 ? 0 : theme.spacing.sm }, children: /* @__PURE__ */ jsx46(ChatMessageBubble, { message: item, renderContent: renderMessageContent }) }),
5697
- ListFooterComponent: /* @__PURE__ */ jsxs28(View36, { children: [
5698
- showTypingIndicator ? /* @__PURE__ */ jsx46(View36, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ jsx46(TypingIndicator, {}) }) : null,
5699
- bottomInset > 0 ? /* @__PURE__ */ jsx46(View36, { style: { height: bottomInset } }) : null
5824
+ ItemSeparatorComponent: () => /* @__PURE__ */ jsx48(View36, { style: { height: theme.spacing.sm } }),
5825
+ renderItem: ({ item }) => /* @__PURE__ */ jsx48(ChatMessageBubble, { message: item, renderContent: renderMessageContent }),
5826
+ ListHeaderComponent: /* @__PURE__ */ jsxs28(View36, { children: [
5827
+ showTypingIndicator ? /* @__PURE__ */ jsx48(View36, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ jsx48(TypingIndicator, {}) }) : null,
5828
+ bottomInset > 0 ? /* @__PURE__ */ jsx48(View36, { style: { height: bottomInset } }) : null
5700
5829
  ] })
5701
5830
  }
5702
5831
  );
@@ -5705,7 +5834,7 @@ var ChatMessageList = React33.forwardRef(
5705
5834
  ChatMessageList.displayName = "ChatMessageList";
5706
5835
 
5707
5836
  // src/components/chat/ChatPage.tsx
5708
- import { jsx as jsx47, jsxs as jsxs29 } from "react/jsx-runtime";
5837
+ import { jsx as jsx49, jsxs as jsxs29 } from "react/jsx-runtime";
5709
5838
  function ChatPage({
5710
5839
  header,
5711
5840
  messages,
@@ -5715,15 +5844,16 @@ function ChatPage({
5715
5844
  composer,
5716
5845
  overlay,
5717
5846
  style,
5847
+ composerHorizontalPadding,
5718
5848
  onNearBottomChange,
5719
5849
  listRef
5720
5850
  }) {
5721
5851
  const theme = useTheme();
5722
5852
  const insets = useSafeAreaInsets4();
5723
- const [composerHeight, setComposerHeight] = React34.useState(0);
5724
- const [keyboardVisible, setKeyboardVisible] = React34.useState(false);
5725
- React34.useEffect(() => {
5726
- if (Platform7.OS !== "ios") return;
5853
+ const [composerHeight, setComposerHeight] = React36.useState(0);
5854
+ const [keyboardVisible, setKeyboardVisible] = React36.useState(false);
5855
+ React36.useEffect(() => {
5856
+ if (Platform9.OS !== "ios") return;
5727
5857
  const show = Keyboard4.addListener("keyboardWillShow", () => setKeyboardVisible(true));
5728
5858
  const hide = Keyboard4.addListener("keyboardWillHide", () => setKeyboardVisible(false));
5729
5859
  return () => {
@@ -5731,28 +5861,28 @@ function ChatPage({
5731
5861
  hide.remove();
5732
5862
  };
5733
5863
  }, []);
5734
- const footerBottomPadding = Platform7.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
5864
+ const footerBottomPadding = Platform9.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
5735
5865
  const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
5736
5866
  const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
5737
- const resolvedOverlay = React34.useMemo(() => {
5867
+ const resolvedOverlay = React36.useMemo(() => {
5738
5868
  var _a;
5739
5869
  if (!overlay) return null;
5740
- if (!React34.isValidElement(overlay)) return overlay;
5870
+ if (!React36.isValidElement(overlay)) return overlay;
5741
5871
  const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
5742
- return React34.cloneElement(overlay, {
5872
+ return React36.cloneElement(overlay, {
5743
5873
  style: [prevStyle, { bottom: overlayBottom }]
5744
5874
  });
5745
5875
  }, [overlay, overlayBottom]);
5746
5876
  return /* @__PURE__ */ jsxs29(View37, { style: [{ flex: 1 }, style], children: [
5747
- header ? /* @__PURE__ */ jsx47(View37, { children: header }) : null,
5748
- topBanner ? /* @__PURE__ */ jsx47(View37, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
5877
+ header ? /* @__PURE__ */ jsx49(View37, { children: header }) : null,
5878
+ topBanner ? /* @__PURE__ */ jsx49(View37, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
5749
5879
  /* @__PURE__ */ jsxs29(View37, { style: { flex: 1 }, children: [
5750
5880
  /* @__PURE__ */ jsxs29(
5751
5881
  View37,
5752
5882
  {
5753
5883
  style: { flex: 1 },
5754
5884
  children: [
5755
- /* @__PURE__ */ jsx47(
5885
+ /* @__PURE__ */ jsx49(
5756
5886
  ChatMessageList,
5757
5887
  {
5758
5888
  ref: listRef,
@@ -5767,7 +5897,7 @@ function ChatPage({
5767
5897
  ]
5768
5898
  }
5769
5899
  ),
5770
- /* @__PURE__ */ jsx47(
5900
+ /* @__PURE__ */ jsx49(
5771
5901
  View37,
5772
5902
  {
5773
5903
  style: {
@@ -5775,11 +5905,11 @@ function ChatPage({
5775
5905
  left: 0,
5776
5906
  right: 0,
5777
5907
  bottom: 0,
5778
- paddingHorizontal: theme.spacing.lg,
5908
+ paddingHorizontal: composerHorizontalPadding ?? theme.spacing.md,
5779
5909
  paddingTop: theme.spacing.sm,
5780
5910
  paddingBottom: footerBottomPadding
5781
5911
  },
5782
- children: /* @__PURE__ */ jsx47(
5912
+ children: /* @__PURE__ */ jsx49(
5783
5913
  ChatComposer,
5784
5914
  {
5785
5915
  ...composer,
@@ -5794,15 +5924,15 @@ function ChatPage({
5794
5924
  }
5795
5925
 
5796
5926
  // src/components/chat/ScrollToBottomButton.tsx
5797
- import * as React35 from "react";
5927
+ import * as React37 from "react";
5798
5928
  import { Pressable as Pressable12, View as View38 } from "react-native";
5799
5929
  import Animated11, { Easing as Easing2, useAnimatedStyle as useAnimatedStyle2, useSharedValue as useSharedValue2, withTiming as withTiming2 } from "react-native-reanimated";
5800
- import { jsx as jsx48 } from "react/jsx-runtime";
5930
+ import { jsx as jsx50 } from "react/jsx-runtime";
5801
5931
  function ScrollToBottomButton({ visible, onPress, children, style }) {
5802
5932
  const theme = useTheme();
5803
5933
  const progress = useSharedValue2(visible ? 1 : 0);
5804
- const [pressed, setPressed] = React35.useState(false);
5805
- React35.useEffect(() => {
5934
+ const [pressed, setPressed] = React37.useState(false);
5935
+ React37.useEffect(() => {
5806
5936
  progress.value = withTiming2(visible ? 1 : 0, { duration: 200, easing: Easing2.out(Easing2.ease) });
5807
5937
  }, [progress, visible]);
5808
5938
  const animStyle = useAnimatedStyle2(() => ({
@@ -5811,7 +5941,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5811
5941
  }));
5812
5942
  const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
5813
5943
  const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
5814
- return /* @__PURE__ */ jsx48(
5944
+ return /* @__PURE__ */ jsx50(
5815
5945
  Animated11.View,
5816
5946
  {
5817
5947
  pointerEvents: visible ? "auto" : "none",
@@ -5825,7 +5955,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5825
5955
  style,
5826
5956
  animStyle
5827
5957
  ],
5828
- children: /* @__PURE__ */ jsx48(
5958
+ children: /* @__PURE__ */ jsx50(
5829
5959
  View38,
5830
5960
  {
5831
5961
  style: {
@@ -5844,7 +5974,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5844
5974
  elevation: 5,
5845
5975
  opacity: pressed ? 0.85 : 1
5846
5976
  },
5847
- children: /* @__PURE__ */ jsx48(
5977
+ children: /* @__PURE__ */ jsx50(
5848
5978
  Pressable12,
5849
5979
  {
5850
5980
  onPress,
@@ -5863,7 +5993,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
5863
5993
 
5864
5994
  // src/components/chat/ChatHeader.tsx
5865
5995
  import { StyleSheet as StyleSheet4 } from "react-native";
5866
- import { jsx as jsx49 } from "react/jsx-runtime";
5996
+ import { jsx as jsx51 } from "react/jsx-runtime";
5867
5997
  function ChatHeader({ left, right, center, style }) {
5868
5998
  const flattenedStyle = StyleSheet4.flatten([
5869
5999
  {
@@ -5871,7 +6001,7 @@ function ChatHeader({ left, right, center, style }) {
5871
6001
  },
5872
6002
  style
5873
6003
  ]);
5874
- return /* @__PURE__ */ jsx49(
6004
+ return /* @__PURE__ */ jsx51(
5875
6005
  StudioSheetHeader,
5876
6006
  {
5877
6007
  left,
@@ -5884,12 +6014,12 @@ function ChatHeader({ left, right, center, style }) {
5884
6014
 
5885
6015
  // src/components/chat/ForkNoticeBanner.tsx
5886
6016
  import { View as View40 } from "react-native";
5887
- import { jsx as jsx50, jsxs as jsxs30 } from "react/jsx-runtime";
6017
+ import { jsx as jsx52, jsxs as jsxs30 } from "react/jsx-runtime";
5888
6018
  function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5889
6019
  const theme = useTheme();
5890
6020
  const resolvedTitle = title ?? (isOwner ? "Remixed app" : "Remix app");
5891
6021
  const resolvedDescription = description ?? (isOwner ? "Any changes you make will be a remix of the original app. You can view the edited version in the Remix tab in your apps page." : "Once you make edits, this remixed version will appear on your Remixed apps page.");
5892
- return /* @__PURE__ */ jsx50(
6022
+ return /* @__PURE__ */ jsx52(
5893
6023
  Card,
5894
6024
  {
5895
6025
  variant: "surfaceRaised",
@@ -5905,7 +6035,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5905
6035
  style
5906
6036
  ],
5907
6037
  children: /* @__PURE__ */ jsxs30(View40, { style: { minWidth: 0 }, children: [
5908
- /* @__PURE__ */ jsx50(
6038
+ /* @__PURE__ */ jsx52(
5909
6039
  Text,
5910
6040
  {
5911
6041
  style: {
@@ -5919,7 +6049,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5919
6049
  children: resolvedTitle
5920
6050
  }
5921
6051
  ),
5922
- /* @__PURE__ */ jsx50(
6052
+ /* @__PURE__ */ jsx52(
5923
6053
  Text,
5924
6054
  {
5925
6055
  style: {
@@ -5937,7 +6067,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
5937
6067
  }
5938
6068
 
5939
6069
  // src/studio/ui/ChatPanel.tsx
5940
- import { jsx as jsx51, jsxs as jsxs31 } from "react/jsx-runtime";
6070
+ import { jsx as jsx53, jsxs as jsxs31 } from "react/jsx-runtime";
5941
6071
  function ChatPanel({
5942
6072
  title = "Chat",
5943
6073
  autoFocusComposer = false,
@@ -5957,9 +6087,9 @@ function ChatPanel({
5957
6087
  onStartDraw,
5958
6088
  onSend
5959
6089
  }) {
5960
- const listRef = React36.useRef(null);
5961
- const [nearBottom, setNearBottom] = React36.useState(true);
5962
- const handleSend = React36.useCallback(
6090
+ const listRef = React38.useRef(null);
6091
+ const [nearBottom, setNearBottom] = React38.useState(true);
6092
+ const handleSend = React38.useCallback(
5963
6093
  async (text, composerAttachments) => {
5964
6094
  const all = composerAttachments ?? attachments;
5965
6095
  await onSend(text, all.length > 0 ? all : void 0);
@@ -5973,25 +6103,25 @@ function ChatPanel({
5973
6103
  },
5974
6104
  [attachments, nearBottom, onClearAttachments, onSend]
5975
6105
  );
5976
- const handleScrollToBottom = React36.useCallback(() => {
6106
+ const handleScrollToBottom = React38.useCallback(() => {
5977
6107
  var _a;
5978
6108
  (_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
5979
6109
  }, []);
5980
- const header = /* @__PURE__ */ jsx51(
6110
+ const header = /* @__PURE__ */ jsx53(
5981
6111
  ChatHeader,
5982
6112
  {
5983
6113
  left: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
5984
- /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx51(IconBack, { size: 20, colorToken: "floatingContent" }) }),
5985
- onNavigateHome ? /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx51(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
6114
+ /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx53(IconBack, { size: 20, colorToken: "floatingContent" }) }),
6115
+ onNavigateHome ? /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ jsx53(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
5986
6116
  ] }),
5987
6117
  right: /* @__PURE__ */ jsxs31(View41, { style: { flexDirection: "row", alignItems: "center" }, children: [
5988
- onStartDraw ? /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx51(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
5989
- /* @__PURE__ */ jsx51(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx51(IconClose, { size: 20, colorToken: "floatingContent" }) })
6118
+ onStartDraw ? /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ jsx53(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
6119
+ /* @__PURE__ */ jsx53(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ jsx53(IconClose, { size: 20, colorToken: "floatingContent" }) })
5990
6120
  ] }),
5991
6121
  center: null
5992
6122
  }
5993
6123
  );
5994
- const topBanner = shouldForkOnEdit ? /* @__PURE__ */ jsx51(
6124
+ const topBanner = shouldForkOnEdit ? /* @__PURE__ */ jsx53(
5995
6125
  ForkNoticeBanner,
5996
6126
  {
5997
6127
  isOwner: !shouldForkOnEdit,
@@ -6001,31 +6131,32 @@ function ChatPanel({
6001
6131
  const showMessagesLoading = Boolean(loading) && messages.length === 0 || forking;
6002
6132
  if (showMessagesLoading) {
6003
6133
  return /* @__PURE__ */ jsxs31(View41, { style: { flex: 1 }, children: [
6004
- /* @__PURE__ */ jsx51(View41, { children: header }),
6005
- topBanner ? /* @__PURE__ */ jsx51(View41, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
6134
+ /* @__PURE__ */ jsx53(View41, { children: header }),
6135
+ topBanner ? /* @__PURE__ */ jsx53(View41, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
6006
6136
  /* @__PURE__ */ jsxs31(View41, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
6007
- /* @__PURE__ */ jsx51(ActivityIndicator8, {}),
6008
- /* @__PURE__ */ jsx51(View41, { style: { height: 12 } }),
6009
- /* @__PURE__ */ jsx51(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
6137
+ /* @__PURE__ */ jsx53(ActivityIndicator8, {}),
6138
+ /* @__PURE__ */ jsx53(View41, { style: { height: 12 } }),
6139
+ /* @__PURE__ */ jsx53(Text, { variant: "bodyMuted", children: forking ? "Creating your copy\u2026" : "Loading messages\u2026" })
6010
6140
  ] })
6011
6141
  ] });
6012
6142
  }
6013
- return /* @__PURE__ */ jsx51(
6143
+ return /* @__PURE__ */ jsx53(
6014
6144
  ChatPage,
6015
6145
  {
6016
6146
  header,
6017
6147
  messages,
6018
6148
  showTypingIndicator,
6019
6149
  topBanner,
6150
+ composerHorizontalPadding: 0,
6020
6151
  listRef,
6021
6152
  onNearBottomChange: setNearBottom,
6022
- overlay: /* @__PURE__ */ jsx51(
6153
+ overlay: /* @__PURE__ */ jsx53(
6023
6154
  ScrollToBottomButton,
6024
6155
  {
6025
6156
  visible: !nearBottom,
6026
6157
  onPress: handleScrollToBottom,
6027
6158
  style: { bottom: 80 },
6028
- children: /* @__PURE__ */ jsx51(IconArrowDown, { size: 20, colorToken: "floatingContent" })
6159
+ children: /* @__PURE__ */ jsx53(IconArrowDown, { size: 20, colorToken: "floatingContent" })
6029
6160
  }
6030
6161
  ),
6031
6162
  composer: {
@@ -6046,7 +6177,7 @@ function ChatPanel({
6046
6177
  }
6047
6178
 
6048
6179
  // src/components/dialogs/ConfirmMergeRequestDialog.tsx
6049
- import * as React37 from "react";
6180
+ import * as React39 from "react";
6050
6181
  import { Pressable as Pressable14, View as View43 } from "react-native";
6051
6182
 
6052
6183
  // src/components/primitives/Modal.tsx
@@ -6055,7 +6186,7 @@ import {
6055
6186
  Pressable as Pressable13,
6056
6187
  View as View42
6057
6188
  } from "react-native";
6058
- import { jsx as jsx52, jsxs as jsxs32 } from "react/jsx-runtime";
6189
+ import { jsx as jsx54, jsxs as jsxs32 } from "react/jsx-runtime";
6059
6190
  function Modal({
6060
6191
  visible,
6061
6192
  onRequestClose,
@@ -6064,7 +6195,7 @@ function Modal({
6064
6195
  contentStyle
6065
6196
  }) {
6066
6197
  const theme = useTheme();
6067
- return /* @__PURE__ */ jsx52(
6198
+ return /* @__PURE__ */ jsx54(
6068
6199
  RNModal,
6069
6200
  {
6070
6201
  visible,
@@ -6072,7 +6203,7 @@ function Modal({
6072
6203
  animationType: "fade",
6073
6204
  onRequestClose,
6074
6205
  children: /* @__PURE__ */ jsxs32(View42, { style: { flex: 1, backgroundColor: theme.colors.backdrop, justifyContent: "center", padding: theme.spacing.lg }, children: [
6075
- /* @__PURE__ */ jsx52(
6206
+ /* @__PURE__ */ jsx54(
6076
6207
  Pressable13,
6077
6208
  {
6078
6209
  accessibilityRole: "button",
@@ -6080,14 +6211,14 @@ function Modal({
6080
6211
  style: { position: "absolute", inset: 0 }
6081
6212
  }
6082
6213
  ),
6083
- /* @__PURE__ */ jsx52(Card, { variant: "surfaceRaised", padded: true, style: [{ borderRadius: theme.radii.xl }, contentStyle], children })
6214
+ /* @__PURE__ */ jsx54(Card, { variant: "surfaceRaised", padded: true, style: [{ borderRadius: theme.radii.xl }, contentStyle], children })
6084
6215
  ] })
6085
6216
  }
6086
6217
  );
6087
6218
  }
6088
6219
 
6089
6220
  // src/components/dialogs/ConfirmMergeRequestDialog.tsx
6090
- import { jsx as jsx53, jsxs as jsxs33 } from "react/jsx-runtime";
6221
+ import { jsx as jsx55, jsxs as jsxs33 } from "react/jsx-runtime";
6091
6222
  function ConfirmMergeRequestDialog({
6092
6223
  visible,
6093
6224
  onOpenChange,
@@ -6098,14 +6229,14 @@ function ConfirmMergeRequestDialog({
6098
6229
  onTestFirst
6099
6230
  }) {
6100
6231
  const theme = useTheme();
6101
- const close = React37.useCallback(() => onOpenChange(false), [onOpenChange]);
6232
+ const close = React39.useCallback(() => onOpenChange(false), [onOpenChange]);
6102
6233
  const canConfirm = Boolean(mergeRequest) && !approveDisabled;
6103
- const handleConfirm = React37.useCallback(() => {
6234
+ const handleConfirm = React39.useCallback(() => {
6104
6235
  if (!mergeRequest) return;
6105
6236
  onOpenChange(false);
6106
6237
  void onConfirm();
6107
6238
  }, [mergeRequest, onConfirm, onOpenChange]);
6108
- const handleTestFirst = React37.useCallback(() => {
6239
+ const handleTestFirst = React39.useCallback(() => {
6109
6240
  if (!mergeRequest) return;
6110
6241
  onOpenChange(false);
6111
6242
  void onTestFirst(mergeRequest);
@@ -6128,7 +6259,7 @@ function ConfirmMergeRequestDialog({
6128
6259
  backgroundColor: theme.colors.background
6129
6260
  },
6130
6261
  children: [
6131
- /* @__PURE__ */ jsx53(View43, { children: /* @__PURE__ */ jsx53(
6262
+ /* @__PURE__ */ jsx55(View43, { children: /* @__PURE__ */ jsx55(
6132
6263
  Text,
6133
6264
  {
6134
6265
  style: {
@@ -6141,7 +6272,7 @@ function ConfirmMergeRequestDialog({
6141
6272
  }
6142
6273
  ) }),
6143
6274
  /* @__PURE__ */ jsxs33(View43, { style: { marginTop: 16 }, children: [
6144
- /* @__PURE__ */ jsx53(
6275
+ /* @__PURE__ */ jsx55(
6145
6276
  View43,
6146
6277
  {
6147
6278
  style: [
@@ -6151,7 +6282,7 @@ function ConfirmMergeRequestDialog({
6151
6282
  opacity: canConfirm ? 1 : 0.5
6152
6283
  }
6153
6284
  ],
6154
- children: /* @__PURE__ */ jsx53(
6285
+ children: /* @__PURE__ */ jsx55(
6155
6286
  Pressable14,
6156
6287
  {
6157
6288
  accessibilityRole: "button",
@@ -6159,13 +6290,13 @@ function ConfirmMergeRequestDialog({
6159
6290
  disabled: !canConfirm,
6160
6291
  onPress: handleConfirm,
6161
6292
  style: [fullWidthButtonBase, { flex: 1 }],
6162
- children: /* @__PURE__ */ jsx53(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
6293
+ children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
6163
6294
  }
6164
6295
  )
6165
6296
  }
6166
6297
  ),
6167
- /* @__PURE__ */ jsx53(View43, { style: { height: 8 } }),
6168
- /* @__PURE__ */ jsx53(
6298
+ /* @__PURE__ */ jsx55(View43, { style: { height: 8 } }),
6299
+ /* @__PURE__ */ jsx55(
6169
6300
  View43,
6170
6301
  {
6171
6302
  style: [
@@ -6177,7 +6308,7 @@ function ConfirmMergeRequestDialog({
6177
6308
  opacity: isBuilding || !mergeRequest ? 0.5 : 1
6178
6309
  }
6179
6310
  ],
6180
- children: /* @__PURE__ */ jsx53(
6311
+ children: /* @__PURE__ */ jsx55(
6181
6312
  Pressable14,
6182
6313
  {
6183
6314
  accessibilityRole: "button",
@@ -6185,13 +6316,13 @@ function ConfirmMergeRequestDialog({
6185
6316
  disabled: isBuilding || !mergeRequest,
6186
6317
  onPress: handleTestFirst,
6187
6318
  style: [fullWidthButtonBase, { flex: 1 }],
6188
- children: /* @__PURE__ */ jsx53(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
6319
+ children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
6189
6320
  }
6190
6321
  )
6191
6322
  }
6192
6323
  ),
6193
- /* @__PURE__ */ jsx53(View43, { style: { height: 8 } }),
6194
- /* @__PURE__ */ jsx53(
6324
+ /* @__PURE__ */ jsx55(View43, { style: { height: 8 } }),
6325
+ /* @__PURE__ */ jsx55(
6195
6326
  View43,
6196
6327
  {
6197
6328
  style: [
@@ -6202,14 +6333,14 @@ function ConfirmMergeRequestDialog({
6202
6333
  borderColor: theme.colors.border
6203
6334
  }
6204
6335
  ],
6205
- children: /* @__PURE__ */ jsx53(
6336
+ children: /* @__PURE__ */ jsx55(
6206
6337
  Pressable14,
6207
6338
  {
6208
6339
  accessibilityRole: "button",
6209
6340
  accessibilityLabel: "Cancel",
6210
6341
  onPress: close,
6211
6342
  style: [fullWidthButtonBase, { flex: 1 }],
6212
- children: /* @__PURE__ */ jsx53(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
6343
+ children: /* @__PURE__ */ jsx55(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
6213
6344
  }
6214
6345
  )
6215
6346
  }
@@ -6221,7 +6352,7 @@ function ConfirmMergeRequestDialog({
6221
6352
  }
6222
6353
 
6223
6354
  // src/studio/ui/ConfirmMergeFlow.tsx
6224
- import { jsx as jsx54 } from "react/jsx-runtime";
6355
+ import { jsx as jsx56 } from "react/jsx-runtime";
6225
6356
  function ConfirmMergeFlow({
6226
6357
  visible,
6227
6358
  onOpenChange,
@@ -6232,7 +6363,7 @@ function ConfirmMergeFlow({
6232
6363
  onConfirm,
6233
6364
  onTestFirst
6234
6365
  }) {
6235
- return /* @__PURE__ */ jsx54(
6366
+ return /* @__PURE__ */ jsx56(
6236
6367
  ConfirmMergeRequestDialog,
6237
6368
  {
6238
6369
  visible,
@@ -6253,8 +6384,94 @@ function ConfirmMergeFlow({
6253
6384
  );
6254
6385
  }
6255
6386
 
6387
+ // src/studio/hooks/useOptimisticChatMessages.ts
6388
+ import * as React40 from "react";
6389
+ function makeOptimisticId() {
6390
+ return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
6391
+ }
6392
+ function toEpochMs(createdAt) {
6393
+ if (createdAt == null) return 0;
6394
+ if (typeof createdAt === "number") return createdAt;
6395
+ if (createdAt instanceof Date) return createdAt.getTime();
6396
+ const t = Date.parse(String(createdAt));
6397
+ return Number.isFinite(t) ? t : 0;
6398
+ }
6399
+ function isOptimisticResolvedByServer(chatMessages, o) {
6400
+ if (o.failed) return false;
6401
+ const normalize = (s) => s.trim();
6402
+ let startIndex = -1;
6403
+ if (o.baseServerLastId) {
6404
+ startIndex = chatMessages.findIndex((m) => m.id === o.baseServerLastId);
6405
+ }
6406
+ const candidates = startIndex >= 0 ? chatMessages.slice(startIndex + 1) : chatMessages;
6407
+ const target = normalize(o.content);
6408
+ for (const m of candidates) {
6409
+ if (m.author !== "human") continue;
6410
+ if (normalize(m.content) !== target) continue;
6411
+ const serverMs = toEpochMs(m.createdAt);
6412
+ const optimisticMs = Date.parse(o.createdAtIso);
6413
+ if (Number.isFinite(optimisticMs) && optimisticMs > 0 && serverMs > 0) {
6414
+ if (serverMs + 12e4 < optimisticMs) continue;
6415
+ }
6416
+ return true;
6417
+ }
6418
+ return false;
6419
+ }
6420
+ function useOptimisticChatMessages({
6421
+ threadId,
6422
+ shouldForkOnEdit,
6423
+ chatMessages,
6424
+ onSendChat
6425
+ }) {
6426
+ const [optimisticChat, setOptimisticChat] = React40.useState([]);
6427
+ React40.useEffect(() => {
6428
+ setOptimisticChat([]);
6429
+ }, [threadId]);
6430
+ const messages = React40.useMemo(() => {
6431
+ if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
6432
+ const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
6433
+ if (unresolved.length === 0) return chatMessages;
6434
+ const optimisticAsChat = unresolved.map((o) => ({
6435
+ id: o.id,
6436
+ author: "human",
6437
+ content: o.content,
6438
+ createdAt: o.createdAtIso,
6439
+ kind: "optimistic",
6440
+ meta: o.failed ? { kind: "optimistic", event: "send.failed", status: "error" } : { kind: "optimistic", event: "send.pending", status: "info" }
6441
+ }));
6442
+ const merged = [...chatMessages, ...optimisticAsChat];
6443
+ merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
6444
+ return merged;
6445
+ }, [chatMessages, optimisticChat]);
6446
+ React40.useEffect(() => {
6447
+ if (optimisticChat.length === 0) return;
6448
+ setOptimisticChat((prev) => {
6449
+ if (prev.length === 0) return prev;
6450
+ const next = prev.filter((o) => !isOptimisticResolvedByServer(chatMessages, o) || o.failed);
6451
+ return next.length === prev.length ? prev : next;
6452
+ });
6453
+ }, [chatMessages, optimisticChat.length]);
6454
+ const onSend = React40.useCallback(
6455
+ async (text, attachments) => {
6456
+ if (shouldForkOnEdit) {
6457
+ await onSendChat(text, attachments);
6458
+ return;
6459
+ }
6460
+ const createdAtIso = (/* @__PURE__ */ new Date()).toISOString();
6461
+ const baseServerLastId = chatMessages.length > 0 ? chatMessages[chatMessages.length - 1].id : null;
6462
+ const id = makeOptimisticId();
6463
+ setOptimisticChat((prev) => [...prev, { id, content: text, createdAtIso, baseServerLastId, failed: false }]);
6464
+ void Promise.resolve(onSendChat(text, attachments)).catch(() => {
6465
+ setOptimisticChat((prev) => prev.map((m) => m.id === id ? { ...m, failed: true } : m));
6466
+ });
6467
+ },
6468
+ [chatMessages, onSendChat, shouldForkOnEdit]
6469
+ );
6470
+ return { messages, onSend };
6471
+ }
6472
+
6256
6473
  // src/studio/ui/StudioOverlay.tsx
6257
- import { Fragment as Fragment6, jsx as jsx55, jsxs as jsxs34 } from "react/jsx-runtime";
6474
+ import { Fragment as Fragment6, jsx as jsx57, jsxs as jsxs34 } from "react/jsx-runtime";
6258
6475
  function StudioOverlay({
6259
6476
  captureTargetRef,
6260
6477
  app,
@@ -6285,31 +6502,38 @@ function StudioOverlay({
6285
6502
  }) {
6286
6503
  const theme = useTheme();
6287
6504
  const { width } = useWindowDimensions4();
6288
- const [sheetOpen, setSheetOpen] = React38.useState(false);
6289
- const [activePage, setActivePage] = React38.useState("preview");
6290
- const [drawing, setDrawing] = React38.useState(false);
6291
- const [chatAttachments, setChatAttachments] = React38.useState([]);
6292
- const [commentsAppId, setCommentsAppId] = React38.useState(null);
6293
- const [commentsCount, setCommentsCount] = React38.useState(null);
6294
- const [confirmMrId, setConfirmMrId] = React38.useState(null);
6295
- const confirmMr = React38.useMemo(
6505
+ const [sheetOpen, setSheetOpen] = React41.useState(false);
6506
+ const [activePage, setActivePage] = React41.useState("preview");
6507
+ const [drawing, setDrawing] = React41.useState(false);
6508
+ const [chatAttachments, setChatAttachments] = React41.useState([]);
6509
+ const [commentsAppId, setCommentsAppId] = React41.useState(null);
6510
+ const [commentsCount, setCommentsCount] = React41.useState(null);
6511
+ const threadId = (app == null ? void 0 : app.threadId) ?? null;
6512
+ const optimistic = useOptimisticChatMessages({
6513
+ threadId,
6514
+ shouldForkOnEdit,
6515
+ chatMessages,
6516
+ onSendChat
6517
+ });
6518
+ const [confirmMrId, setConfirmMrId] = React41.useState(null);
6519
+ const confirmMr = React41.useMemo(
6296
6520
  () => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
6297
6521
  [confirmMrId, incomingMergeRequests]
6298
6522
  );
6299
- const handleSheetOpenChange = React38.useCallback((open) => {
6523
+ const handleSheetOpenChange = React41.useCallback((open) => {
6300
6524
  setSheetOpen(open);
6301
6525
  if (!open) Keyboard5.dismiss();
6302
6526
  }, []);
6303
- const closeSheet = React38.useCallback(() => {
6527
+ const closeSheet = React41.useCallback(() => {
6304
6528
  handleSheetOpenChange(false);
6305
6529
  }, [handleSheetOpenChange]);
6306
- const openSheet = React38.useCallback(() => setSheetOpen(true), []);
6307
- const goToChat = React38.useCallback(() => {
6530
+ const openSheet = React41.useCallback(() => setSheetOpen(true), []);
6531
+ const goToChat = React41.useCallback(() => {
6308
6532
  setActivePage("chat");
6309
6533
  openSheet();
6310
6534
  }, [openSheet]);
6311
- const backToPreview = React38.useCallback(() => {
6312
- if (Platform8.OS !== "ios") {
6535
+ const backToPreview = React41.useCallback(() => {
6536
+ if (Platform10.OS !== "ios") {
6313
6537
  Keyboard5.dismiss();
6314
6538
  setActivePage("preview");
6315
6539
  return;
@@ -6326,11 +6550,11 @@ function StudioOverlay({
6326
6550
  const t = setTimeout(finalize, 350);
6327
6551
  Keyboard5.dismiss();
6328
6552
  }, []);
6329
- const startDraw = React38.useCallback(() => {
6553
+ const startDraw = React41.useCallback(() => {
6330
6554
  setDrawing(true);
6331
6555
  closeSheet();
6332
6556
  }, [closeSheet]);
6333
- const handleDrawCapture = React38.useCallback(
6557
+ const handleDrawCapture = React41.useCallback(
6334
6558
  (dataUrl) => {
6335
6559
  setChatAttachments((prev) => [...prev, dataUrl]);
6336
6560
  setDrawing(false);
@@ -6339,7 +6563,7 @@ function StudioOverlay({
6339
6563
  },
6340
6564
  [openSheet]
6341
6565
  );
6342
- const toggleSheet = React38.useCallback(async () => {
6566
+ const toggleSheet = React41.useCallback(async () => {
6343
6567
  if (!sheetOpen) {
6344
6568
  const shouldExitTest = Boolean(testingMrId) || isTesting;
6345
6569
  if (shouldExitTest) {
@@ -6351,7 +6575,7 @@ function StudioOverlay({
6351
6575
  closeSheet();
6352
6576
  }
6353
6577
  }, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
6354
- const handleTestMr = React38.useCallback(
6578
+ const handleTestMr = React41.useCallback(
6355
6579
  async (mr) => {
6356
6580
  if (!onTestMr) return;
6357
6581
  await onTestMr(mr);
@@ -6360,13 +6584,13 @@ function StudioOverlay({
6360
6584
  [closeSheet, onTestMr]
6361
6585
  );
6362
6586
  return /* @__PURE__ */ jsxs34(Fragment6, { children: [
6363
- /* @__PURE__ */ jsx55(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
6364
- /* @__PURE__ */ jsx55(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ jsx55(
6587
+ /* @__PURE__ */ jsx57(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
6588
+ /* @__PURE__ */ jsx57(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, children: /* @__PURE__ */ jsx57(
6365
6589
  StudioSheetPager,
6366
6590
  {
6367
6591
  activePage,
6368
6592
  width,
6369
- preview: /* @__PURE__ */ jsx55(
6593
+ preview: /* @__PURE__ */ jsx57(
6370
6594
  PreviewPanel,
6371
6595
  {
6372
6596
  app,
@@ -6392,10 +6616,10 @@ function StudioOverlay({
6392
6616
  commentCountOverride: commentsCount ?? void 0
6393
6617
  }
6394
6618
  ),
6395
- chat: /* @__PURE__ */ jsx55(
6619
+ chat: /* @__PURE__ */ jsx57(
6396
6620
  ChatPanel,
6397
6621
  {
6398
- messages: chatMessages,
6622
+ messages: optimistic.messages,
6399
6623
  showTypingIndicator: chatShowTypingIndicator,
6400
6624
  loading: chatLoading,
6401
6625
  sendDisabled: chatSendDisabled,
@@ -6410,12 +6634,12 @@ function StudioOverlay({
6410
6634
  onClose: closeSheet,
6411
6635
  onNavigateHome,
6412
6636
  onStartDraw: startDraw,
6413
- onSend: onSendChat
6637
+ onSend: optimistic.onSend
6414
6638
  }
6415
6639
  )
6416
6640
  }
6417
6641
  ) }),
6418
- /* @__PURE__ */ jsx55(
6642
+ /* @__PURE__ */ jsx57(
6419
6643
  FloatingDraggableButton,
6420
6644
  {
6421
6645
  visible: !sheetOpen && !drawing,
@@ -6423,10 +6647,10 @@ function StudioOverlay({
6423
6647
  badgeCount: incomingMergeRequests.length,
6424
6648
  onPress: toggleSheet,
6425
6649
  isLoading: (app == null ? void 0 : app.status) === "editing",
6426
- children: /* @__PURE__ */ jsx55(View44, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx55(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
6650
+ children: /* @__PURE__ */ jsx57(View44, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx57(MergeIcon, { width: 24, height: 24, color: theme.colors.floatingContent }) })
6427
6651
  }
6428
6652
  ),
6429
- /* @__PURE__ */ jsx55(
6653
+ /* @__PURE__ */ jsx57(
6430
6654
  DrawModeOverlay,
6431
6655
  {
6432
6656
  visible: drawing,
@@ -6435,7 +6659,7 @@ function StudioOverlay({
6435
6659
  onCapture: handleDrawCapture
6436
6660
  }
6437
6661
  ),
6438
- /* @__PURE__ */ jsx55(
6662
+ /* @__PURE__ */ jsx57(
6439
6663
  ConfirmMergeFlow,
6440
6664
  {
6441
6665
  visible: Boolean(confirmMr),
@@ -6448,7 +6672,7 @@ function StudioOverlay({
6448
6672
  onTestFirst: handleTestMr
6449
6673
  }
6450
6674
  ),
6451
- /* @__PURE__ */ jsx55(
6675
+ /* @__PURE__ */ jsx57(
6452
6676
  AppCommentsSheet,
6453
6677
  {
6454
6678
  appId: commentsAppId,
@@ -6461,7 +6685,7 @@ function StudioOverlay({
6461
6685
  }
6462
6686
 
6463
6687
  // src/studio/ComergeStudio.tsx
6464
- import { jsx as jsx56, jsxs as jsxs35 } from "react/jsx-runtime";
6688
+ import { jsx as jsx58, jsxs as jsxs35 } from "react/jsx-runtime";
6465
6689
  function ComergeStudio({
6466
6690
  appId,
6467
6691
  apiKey,
@@ -6469,17 +6693,17 @@ function ComergeStudio({
6469
6693
  onNavigateHome,
6470
6694
  style
6471
6695
  }) {
6472
- const [activeAppId, setActiveAppId] = React39.useState(appId);
6473
- const [runtimeAppId, setRuntimeAppId] = React39.useState(appId);
6474
- const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React39.useState(null);
6475
- const platform = React39.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
6476
- React39.useEffect(() => {
6696
+ const [activeAppId, setActiveAppId] = React42.useState(appId);
6697
+ const [runtimeAppId, setRuntimeAppId] = React42.useState(appId);
6698
+ const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React42.useState(null);
6699
+ const platform = React42.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
6700
+ React42.useEffect(() => {
6477
6701
  setActiveAppId(appId);
6478
6702
  setRuntimeAppId(appId);
6479
6703
  setPendingRuntimeTargetAppId(null);
6480
6704
  }, [appId]);
6481
- const captureTargetRef = React39.useRef(null);
6482
- return /* @__PURE__ */ jsx56(StudioBootstrap, { apiKey, children: ({ userId }) => /* @__PURE__ */ jsx56(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx56(
6705
+ const captureTargetRef = React42.useRef(null);
6706
+ return /* @__PURE__ */ jsx58(StudioBootstrap, { apiKey, children: ({ userId }) => /* @__PURE__ */ jsx58(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx58(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ jsx58(
6483
6707
  ComergeStudioInner,
6484
6708
  {
6485
6709
  userId,
@@ -6495,7 +6719,7 @@ function ComergeStudio({
6495
6719
  captureTargetRef,
6496
6720
  style
6497
6721
  }
6498
- ) }) });
6722
+ ) }) }) });
6499
6723
  }
6500
6724
  function ComergeStudioInner({
6501
6725
  userId,
@@ -6514,11 +6738,11 @@ function ComergeStudioInner({
6514
6738
  const { app, loading: appLoading } = useApp(activeAppId);
6515
6739
  const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
6516
6740
  const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
6517
- const sawEditingOnPendingTargetRef = React39.useRef(false);
6518
- React39.useEffect(() => {
6741
+ const sawEditingOnPendingTargetRef = React42.useRef(false);
6742
+ React42.useEffect(() => {
6519
6743
  sawEditingOnPendingTargetRef.current = false;
6520
6744
  }, [pendingRuntimeTargetAppId]);
6521
- React39.useEffect(() => {
6745
+ React42.useEffect(() => {
6522
6746
  if (!pendingRuntimeTargetAppId) return;
6523
6747
  if (activeAppId !== pendingRuntimeTargetAppId) return;
6524
6748
  if ((app == null ? void 0 : app.status) === "editing") {
@@ -6535,13 +6759,38 @@ function ComergeStudioInner({
6535
6759
  platform,
6536
6760
  canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready"
6537
6761
  });
6762
+ const sawEditingOnActiveAppRef = React42.useRef(false);
6763
+ const [showPostEditPreparing, setShowPostEditPreparing] = React42.useState(false);
6764
+ React42.useEffect(() => {
6765
+ sawEditingOnActiveAppRef.current = false;
6766
+ setShowPostEditPreparing(false);
6767
+ }, [activeAppId]);
6768
+ React42.useEffect(() => {
6769
+ if (!(app == null ? void 0 : app.id)) return;
6770
+ if (app.status === "editing") {
6771
+ sawEditingOnActiveAppRef.current = true;
6772
+ setShowPostEditPreparing(false);
6773
+ return;
6774
+ }
6775
+ if (app.status === "ready" && sawEditingOnActiveAppRef.current) {
6776
+ setShowPostEditPreparing(true);
6777
+ sawEditingOnActiveAppRef.current = false;
6778
+ }
6779
+ }, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
6780
+ React42.useEffect(() => {
6781
+ if (!showPostEditPreparing) return;
6782
+ const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
6783
+ if (!stillProcessingBaseBundle) {
6784
+ setShowPostEditPreparing(false);
6785
+ }
6786
+ }, [showPostEditPreparing, bundle.loading, bundle.loadingMode, bundle.isTesting]);
6538
6787
  const threadId = (app == null ? void 0 : app.threadId) ?? "";
6539
6788
  const thread = useThreadMessages(threadId);
6540
6789
  const mergeRequests = useMergeRequests({ appId: activeAppId });
6541
- const hasOpenOutgoingMr = React39.useMemo(() => {
6790
+ const hasOpenOutgoingMr = React42.useMemo(() => {
6542
6791
  return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
6543
6792
  }, [mergeRequests.lists.outgoing]);
6544
- const incomingReviewMrs = React39.useMemo(() => {
6793
+ const incomingReviewMrs = React42.useMemo(() => {
6545
6794
  if (!userId) return mergeRequests.lists.incoming;
6546
6795
  return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
6547
6796
  }, [mergeRequests.lists.incoming, userId]);
@@ -6563,18 +6812,26 @@ function ComergeStudioInner({
6563
6812
  uploadAttachments: uploader.uploadBase64Images
6564
6813
  });
6565
6814
  const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
6566
- const [processingMrId, setProcessingMrId] = React39.useState(null);
6567
- const [testingMrId, setTestingMrId] = React39.useState(null);
6568
- const chatShowTypingIndicator = React39.useMemo(() => {
6815
+ const [processingMrId, setProcessingMrId] = React42.useState(null);
6816
+ const [testingMrId, setTestingMrId] = React42.useState(null);
6817
+ const chatShowTypingIndicator = React42.useMemo(() => {
6569
6818
  var _a;
6570
6819
  if (!thread.raw || thread.raw.length === 0) return false;
6571
6820
  const last = thread.raw[thread.raw.length - 1];
6572
6821
  const payloadType = typeof ((_a = last.payload) == null ? void 0 : _a.type) === "string" ? String(last.payload.type) : void 0;
6573
6822
  return payloadType !== "outcome";
6574
6823
  }, [thread.raw]);
6575
- return /* @__PURE__ */ jsx56(View45, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs35(View45, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
6576
- /* @__PURE__ */ jsx56(RuntimeRenderer, { appKey, bundlePath: bundle.bundlePath, renderToken: bundle.renderToken }),
6577
- /* @__PURE__ */ jsx56(
6824
+ return /* @__PURE__ */ jsx58(View45, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsxs35(View45, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
6825
+ /* @__PURE__ */ jsx58(
6826
+ RuntimeRenderer,
6827
+ {
6828
+ appKey,
6829
+ bundlePath: bundle.bundlePath,
6830
+ forcePreparing: showPostEditPreparing,
6831
+ renderToken: bundle.renderToken
6832
+ }
6833
+ ),
6834
+ /* @__PURE__ */ jsx58(
6578
6835
  StudioOverlay,
6579
6836
  {
6580
6837
  captureTargetRef,