@comergehq/studio 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +821 -386
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +830 -387
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/components/chat/ChatMessageAttachments.tsx +243 -0
- package/src/components/chat/ChatMessageBubble.tsx +74 -24
- package/src/components/chat/ChatMessageList.tsx +4 -1
- package/src/components/chat/ChatPage.tsx +3 -0
- package/src/components/draw/DrawModeOverlay.tsx +7 -1
- package/src/components/models/types.ts +11 -0
- package/src/components/overlays/EdgeGlowFrame.tsx +7 -2
- package/src/data/attachment/types.ts +2 -0
- package/src/studio/ComergeStudio.tsx +3 -0
- package/src/studio/hooks/useAttachmentUpload.ts +37 -6
- package/src/studio/hooks/useOptimisticChatMessages.ts +47 -3
- package/src/studio/hooks/useThreadMessages.ts +79 -5
- package/src/studio/ui/ChatPanel.tsx +3 -0
- package/src/studio/ui/StudioOverlay.tsx +3 -0
- package/src/studio/ui/preview-panel/PreviewRelatedAppsSection.tsx +28 -19
package/dist/index.js
CHANGED
|
@@ -516,8 +516,8 @@ __export(index_exports, {
|
|
|
516
516
|
module.exports = __toCommonJS(index_exports);
|
|
517
517
|
|
|
518
518
|
// src/studio/ComergeStudio.tsx
|
|
519
|
-
var
|
|
520
|
-
var
|
|
519
|
+
var React52 = __toESM(require("react"));
|
|
520
|
+
var import_react_native63 = require("react-native");
|
|
521
521
|
var import_bottom_sheet6 = require("@gorhom/bottom-sheet");
|
|
522
522
|
var import_runtime2 = require("@comergehq/runtime");
|
|
523
523
|
|
|
@@ -1635,6 +1635,34 @@ function compareMessages(a, b) {
|
|
|
1635
1635
|
if (aMs !== bMs) return aMs - bMs;
|
|
1636
1636
|
return String(a.createdAt).localeCompare(String(b.createdAt));
|
|
1637
1637
|
}
|
|
1638
|
+
function parseAttachments(payload) {
|
|
1639
|
+
const raw = payload == null ? void 0 : payload.attachments;
|
|
1640
|
+
if (!Array.isArray(raw)) return [];
|
|
1641
|
+
const out = [];
|
|
1642
|
+
for (const item of raw) {
|
|
1643
|
+
if (!item || typeof item !== "object") continue;
|
|
1644
|
+
const id = typeof item.id === "string" ? String(item.id) : "";
|
|
1645
|
+
const name = typeof item.name === "string" ? String(item.name) : "";
|
|
1646
|
+
const mimeType = typeof item.mimeType === "string" ? String(item.mimeType) : "";
|
|
1647
|
+
const size = typeof item.size === "number" ? Number(item.size) : 0;
|
|
1648
|
+
if (!id || !name || !mimeType || !Number.isFinite(size) || size <= 0) continue;
|
|
1649
|
+
out.push({
|
|
1650
|
+
id,
|
|
1651
|
+
name,
|
|
1652
|
+
mimeType,
|
|
1653
|
+
size,
|
|
1654
|
+
uri: typeof item.downloadUrl === "string" ? String(item.downloadUrl) : void 0,
|
|
1655
|
+
width: typeof item.width === "number" ? Number(item.width) : void 0,
|
|
1656
|
+
height: typeof item.height === "number" ? Number(item.height) : void 0
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
return out;
|
|
1660
|
+
}
|
|
1661
|
+
function hasAttachmentWithoutUrl(payload) {
|
|
1662
|
+
const attachments = parseAttachments(payload);
|
|
1663
|
+
if (attachments.length === 0) return false;
|
|
1664
|
+
return attachments.some((att) => !att.uri);
|
|
1665
|
+
}
|
|
1638
1666
|
function mapMessageToChatMessage(m) {
|
|
1639
1667
|
var _a, _b;
|
|
1640
1668
|
const kind = typeof ((_a = m.payload) == null ? void 0 : _a.type) === "string" ? String(m.payload.type) : null;
|
|
@@ -1644,7 +1672,8 @@ function mapMessageToChatMessage(m) {
|
|
|
1644
1672
|
content: typeof ((_b = m.payload) == null ? void 0 : _b.content) === "string" ? m.payload.content : "",
|
|
1645
1673
|
createdAt: m.createdAt,
|
|
1646
1674
|
kind,
|
|
1647
|
-
meta: extractMeta(m.payload)
|
|
1675
|
+
meta: extractMeta(m.payload),
|
|
1676
|
+
attachments: parseAttachments(m.payload)
|
|
1648
1677
|
};
|
|
1649
1678
|
}
|
|
1650
1679
|
function useThreadMessages(threadId) {
|
|
@@ -1655,9 +1684,19 @@ function useThreadMessages(threadId) {
|
|
|
1655
1684
|
const activeRequestIdRef = React4.useRef(0);
|
|
1656
1685
|
const foregroundSignal = useForegroundSignal(Boolean(threadId));
|
|
1657
1686
|
const hasLoadedOnceRef = React4.useRef(false);
|
|
1687
|
+
const attachmentRecoveryTimerRef = React4.useRef(null);
|
|
1688
|
+
const lastAttachmentRecoveryAtRef = React4.useRef(0);
|
|
1658
1689
|
React4.useEffect(() => {
|
|
1659
1690
|
hasLoadedOnceRef.current = false;
|
|
1660
1691
|
}, [threadId]);
|
|
1692
|
+
React4.useEffect(() => {
|
|
1693
|
+
return () => {
|
|
1694
|
+
if (attachmentRecoveryTimerRef.current) {
|
|
1695
|
+
clearTimeout(attachmentRecoveryTimerRef.current);
|
|
1696
|
+
attachmentRecoveryTimerRef.current = null;
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
}, []);
|
|
1661
1700
|
const upsertSorted = React4.useCallback((prev, m) => {
|
|
1662
1701
|
const next = prev.filter((x) => x.id !== m.id);
|
|
1663
1702
|
next.push(m);
|
|
@@ -1698,29 +1737,56 @@ function useThreadMessages(threadId) {
|
|
|
1698
1737
|
}
|
|
1699
1738
|
}
|
|
1700
1739
|
}, [threadId]);
|
|
1740
|
+
const recoverAttachmentUrls = React4.useCallback(() => {
|
|
1741
|
+
if (!threadId) return;
|
|
1742
|
+
if (attachmentRecoveryTimerRef.current) return;
|
|
1743
|
+
const now = Date.now();
|
|
1744
|
+
if (now - lastAttachmentRecoveryAtRef.current < 2e3) return;
|
|
1745
|
+
attachmentRecoveryTimerRef.current = setTimeout(() => {
|
|
1746
|
+
attachmentRecoveryTimerRef.current = null;
|
|
1747
|
+
lastAttachmentRecoveryAtRef.current = Date.now();
|
|
1748
|
+
void refetch({ background: true });
|
|
1749
|
+
}, 250);
|
|
1750
|
+
}, [refetch, threadId]);
|
|
1701
1751
|
React4.useEffect(() => {
|
|
1702
1752
|
void refetch();
|
|
1703
1753
|
}, [refetch]);
|
|
1704
1754
|
React4.useEffect(() => {
|
|
1705
1755
|
if (!threadId) return;
|
|
1706
1756
|
const unsubscribe = messagesRepository.subscribeThread(threadId, {
|
|
1707
|
-
onInsert: (m) =>
|
|
1708
|
-
|
|
1757
|
+
onInsert: (m) => {
|
|
1758
|
+
setRaw((prev) => upsertSorted(prev, m));
|
|
1759
|
+
if (hasAttachmentWithoutUrl(m.payload)) {
|
|
1760
|
+
recoverAttachmentUrls();
|
|
1761
|
+
}
|
|
1762
|
+
},
|
|
1763
|
+
onUpdate: (m) => {
|
|
1764
|
+
setRaw((prev) => upsertSorted(prev, m));
|
|
1765
|
+
if (hasAttachmentWithoutUrl(m.payload)) {
|
|
1766
|
+
recoverAttachmentUrls();
|
|
1767
|
+
}
|
|
1768
|
+
},
|
|
1709
1769
|
onDelete: (m) => setRaw((prev) => prev.filter((x) => x.id !== m.id))
|
|
1710
1770
|
});
|
|
1711
1771
|
return unsubscribe;
|
|
1712
|
-
}, [threadId, upsertSorted, foregroundSignal]);
|
|
1772
|
+
}, [threadId, upsertSorted, foregroundSignal, recoverAttachmentUrls]);
|
|
1713
1773
|
React4.useEffect(() => {
|
|
1714
1774
|
if (!threadId) return;
|
|
1715
1775
|
if (foregroundSignal <= 0) return;
|
|
1716
1776
|
void refetch({ background: true });
|
|
1717
1777
|
}, [foregroundSignal, refetch, threadId]);
|
|
1778
|
+
React4.useEffect(() => {
|
|
1779
|
+
if (!threadId) return;
|
|
1780
|
+
if (raw.length === 0) return;
|
|
1781
|
+
if (!raw.some((m) => hasAttachmentWithoutUrl(m.payload))) return;
|
|
1782
|
+
recoverAttachmentUrls();
|
|
1783
|
+
}, [raw, recoverAttachmentUrls, threadId]);
|
|
1718
1784
|
const messages = React4.useMemo(() => {
|
|
1719
1785
|
const visible = raw.filter((m) => !isQueuedHiddenMessage(m));
|
|
1720
1786
|
const resolved = visible.length > 0 ? visible : raw;
|
|
1721
1787
|
return resolved.map(mapMessageToChatMessage);
|
|
1722
1788
|
}, [raw]);
|
|
1723
|
-
return { raw, messages, loading, refreshing, error, refetch };
|
|
1789
|
+
return { raw, messages, loading, refreshing, error, refetch, recoverAttachmentUrls };
|
|
1724
1790
|
}
|
|
1725
1791
|
|
|
1726
1792
|
// src/studio/hooks/useBundleManager.ts
|
|
@@ -2983,6 +3049,23 @@ function getMimeTypeFromDataUrl(dataUrl) {
|
|
|
2983
3049
|
const mimeMatch = header.match(/data:(.*?);base64/i);
|
|
2984
3050
|
return (mimeMatch == null ? void 0 : mimeMatch[1]) ?? "image/png";
|
|
2985
3051
|
}
|
|
3052
|
+
async function getImageDimensionsFromDataUrl(dataUrl) {
|
|
3053
|
+
try {
|
|
3054
|
+
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
3055
|
+
const dims = await new Promise((resolve, reject) => {
|
|
3056
|
+
import_react_native6.Image.getSize(
|
|
3057
|
+
normalized,
|
|
3058
|
+
(width, height) => resolve({ width, height }),
|
|
3059
|
+
(err) => reject(err)
|
|
3060
|
+
);
|
|
3061
|
+
});
|
|
3062
|
+
if (dims.width > 0 && dims.height > 0) {
|
|
3063
|
+
return { width: Math.round(dims.width), height: Math.round(dims.height) };
|
|
3064
|
+
}
|
|
3065
|
+
} catch {
|
|
3066
|
+
}
|
|
3067
|
+
return {};
|
|
3068
|
+
}
|
|
2986
3069
|
function useAttachmentUpload() {
|
|
2987
3070
|
const [uploading, setUploading] = React7.useState(false);
|
|
2988
3071
|
const [error, setError] = React7.useState(null);
|
|
@@ -2997,17 +3080,24 @@ function useAttachmentUpload() {
|
|
|
2997
3080
|
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
2998
3081
|
const blob = import_react_native6.Platform.OS === "android" ? await dataUrlToBlobAndroid(normalized) : await (await fetch(normalized)).blob();
|
|
2999
3082
|
const mimeType = getMimeTypeFromDataUrl(normalized);
|
|
3000
|
-
|
|
3083
|
+
const dimensions = mimeType.startsWith("image/") ? await getImageDimensionsFromDataUrl(normalized) : {};
|
|
3084
|
+
return { blob, idx, mimeType, ...dimensions };
|
|
3001
3085
|
})
|
|
3002
3086
|
);
|
|
3003
|
-
const files = blobs.map(({ blob, mimeType }, idx) => ({
|
|
3087
|
+
const files = blobs.map(({ blob, mimeType, width, height }, idx) => ({
|
|
3004
3088
|
name: `attachment-${Date.now()}-${idx}.png`,
|
|
3005
3089
|
size: blob.size,
|
|
3006
|
-
mimeType
|
|
3090
|
+
mimeType,
|
|
3091
|
+
width,
|
|
3092
|
+
height
|
|
3007
3093
|
}));
|
|
3008
3094
|
const presign = await attachmentRepository.presign({ threadId, appId, files });
|
|
3009
3095
|
await Promise.all(presign.uploads.map((u, index) => attachmentRepository.upload(u, blobs[index].blob)));
|
|
3010
|
-
return presign.uploads.map((u) =>
|
|
3096
|
+
return presign.uploads.map((u, index) => ({
|
|
3097
|
+
...u.attachment,
|
|
3098
|
+
width: blobs[index].width,
|
|
3099
|
+
height: blobs[index].height
|
|
3100
|
+
}));
|
|
3011
3101
|
} catch (e) {
|
|
3012
3102
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
3013
3103
|
setError(err);
|
|
@@ -3026,13 +3116,16 @@ function useAttachmentUpload() {
|
|
|
3026
3116
|
const normalized = dataUrl.startsWith("data:") ? dataUrl : `data:image/png;base64,${dataUrl}`;
|
|
3027
3117
|
const blob = import_react_native6.Platform.OS === "android" ? await dataUrlToBlobAndroid(normalized) : await (await fetch(normalized)).blob();
|
|
3028
3118
|
const mimeType = getMimeTypeFromDataUrl(normalized);
|
|
3029
|
-
|
|
3119
|
+
const dimensions = mimeType.startsWith("image/") ? await getImageDimensionsFromDataUrl(normalized) : {};
|
|
3120
|
+
return { blob, mimeType, ...dimensions };
|
|
3030
3121
|
})
|
|
3031
3122
|
);
|
|
3032
|
-
const files = blobs.map(({ blob, mimeType }, idx) => ({
|
|
3123
|
+
const files = blobs.map(({ blob, mimeType, width, height }, idx) => ({
|
|
3033
3124
|
name: `attachment-${Date.now()}-${idx}.png`,
|
|
3034
3125
|
size: blob.size,
|
|
3035
|
-
mimeType
|
|
3126
|
+
mimeType,
|
|
3127
|
+
width,
|
|
3128
|
+
height
|
|
3036
3129
|
}));
|
|
3037
3130
|
const presign = await attachmentRepository.stagePresign({ files });
|
|
3038
3131
|
await Promise.all(presign.uploads.map((u, index) => attachmentRepository.uploadStaged(u, blobs[index].blob)));
|
|
@@ -3315,8 +3408,8 @@ function RuntimeRenderer({
|
|
|
3315
3408
|
}
|
|
3316
3409
|
|
|
3317
3410
|
// src/studio/ui/StudioOverlay.tsx
|
|
3318
|
-
var
|
|
3319
|
-
var
|
|
3411
|
+
var React47 = __toESM(require("react"));
|
|
3412
|
+
var import_react_native62 = require("react-native");
|
|
3320
3413
|
|
|
3321
3414
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
3322
3415
|
var React12 = __toESM(require("react"));
|
|
@@ -3856,6 +3949,7 @@ function EdgeGlowFrame({
|
|
|
3856
3949
|
role = "accent",
|
|
3857
3950
|
thickness = 40,
|
|
3858
3951
|
intensity = 1,
|
|
3952
|
+
animationDurationMs = 300,
|
|
3859
3953
|
style
|
|
3860
3954
|
}) {
|
|
3861
3955
|
const theme = useTheme();
|
|
@@ -3864,10 +3958,10 @@ function EdgeGlowFrame({
|
|
|
3864
3958
|
React14.useEffect(() => {
|
|
3865
3959
|
import_react_native13.Animated.timing(anim, {
|
|
3866
3960
|
toValue: visible ? 1 : 0,
|
|
3867
|
-
duration:
|
|
3961
|
+
duration: animationDurationMs,
|
|
3868
3962
|
useNativeDriver: true
|
|
3869
3963
|
}).start();
|
|
3870
|
-
}, [anim, visible]);
|
|
3964
|
+
}, [anim, visible, animationDurationMs]);
|
|
3871
3965
|
const c = baseColor(role, theme);
|
|
3872
3966
|
const strong = withAlpha(c, 0.6 * alpha);
|
|
3873
3967
|
const soft = withAlpha(c, 0.22 * alpha);
|
|
@@ -4386,7 +4480,16 @@ function DrawModeOverlay({
|
|
|
4386
4480
|
}, [captureTargetRef, capturing, onCapture]);
|
|
4387
4481
|
if (!visible) return null;
|
|
4388
4482
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native17.View, { style: [import_react_native17.StyleSheet.absoluteFill, styles3.root, style], pointerEvents: "box-none", children: [
|
|
4389
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4483
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4484
|
+
EdgeGlowFrame,
|
|
4485
|
+
{
|
|
4486
|
+
visible: !hideUi,
|
|
4487
|
+
role: "danger",
|
|
4488
|
+
thickness: 50,
|
|
4489
|
+
intensity: 1,
|
|
4490
|
+
animationDurationMs: hideUi ? 0 : 300
|
|
4491
|
+
}
|
|
4492
|
+
),
|
|
4390
4493
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4391
4494
|
DrawSurface,
|
|
4392
4495
|
{
|
|
@@ -5874,7 +5977,10 @@ function PreviewRelatedAppsSection({
|
|
|
5874
5977
|
}) {
|
|
5875
5978
|
var _a;
|
|
5876
5979
|
const theme = useTheme();
|
|
5980
|
+
const { height: windowHeight } = (0, import_react_native35.useWindowDimensions)();
|
|
5877
5981
|
const [relatedAppsOpen, setRelatedAppsOpen] = React27.useState(false);
|
|
5982
|
+
const modalMaxHeight = Math.max(240, windowHeight * 0.5);
|
|
5983
|
+
const modalScrollMaxHeight = Math.max(140, modalMaxHeight - 96);
|
|
5878
5984
|
const relatedAppItems = React27.useMemo(() => {
|
|
5879
5985
|
if (!relatedApps) return [];
|
|
5880
5986
|
const items = [];
|
|
@@ -6007,10 +6113,7 @@ function PreviewRelatedAppsSection({
|
|
|
6007
6113
|
}
|
|
6008
6114
|
)
|
|
6009
6115
|
] }),
|
|
6010
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.
|
|
6011
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native35.View, { style: { minHeight: 20, justifyContent: "center" }, children: item.app.status !== "ready" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PreviewStatusBadge, { status: item.app.status }) : null }),
|
|
6012
|
-
isSwitching ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native35.ActivityIndicator, { size: "small", color: theme.colors.primary }) : null
|
|
6013
|
-
] })
|
|
6116
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native35.View, { style: { alignItems: "flex-end", gap: 6 }, children: isSwitching ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native35.ActivityIndicator, { size: "small", color: theme.colors.primary }) : null })
|
|
6014
6117
|
] })
|
|
6015
6118
|
},
|
|
6016
6119
|
item.app.id
|
|
@@ -6053,17 +6156,35 @@ function PreviewRelatedAppsSection({
|
|
|
6053
6156
|
children: inlineItems.map((item) => renderRelatedCard(item))
|
|
6054
6157
|
}
|
|
6055
6158
|
),
|
|
6056
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6159
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6160
|
+
Modal,
|
|
6161
|
+
{
|
|
6162
|
+
visible: relatedAppsOpen,
|
|
6163
|
+
onRequestClose: closeRelatedApps,
|
|
6164
|
+
contentStyle: { maxHeight: modalMaxHeight, overflow: "hidden" },
|
|
6165
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native35.View, { style: { gap: theme.spacing.sm, minHeight: 0 }, children: [
|
|
6166
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Text, { style: { color: theme.colors.text, fontSize: 18, fontWeight: theme.typography.fontWeight.semibold }, children: "Related apps" }),
|
|
6167
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
6168
|
+
import_react_native35.ScrollView,
|
|
6169
|
+
{
|
|
6170
|
+
style: { maxHeight: modalScrollMaxHeight },
|
|
6171
|
+
contentContainerStyle: { paddingBottom: theme.spacing.xs, gap: theme.spacing.sm },
|
|
6172
|
+
showsVerticalScrollIndicator: true,
|
|
6173
|
+
children: [
|
|
6174
|
+
sectionedRelatedApps.original.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native35.View, { children: [
|
|
6175
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Text, { style: { color: theme.colors.textMuted, marginBottom: theme.spacing.xs }, children: "Original" }),
|
|
6176
|
+
sectionedRelatedApps.original.map((item) => renderRelatedCard(item, { fullWidth: true }))
|
|
6177
|
+
] }) : null,
|
|
6178
|
+
sectionedRelatedApps.remixes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native35.View, { children: [
|
|
6179
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Text, { style: { color: theme.colors.textMuted, marginBottom: theme.spacing.xs }, children: "Remixes" }),
|
|
6180
|
+
sectionedRelatedApps.remixes.map((item) => renderRelatedCard(item, { fullWidth: true }))
|
|
6181
|
+
] }) : null
|
|
6182
|
+
]
|
|
6183
|
+
}
|
|
6184
|
+
)
|
|
6185
|
+
] })
|
|
6186
|
+
}
|
|
6187
|
+
)
|
|
6067
6188
|
] });
|
|
6068
6189
|
}
|
|
6069
6190
|
|
|
@@ -7636,22 +7757,22 @@ ${shareUrl}`;
|
|
|
7636
7757
|
}
|
|
7637
7758
|
|
|
7638
7759
|
// src/studio/ui/ChatPanel.tsx
|
|
7639
|
-
var
|
|
7640
|
-
var
|
|
7760
|
+
var React44 = __toESM(require("react"));
|
|
7761
|
+
var import_react_native59 = require("react-native");
|
|
7641
7762
|
|
|
7642
7763
|
// src/components/chat/ChatPage.tsx
|
|
7643
|
-
var
|
|
7644
|
-
var
|
|
7764
|
+
var React41 = __toESM(require("react"));
|
|
7765
|
+
var import_react_native52 = require("react-native");
|
|
7645
7766
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
7646
7767
|
|
|
7647
7768
|
// src/components/chat/ChatMessageList.tsx
|
|
7648
|
-
var
|
|
7649
|
-
var
|
|
7769
|
+
var React40 = __toESM(require("react"));
|
|
7770
|
+
var import_react_native51 = require("react-native");
|
|
7650
7771
|
var import_bottom_sheet5 = require("@gorhom/bottom-sheet");
|
|
7651
7772
|
|
|
7652
7773
|
// src/components/chat/ChatMessageBubble.tsx
|
|
7653
|
-
var
|
|
7654
|
-
var
|
|
7774
|
+
var React38 = __toESM(require("react"));
|
|
7775
|
+
var import_react_native49 = require("react-native");
|
|
7655
7776
|
var import_lucide_react_native10 = require("lucide-react-native");
|
|
7656
7777
|
|
|
7657
7778
|
// src/components/primitives/Button.tsx
|
|
@@ -7717,19 +7838,261 @@ function Button({
|
|
|
7717
7838
|
);
|
|
7718
7839
|
}
|
|
7719
7840
|
|
|
7720
|
-
// src/components/chat/
|
|
7841
|
+
// src/components/chat/ChatMessageAttachments.tsx
|
|
7842
|
+
var React37 = __toESM(require("react"));
|
|
7843
|
+
var import_react_native48 = require("react-native");
|
|
7844
|
+
var import_expo_image = require("expo-image");
|
|
7721
7845
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
7846
|
+
function ChatMessageAttachments({
|
|
7847
|
+
messageId,
|
|
7848
|
+
attachments,
|
|
7849
|
+
align = "left",
|
|
7850
|
+
onAttachmentLoadError
|
|
7851
|
+
}) {
|
|
7852
|
+
const theme = useTheme();
|
|
7853
|
+
const [viewerVisible, setViewerVisible] = React37.useState(false);
|
|
7854
|
+
const [viewerIndex, setViewerIndex] = React37.useState(0);
|
|
7855
|
+
const failedKeysRef = React37.useRef(/* @__PURE__ */ new Set());
|
|
7856
|
+
const [loadingById, setLoadingById] = React37.useState({});
|
|
7857
|
+
const [modalLoadingById, setModalLoadingById] = React37.useState({});
|
|
7858
|
+
const pulse = React37.useRef(new import_react_native48.Animated.Value(0.45)).current;
|
|
7859
|
+
const imageAttachments = React37.useMemo(
|
|
7860
|
+
() => attachments.filter(
|
|
7861
|
+
(att) => att.mimeType.startsWith("image/") && typeof att.uri === "string" && att.uri.length > 0
|
|
7862
|
+
),
|
|
7863
|
+
[attachments]
|
|
7864
|
+
);
|
|
7865
|
+
const itemHeight = imageAttachments.length === 1 ? 180 : 124;
|
|
7866
|
+
const maxItemWidth = imageAttachments.length === 1 ? 280 : 180;
|
|
7867
|
+
const getAspectRatio = (att) => {
|
|
7868
|
+
const width = typeof att.width === "number" ? att.width : 0;
|
|
7869
|
+
const height = typeof att.height === "number" ? att.height : 0;
|
|
7870
|
+
if (width > 0 && height > 0) {
|
|
7871
|
+
return Math.max(0.35, Math.min(2.4, width / height));
|
|
7872
|
+
}
|
|
7873
|
+
return 0.8;
|
|
7874
|
+
};
|
|
7875
|
+
React37.useEffect(() => {
|
|
7876
|
+
import_react_native48.Animated.loop(
|
|
7877
|
+
import_react_native48.Animated.sequence([
|
|
7878
|
+
import_react_native48.Animated.timing(pulse, { toValue: 0.85, duration: 650, useNativeDriver: true }),
|
|
7879
|
+
import_react_native48.Animated.timing(pulse, { toValue: 0.45, duration: 650, useNativeDriver: true })
|
|
7880
|
+
])
|
|
7881
|
+
).start();
|
|
7882
|
+
}, [pulse]);
|
|
7883
|
+
React37.useEffect(() => {
|
|
7884
|
+
if (imageAttachments.length === 0) {
|
|
7885
|
+
setLoadingById({});
|
|
7886
|
+
setModalLoadingById({});
|
|
7887
|
+
return;
|
|
7888
|
+
}
|
|
7889
|
+
setLoadingById((prev) => {
|
|
7890
|
+
const next = {};
|
|
7891
|
+
for (const att of imageAttachments) {
|
|
7892
|
+
next[att.id] = prev[att.id] ?? true;
|
|
7893
|
+
}
|
|
7894
|
+
return next;
|
|
7895
|
+
});
|
|
7896
|
+
}, [imageAttachments]);
|
|
7897
|
+
React37.useEffect(() => {
|
|
7898
|
+
if (!viewerVisible) return;
|
|
7899
|
+
if (imageAttachments.length === 0) {
|
|
7900
|
+
setModalLoadingById({});
|
|
7901
|
+
return;
|
|
7902
|
+
}
|
|
7903
|
+
setModalLoadingById(() => {
|
|
7904
|
+
const next = {};
|
|
7905
|
+
for (const att of imageAttachments) {
|
|
7906
|
+
next[att.id] = true;
|
|
7907
|
+
}
|
|
7908
|
+
return next;
|
|
7909
|
+
});
|
|
7910
|
+
}, [viewerVisible, imageAttachments]);
|
|
7911
|
+
if (imageAttachments.length === 0) return null;
|
|
7912
|
+
const handleError = (attachmentId) => {
|
|
7913
|
+
const key = `${messageId}:${attachmentId}`;
|
|
7914
|
+
if (failedKeysRef.current.has(key)) return;
|
|
7915
|
+
failedKeysRef.current.add(key);
|
|
7916
|
+
onAttachmentLoadError == null ? void 0 : onAttachmentLoadError(messageId, attachmentId);
|
|
7917
|
+
};
|
|
7918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
7919
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
7920
|
+
import_react_native48.View,
|
|
7921
|
+
{
|
|
7922
|
+
style: {
|
|
7923
|
+
flexDirection: "row",
|
|
7924
|
+
flexWrap: "wrap",
|
|
7925
|
+
justifyContent: align === "right" ? "flex-end" : "flex-start",
|
|
7926
|
+
alignSelf: align === "right" ? "flex-end" : "flex-start",
|
|
7927
|
+
gap: theme.spacing.sm,
|
|
7928
|
+
marginBottom: theme.spacing.sm
|
|
7929
|
+
},
|
|
7930
|
+
children: imageAttachments.map((att, index) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
7931
|
+
import_react_native48.Pressable,
|
|
7932
|
+
{
|
|
7933
|
+
onPress: () => {
|
|
7934
|
+
setViewerIndex(index);
|
|
7935
|
+
setViewerVisible(true);
|
|
7936
|
+
},
|
|
7937
|
+
accessibilityRole: "button",
|
|
7938
|
+
accessibilityLabel: `Attachment ${index + 1} of ${imageAttachments.length}`,
|
|
7939
|
+
style: {
|
|
7940
|
+
height: itemHeight,
|
|
7941
|
+
aspectRatio: getAspectRatio(att),
|
|
7942
|
+
maxWidth: maxItemWidth,
|
|
7943
|
+
borderRadius: theme.radii.lg,
|
|
7944
|
+
overflow: "hidden"
|
|
7945
|
+
},
|
|
7946
|
+
children: [
|
|
7947
|
+
loadingById[att.id] ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
7948
|
+
import_react_native48.Animated.View,
|
|
7949
|
+
{
|
|
7950
|
+
style: {
|
|
7951
|
+
...import_react_native48.StyleSheet.absoluteFillObject,
|
|
7952
|
+
opacity: pulse,
|
|
7953
|
+
backgroundColor: theme.colors.border
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
) : null,
|
|
7957
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
7958
|
+
import_expo_image.Image,
|
|
7959
|
+
{
|
|
7960
|
+
source: { uri: att.uri },
|
|
7961
|
+
style: { width: "100%", height: "100%" },
|
|
7962
|
+
contentFit: "contain",
|
|
7963
|
+
transition: 140,
|
|
7964
|
+
cachePolicy: "memory-disk",
|
|
7965
|
+
onLoadStart: () => {
|
|
7966
|
+
setLoadingById((prev) => ({ ...prev, [att.id]: true }));
|
|
7967
|
+
},
|
|
7968
|
+
onLoadEnd: () => {
|
|
7969
|
+
setLoadingById((prev) => ({ ...prev, [att.id]: false }));
|
|
7970
|
+
},
|
|
7971
|
+
onError: () => handleError(att.id)
|
|
7972
|
+
}
|
|
7973
|
+
)
|
|
7974
|
+
]
|
|
7975
|
+
},
|
|
7976
|
+
att.id
|
|
7977
|
+
))
|
|
7978
|
+
}
|
|
7979
|
+
),
|
|
7980
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_react_native48.Modal, { visible: viewerVisible, transparent: true, animationType: "fade", onRequestClose: () => setViewerVisible(false), children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_react_native48.View, { style: { flex: 1, backgroundColor: "rgba(0,0,0,0.95)" }, children: [
|
|
7981
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
7982
|
+
import_react_native48.View,
|
|
7983
|
+
{
|
|
7984
|
+
style: {
|
|
7985
|
+
position: "absolute",
|
|
7986
|
+
top: 56,
|
|
7987
|
+
right: 16,
|
|
7988
|
+
zIndex: 2
|
|
7989
|
+
},
|
|
7990
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
7991
|
+
import_react_native48.Pressable,
|
|
7992
|
+
{
|
|
7993
|
+
accessibilityRole: "button",
|
|
7994
|
+
accessibilityLabel: "Close attachment viewer",
|
|
7995
|
+
onPress: () => setViewerVisible(false),
|
|
7996
|
+
style: {
|
|
7997
|
+
width: 44,
|
|
7998
|
+
height: 44,
|
|
7999
|
+
borderRadius: 22,
|
|
8000
|
+
alignItems: "center",
|
|
8001
|
+
justifyContent: "center",
|
|
8002
|
+
backgroundColor: "rgba(255,255,255,0.15)"
|
|
8003
|
+
},
|
|
8004
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(IconClose, { size: 18, colorToken: "onPrimary" })
|
|
8005
|
+
}
|
|
8006
|
+
)
|
|
8007
|
+
}
|
|
8008
|
+
),
|
|
8009
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
8010
|
+
import_react_native48.FlatList,
|
|
8011
|
+
{
|
|
8012
|
+
data: imageAttachments,
|
|
8013
|
+
horizontal: true,
|
|
8014
|
+
pagingEnabled: true,
|
|
8015
|
+
initialScrollIndex: viewerIndex,
|
|
8016
|
+
keyExtractor: (item) => item.id,
|
|
8017
|
+
showsHorizontalScrollIndicator: false,
|
|
8018
|
+
getItemLayout: (_, index) => {
|
|
8019
|
+
const width = import_react_native48.Dimensions.get("window").width;
|
|
8020
|
+
return { length: width, offset: width * index, index };
|
|
8021
|
+
},
|
|
8022
|
+
renderItem: ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_react_native48.View, { style: { width: import_react_native48.Dimensions.get("window").width, height: "100%", justifyContent: "center" }, children: [
|
|
8023
|
+
modalLoadingById[item.id] ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
8024
|
+
import_react_native48.Animated.View,
|
|
8025
|
+
{
|
|
8026
|
+
style: {
|
|
8027
|
+
...import_react_native48.StyleSheet.absoluteFillObject,
|
|
8028
|
+
opacity: pulse,
|
|
8029
|
+
backgroundColor: theme.colors.border
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
) : null,
|
|
8033
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
8034
|
+
import_expo_image.Image,
|
|
8035
|
+
{
|
|
8036
|
+
source: { uri: item.uri },
|
|
8037
|
+
style: { width: "100%", height: "78%" },
|
|
8038
|
+
contentFit: "contain",
|
|
8039
|
+
transition: 140,
|
|
8040
|
+
cachePolicy: "memory-disk",
|
|
8041
|
+
onLoadStart: () => {
|
|
8042
|
+
setModalLoadingById((prev) => ({ ...prev, [item.id]: true }));
|
|
8043
|
+
},
|
|
8044
|
+
onLoadEnd: () => {
|
|
8045
|
+
setModalLoadingById((prev) => ({ ...prev, [item.id]: false }));
|
|
8046
|
+
},
|
|
8047
|
+
onError: () => handleError(item.id)
|
|
8048
|
+
}
|
|
8049
|
+
),
|
|
8050
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
8051
|
+
Text,
|
|
8052
|
+
{
|
|
8053
|
+
variant: "caption",
|
|
8054
|
+
color: "#FFFFFF",
|
|
8055
|
+
style: { textAlign: "center", marginTop: theme.spacing.sm },
|
|
8056
|
+
children: [
|
|
8057
|
+
index + 1,
|
|
8058
|
+
" / ",
|
|
8059
|
+
imageAttachments.length
|
|
8060
|
+
]
|
|
8061
|
+
}
|
|
8062
|
+
)
|
|
8063
|
+
] })
|
|
8064
|
+
}
|
|
8065
|
+
)
|
|
8066
|
+
] }) })
|
|
8067
|
+
] });
|
|
8068
|
+
}
|
|
8069
|
+
|
|
8070
|
+
// src/components/chat/ChatMessageBubble.tsx
|
|
8071
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
7722
8072
|
function areMessageMetaEqual(a, b) {
|
|
7723
8073
|
if (a === b) return true;
|
|
7724
8074
|
if (!a || !b) return a === b;
|
|
7725
8075
|
return a.kind === b.kind && a.event === b.event && a.status === b.status && a.mergeRequestId === b.mergeRequestId && a.sourceAppId === b.sourceAppId && a.targetAppId === b.targetAppId && a.appId === b.appId && a.threadId === b.threadId;
|
|
7726
8076
|
}
|
|
8077
|
+
function areMessageAttachmentsEqual(a, b) {
|
|
8078
|
+
if (a === b) return true;
|
|
8079
|
+
const left = a ?? [];
|
|
8080
|
+
const right = b ?? [];
|
|
8081
|
+
if (left.length !== right.length) return false;
|
|
8082
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
8083
|
+
if (left[i].id !== right[i].id || left[i].name !== right[i].name || left[i].mimeType !== right[i].mimeType || left[i].size !== right[i].size || left[i].uri !== right[i].uri || left[i].width !== right[i].width || left[i].height !== right[i].height) {
|
|
8084
|
+
return false;
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
return true;
|
|
8088
|
+
}
|
|
7727
8089
|
function ChatMessageBubbleInner({
|
|
7728
8090
|
message,
|
|
7729
8091
|
renderContent,
|
|
7730
8092
|
isLast,
|
|
7731
8093
|
retrying,
|
|
7732
8094
|
onRetryMessage,
|
|
8095
|
+
onAttachmentLoadError,
|
|
7733
8096
|
style
|
|
7734
8097
|
}) {
|
|
7735
8098
|
var _a, _b;
|
|
@@ -7748,11 +8111,36 @@ function ChatMessageBubbleInner({
|
|
|
7748
8111
|
const bodyColor = metaStatus === "success" ? theme.colors.success : metaStatus === "error" ? theme.colors.danger : void 0;
|
|
7749
8112
|
const showRetry = Boolean(onRetryMessage) && isLast && metaStatus === "error" && message.author === "human";
|
|
7750
8113
|
const retryLabel = retrying ? "Retrying..." : "Retry";
|
|
7751
|
-
const
|
|
8114
|
+
const hasText = message.content.trim().length > 0;
|
|
8115
|
+
const attachments = message.attachments ?? [];
|
|
8116
|
+
const hasAttachments = attachments.length > 0;
|
|
8117
|
+
const hasStatusIcon = isMergeCompleted || isSyncCompleted || isMergeApproved || isSyncStarted;
|
|
8118
|
+
const shouldRenderBubble = hasText || hasStatusIcon;
|
|
8119
|
+
const handleRetryPress = React38.useCallback(() => {
|
|
7752
8120
|
onRetryMessage == null ? void 0 : onRetryMessage(message.id);
|
|
7753
8121
|
}, [message.id, onRetryMessage]);
|
|
7754
|
-
return /* @__PURE__ */ (0,
|
|
7755
|
-
/* @__PURE__ */ (0,
|
|
8122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native49.View, { style: [align, style], children: [
|
|
8123
|
+
hasAttachments ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
8124
|
+
import_react_native49.View,
|
|
8125
|
+
{
|
|
8126
|
+
style: {
|
|
8127
|
+
maxWidth: "85%",
|
|
8128
|
+
marginBottom: shouldRenderBubble ? theme.spacing.xs : 0,
|
|
8129
|
+
alignSelf: isHuman ? "flex-end" : "flex-start",
|
|
8130
|
+
alignItems: isHuman ? "flex-end" : "flex-start"
|
|
8131
|
+
},
|
|
8132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
8133
|
+
ChatMessageAttachments,
|
|
8134
|
+
{
|
|
8135
|
+
messageId: message.id,
|
|
8136
|
+
attachments,
|
|
8137
|
+
align: isHuman ? "right" : "left",
|
|
8138
|
+
onAttachmentLoadError
|
|
8139
|
+
}
|
|
8140
|
+
)
|
|
8141
|
+
}
|
|
8142
|
+
) : null,
|
|
8143
|
+
shouldRenderBubble ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
7756
8144
|
Surface,
|
|
7757
8145
|
{
|
|
7758
8146
|
variant: bubbleVariant,
|
|
@@ -7767,14 +8155,14 @@ function ChatMessageBubbleInner({
|
|
|
7767
8155
|
},
|
|
7768
8156
|
cornerStyle
|
|
7769
8157
|
],
|
|
7770
|
-
children: /* @__PURE__ */ (0,
|
|
7771
|
-
isMergeCompleted || isSyncCompleted ? /* @__PURE__ */ (0,
|
|
7772
|
-
isMergeApproved || isSyncStarted ? /* @__PURE__ */ (0,
|
|
7773
|
-
/* @__PURE__ */ (0,
|
|
8158
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native49.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8159
|
+
isMergeCompleted || isSyncCompleted ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react_native10.CheckCheck, { size: 16, color: theme.colors.success, style: { marginRight: theme.spacing.sm } }) : null,
|
|
8160
|
+
isMergeApproved || isSyncStarted ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react_native10.GitMerge, { size: 16, color: theme.colors.text, style: { marginRight: theme.spacing.sm } }) : null,
|
|
8161
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_native49.View, { style: { flexShrink: 1, minWidth: 0 }, children: renderContent ? renderContent(message) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MarkdownText, { markdown: message.content, variant: "chat", bodyColor }) })
|
|
7774
8162
|
] })
|
|
7775
8163
|
}
|
|
7776
|
-
),
|
|
7777
|
-
showRetry ? /* @__PURE__ */ (0,
|
|
8164
|
+
) : null,
|
|
8165
|
+
showRetry ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_native49.View, { style: { marginTop: theme.spacing.xs, alignSelf: align.alignSelf }, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
7778
8166
|
Button,
|
|
7779
8167
|
{
|
|
7780
8168
|
variant: "ghost",
|
|
@@ -7783,9 +8171,9 @@ function ChatMessageBubbleInner({
|
|
|
7783
8171
|
disabled: retrying,
|
|
7784
8172
|
style: { borderColor: theme.colors.danger },
|
|
7785
8173
|
accessibilityLabel: "Retry send",
|
|
7786
|
-
children: /* @__PURE__ */ (0,
|
|
7787
|
-
!retrying ? /* @__PURE__ */ (0,
|
|
7788
|
-
/* @__PURE__ */ (0,
|
|
8174
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native49.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8175
|
+
!retrying ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react_native10.RotateCcw, { size: 14, color: theme.colors.danger }) : null,
|
|
8176
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
7789
8177
|
Text,
|
|
7790
8178
|
{
|
|
7791
8179
|
variant: "caption",
|
|
@@ -7801,30 +8189,30 @@ function ChatMessageBubbleInner({
|
|
|
7801
8189
|
] });
|
|
7802
8190
|
}
|
|
7803
8191
|
function areEqual(prev, next) {
|
|
7804
|
-
return prev.message.id === next.message.id && prev.message.author === next.message.author && prev.message.content === next.message.content && prev.message.kind === next.message.kind && String(prev.message.createdAt) === String(next.message.createdAt) && areMessageMetaEqual(prev.message.meta, next.message.meta) && prev.renderContent === next.renderContent && prev.isLast === next.isLast && prev.retrying === next.retrying && prev.onRetryMessage === next.onRetryMessage && prev.style === next.style;
|
|
8192
|
+
return prev.message.id === next.message.id && prev.message.author === next.message.author && prev.message.content === next.message.content && areMessageAttachmentsEqual(prev.message.attachments, next.message.attachments) && prev.message.kind === next.message.kind && String(prev.message.createdAt) === String(next.message.createdAt) && areMessageMetaEqual(prev.message.meta, next.message.meta) && prev.renderContent === next.renderContent && prev.isLast === next.isLast && prev.retrying === next.retrying && prev.onRetryMessage === next.onRetryMessage && prev.onAttachmentLoadError === next.onAttachmentLoadError && prev.style === next.style;
|
|
7805
8193
|
}
|
|
7806
|
-
var ChatMessageBubble =
|
|
8194
|
+
var ChatMessageBubble = React38.memo(ChatMessageBubbleInner, areEqual);
|
|
7807
8195
|
ChatMessageBubble.displayName = "ChatMessageBubble";
|
|
7808
8196
|
|
|
7809
8197
|
// src/components/chat/TypingIndicator.tsx
|
|
7810
|
-
var
|
|
7811
|
-
var
|
|
7812
|
-
var
|
|
8198
|
+
var React39 = __toESM(require("react"));
|
|
8199
|
+
var import_react_native50 = require("react-native");
|
|
8200
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
7813
8201
|
function TypingIndicator({ style }) {
|
|
7814
8202
|
const theme = useTheme();
|
|
7815
8203
|
const dotColor = theme.colors.textSubtle;
|
|
7816
|
-
const anims =
|
|
7817
|
-
() => [new
|
|
8204
|
+
const anims = React39.useMemo(
|
|
8205
|
+
() => [new import_react_native50.Animated.Value(0.3), new import_react_native50.Animated.Value(0.3), new import_react_native50.Animated.Value(0.3)],
|
|
7818
8206
|
[]
|
|
7819
8207
|
);
|
|
7820
|
-
|
|
8208
|
+
React39.useEffect(() => {
|
|
7821
8209
|
const loops = [];
|
|
7822
8210
|
anims.forEach((a, idx) => {
|
|
7823
|
-
const seq =
|
|
7824
|
-
|
|
7825
|
-
|
|
8211
|
+
const seq = import_react_native50.Animated.sequence([
|
|
8212
|
+
import_react_native50.Animated.timing(a, { toValue: 1, duration: 420, useNativeDriver: true, delay: idx * 140 }),
|
|
8213
|
+
import_react_native50.Animated.timing(a, { toValue: 0.3, duration: 420, useNativeDriver: true })
|
|
7826
8214
|
]);
|
|
7827
|
-
const loop =
|
|
8215
|
+
const loop = import_react_native50.Animated.loop(seq);
|
|
7828
8216
|
loops.push(loop);
|
|
7829
8217
|
loop.start();
|
|
7830
8218
|
});
|
|
@@ -7832,8 +8220,8 @@ function TypingIndicator({ style }) {
|
|
|
7832
8220
|
loops.forEach((l) => l.stop());
|
|
7833
8221
|
};
|
|
7834
8222
|
}, [anims]);
|
|
7835
|
-
return /* @__PURE__ */ (0,
|
|
7836
|
-
|
|
8223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native50.View, { style: [{ flexDirection: "row", alignItems: "center" }, style], children: anims.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
8224
|
+
import_react_native50.Animated.View,
|
|
7837
8225
|
{
|
|
7838
8226
|
style: {
|
|
7839
8227
|
width: 8,
|
|
@@ -7842,7 +8230,7 @@ function TypingIndicator({ style }) {
|
|
|
7842
8230
|
marginHorizontal: 3,
|
|
7843
8231
|
backgroundColor: dotColor,
|
|
7844
8232
|
opacity: a,
|
|
7845
|
-
transform: [{ translateY:
|
|
8233
|
+
transform: [{ translateY: import_react_native50.Animated.multiply(import_react_native50.Animated.subtract(a, 0.3), 2) }]
|
|
7846
8234
|
}
|
|
7847
8235
|
},
|
|
7848
8236
|
i
|
|
@@ -7850,36 +8238,37 @@ function TypingIndicator({ style }) {
|
|
|
7850
8238
|
}
|
|
7851
8239
|
|
|
7852
8240
|
// src/components/chat/ChatMessageList.tsx
|
|
7853
|
-
var
|
|
7854
|
-
var ChatMessageList =
|
|
8241
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
8242
|
+
var ChatMessageList = React40.forwardRef(
|
|
7855
8243
|
({
|
|
7856
8244
|
messages,
|
|
7857
8245
|
showTypingIndicator = false,
|
|
7858
8246
|
renderMessageContent,
|
|
7859
8247
|
onRetryMessage,
|
|
7860
8248
|
isRetryingMessage,
|
|
8249
|
+
onAttachmentLoadError,
|
|
7861
8250
|
contentStyle,
|
|
7862
8251
|
bottomInset = 0,
|
|
7863
8252
|
onNearBottomChange,
|
|
7864
8253
|
nearBottomThreshold = 200
|
|
7865
8254
|
}, ref) => {
|
|
7866
8255
|
const theme = useTheme();
|
|
7867
|
-
const listRef =
|
|
7868
|
-
const nearBottomRef =
|
|
7869
|
-
const initialScrollDoneRef =
|
|
7870
|
-
const lastMessageIdRef =
|
|
7871
|
-
const data =
|
|
8256
|
+
const listRef = React40.useRef(null);
|
|
8257
|
+
const nearBottomRef = React40.useRef(true);
|
|
8258
|
+
const initialScrollDoneRef = React40.useRef(false);
|
|
8259
|
+
const lastMessageIdRef = React40.useRef(null);
|
|
8260
|
+
const data = React40.useMemo(() => {
|
|
7872
8261
|
return [...messages].reverse();
|
|
7873
8262
|
}, [messages]);
|
|
7874
8263
|
const lastMessageId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
7875
|
-
const keyExtractor =
|
|
7876
|
-
const scrollToBottom =
|
|
8264
|
+
const keyExtractor = React40.useCallback((m) => m.id, []);
|
|
8265
|
+
const scrollToBottom = React40.useCallback((options) => {
|
|
7877
8266
|
var _a;
|
|
7878
8267
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
7879
8268
|
(_a = listRef.current) == null ? void 0 : _a.scrollToOffset({ offset: 0, animated });
|
|
7880
8269
|
}, []);
|
|
7881
|
-
|
|
7882
|
-
const handleScroll =
|
|
8270
|
+
React40.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
|
|
8271
|
+
const handleScroll = React40.useCallback(
|
|
7883
8272
|
(e) => {
|
|
7884
8273
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
7885
8274
|
const distanceFromBottom = Math.max(contentOffset.y - Math.max(bottomInset, 0), 0);
|
|
@@ -7891,7 +8280,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7891
8280
|
},
|
|
7892
8281
|
[bottomInset, nearBottomThreshold, onNearBottomChange]
|
|
7893
8282
|
);
|
|
7894
|
-
|
|
8283
|
+
React40.useEffect(() => {
|
|
7895
8284
|
if (!initialScrollDoneRef.current) return;
|
|
7896
8285
|
const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
7897
8286
|
const prevLastId = lastMessageIdRef.current;
|
|
@@ -7901,14 +8290,14 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7901
8290
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
7902
8291
|
return () => cancelAnimationFrame(id);
|
|
7903
8292
|
}, [messages, scrollToBottom]);
|
|
7904
|
-
|
|
8293
|
+
React40.useEffect(() => {
|
|
7905
8294
|
if (showTypingIndicator && nearBottomRef.current) {
|
|
7906
8295
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
7907
8296
|
return () => cancelAnimationFrame(id);
|
|
7908
8297
|
}
|
|
7909
8298
|
return void 0;
|
|
7910
8299
|
}, [showTypingIndicator, scrollToBottom]);
|
|
7911
|
-
const handleContentSizeChange =
|
|
8300
|
+
const handleContentSizeChange = React40.useCallback(() => {
|
|
7912
8301
|
if (initialScrollDoneRef.current) return;
|
|
7913
8302
|
initialScrollDoneRef.current = true;
|
|
7914
8303
|
lastMessageIdRef.current = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
@@ -7916,7 +8305,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7916
8305
|
onNearBottomChange == null ? void 0 : onNearBottomChange(true);
|
|
7917
8306
|
requestAnimationFrame(() => scrollToBottom({ animated: false }));
|
|
7918
8307
|
}, [messages, onNearBottomChange, scrollToBottom]);
|
|
7919
|
-
const contentContainerStyle =
|
|
8308
|
+
const contentContainerStyle = React40.useMemo(
|
|
7920
8309
|
() => [
|
|
7921
8310
|
{
|
|
7922
8311
|
paddingHorizontal: theme.spacing.lg,
|
|
@@ -7926,28 +8315,29 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7926
8315
|
],
|
|
7927
8316
|
[contentStyle, theme.spacing.lg, theme.spacing.sm]
|
|
7928
8317
|
);
|
|
7929
|
-
const renderSeparator =
|
|
7930
|
-
const listHeader =
|
|
7931
|
-
() => /* @__PURE__ */ (0,
|
|
7932
|
-
showTypingIndicator ? /* @__PURE__ */ (0,
|
|
7933
|
-
bottomInset > 0 ? /* @__PURE__ */ (0,
|
|
8318
|
+
const renderSeparator = React40.useCallback(() => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native51.View, { style: { height: theme.spacing.sm } }), [theme.spacing.sm]);
|
|
8319
|
+
const listHeader = React40.useMemo(
|
|
8320
|
+
() => /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_react_native51.View, { children: [
|
|
8321
|
+
showTypingIndicator ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native51.View, { style: { marginTop: theme.spacing.sm, alignSelf: "flex-start", paddingHorizontal: theme.spacing.lg }, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(TypingIndicator, {}) }) : null,
|
|
8322
|
+
bottomInset > 0 ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native51.View, { style: { height: bottomInset } }) : null
|
|
7934
8323
|
] }),
|
|
7935
8324
|
[bottomInset, showTypingIndicator, theme.spacing.lg, theme.spacing.sm]
|
|
7936
8325
|
);
|
|
7937
|
-
const renderItem =
|
|
7938
|
-
({ item }) => /* @__PURE__ */ (0,
|
|
8326
|
+
const renderItem = React40.useCallback(
|
|
8327
|
+
({ item }) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
7939
8328
|
ChatMessageBubble,
|
|
7940
8329
|
{
|
|
7941
8330
|
message: item,
|
|
7942
8331
|
renderContent: renderMessageContent,
|
|
7943
8332
|
isLast: Boolean(lastMessageId && item.id === lastMessageId),
|
|
7944
8333
|
retrying: (isRetryingMessage == null ? void 0 : isRetryingMessage(item.id)) ?? false,
|
|
7945
|
-
onRetryMessage
|
|
8334
|
+
onRetryMessage,
|
|
8335
|
+
onAttachmentLoadError
|
|
7946
8336
|
}
|
|
7947
8337
|
),
|
|
7948
|
-
[isRetryingMessage, lastMessageId, onRetryMessage, renderMessageContent]
|
|
8338
|
+
[isRetryingMessage, lastMessageId, onAttachmentLoadError, onRetryMessage, renderMessageContent]
|
|
7949
8339
|
);
|
|
7950
|
-
return /* @__PURE__ */ (0,
|
|
8340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
7951
8341
|
import_bottom_sheet5.BottomSheetFlatList,
|
|
7952
8342
|
{
|
|
7953
8343
|
ref: listRef,
|
|
@@ -7970,7 +8360,7 @@ var ChatMessageList = React39.forwardRef(
|
|
|
7970
8360
|
ChatMessageList.displayName = "ChatMessageList";
|
|
7971
8361
|
|
|
7972
8362
|
// src/components/chat/ChatPage.tsx
|
|
7973
|
-
var
|
|
8363
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
7974
8364
|
function ChatPage({
|
|
7975
8365
|
header,
|
|
7976
8366
|
messages,
|
|
@@ -7978,6 +8368,7 @@ function ChatPage({
|
|
|
7978
8368
|
renderMessageContent,
|
|
7979
8369
|
onRetryMessage,
|
|
7980
8370
|
isRetryingMessage,
|
|
8371
|
+
onAttachmentLoadError,
|
|
7981
8372
|
topBanner,
|
|
7982
8373
|
composerTop,
|
|
7983
8374
|
composer,
|
|
@@ -7989,35 +8380,35 @@ function ChatPage({
|
|
|
7989
8380
|
}) {
|
|
7990
8381
|
const theme = useTheme();
|
|
7991
8382
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
7992
|
-
const [composerHeight, setComposerHeight] =
|
|
7993
|
-
const [composerTopHeight, setComposerTopHeight] =
|
|
7994
|
-
const footerBottomPadding =
|
|
8383
|
+
const [composerHeight, setComposerHeight] = React41.useState(0);
|
|
8384
|
+
const [composerTopHeight, setComposerTopHeight] = React41.useState(0);
|
|
8385
|
+
const footerBottomPadding = import_react_native52.Platform.OS === "ios" ? insets.bottom - 24 : insets.bottom + 10;
|
|
7995
8386
|
const totalComposerHeight = composerHeight + composerTopHeight;
|
|
7996
8387
|
const overlayBottom = totalComposerHeight + footerBottomPadding + theme.spacing.lg;
|
|
7997
8388
|
const bottomInset = totalComposerHeight + footerBottomPadding + theme.spacing.xl;
|
|
7998
|
-
const resolvedOverlay =
|
|
8389
|
+
const resolvedOverlay = React41.useMemo(() => {
|
|
7999
8390
|
var _a;
|
|
8000
8391
|
if (!overlay) return null;
|
|
8001
|
-
if (!
|
|
8392
|
+
if (!React41.isValidElement(overlay)) return overlay;
|
|
8002
8393
|
const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
|
|
8003
|
-
return
|
|
8394
|
+
return React41.cloneElement(overlay, {
|
|
8004
8395
|
style: [prevStyle, { bottom: overlayBottom }]
|
|
8005
8396
|
});
|
|
8006
8397
|
}, [overlay, overlayBottom]);
|
|
8007
|
-
|
|
8398
|
+
React41.useEffect(() => {
|
|
8008
8399
|
if (composerTop) return;
|
|
8009
8400
|
setComposerTopHeight(0);
|
|
8010
8401
|
}, [composerTop]);
|
|
8011
|
-
return /* @__PURE__ */ (0,
|
|
8012
|
-
header ? /* @__PURE__ */ (0,
|
|
8013
|
-
topBanner ? /* @__PURE__ */ (0,
|
|
8014
|
-
/* @__PURE__ */ (0,
|
|
8015
|
-
/* @__PURE__ */ (0,
|
|
8016
|
-
|
|
8402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native52.View, { style: [{ flex: 1 }, style], children: [
|
|
8403
|
+
header ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native52.View, { children: header }) : null,
|
|
8404
|
+
topBanner ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_react_native52.View, { style: { paddingHorizontal: theme.spacing.lg, paddingTop: theme.spacing.sm }, children: topBanner }) : null,
|
|
8405
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native52.View, { style: { flex: 1 }, children: [
|
|
8406
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8407
|
+
import_react_native52.View,
|
|
8017
8408
|
{
|
|
8018
8409
|
style: { flex: 1 },
|
|
8019
8410
|
children: [
|
|
8020
|
-
/* @__PURE__ */ (0,
|
|
8411
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8021
8412
|
ChatMessageList,
|
|
8022
8413
|
{
|
|
8023
8414
|
ref: listRef,
|
|
@@ -8026,6 +8417,7 @@ function ChatPage({
|
|
|
8026
8417
|
renderMessageContent,
|
|
8027
8418
|
onRetryMessage,
|
|
8028
8419
|
isRetryingMessage,
|
|
8420
|
+
onAttachmentLoadError,
|
|
8029
8421
|
onNearBottomChange,
|
|
8030
8422
|
bottomInset
|
|
8031
8423
|
}
|
|
@@ -8034,8 +8426,8 @@ function ChatPage({
|
|
|
8034
8426
|
]
|
|
8035
8427
|
}
|
|
8036
8428
|
),
|
|
8037
|
-
/* @__PURE__ */ (0,
|
|
8038
|
-
|
|
8429
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
8430
|
+
import_react_native52.View,
|
|
8039
8431
|
{
|
|
8040
8432
|
style: {
|
|
8041
8433
|
position: "absolute",
|
|
@@ -8047,15 +8439,15 @@ function ChatPage({
|
|
|
8047
8439
|
paddingBottom: footerBottomPadding
|
|
8048
8440
|
},
|
|
8049
8441
|
children: [
|
|
8050
|
-
composerTop ? /* @__PURE__ */ (0,
|
|
8051
|
-
|
|
8442
|
+
composerTop ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8443
|
+
import_react_native52.View,
|
|
8052
8444
|
{
|
|
8053
8445
|
style: { marginBottom: theme.spacing.sm },
|
|
8054
8446
|
onLayout: (e) => setComposerTopHeight(e.nativeEvent.layout.height),
|
|
8055
8447
|
children: composerTop
|
|
8056
8448
|
}
|
|
8057
8449
|
) : null,
|
|
8058
|
-
/* @__PURE__ */ (0,
|
|
8450
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
8059
8451
|
ChatComposer,
|
|
8060
8452
|
{
|
|
8061
8453
|
...composer,
|
|
@@ -8071,15 +8463,15 @@ function ChatPage({
|
|
|
8071
8463
|
}
|
|
8072
8464
|
|
|
8073
8465
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
8074
|
-
var
|
|
8075
|
-
var
|
|
8466
|
+
var React42 = __toESM(require("react"));
|
|
8467
|
+
var import_react_native53 = require("react-native");
|
|
8076
8468
|
var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
|
|
8077
|
-
var
|
|
8469
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
8078
8470
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
8079
8471
|
const theme = useTheme();
|
|
8080
8472
|
const progress = (0, import_react_native_reanimated2.useSharedValue)(visible ? 1 : 0);
|
|
8081
|
-
const [pressed, setPressed] =
|
|
8082
|
-
|
|
8473
|
+
const [pressed, setPressed] = React42.useState(false);
|
|
8474
|
+
React42.useEffect(() => {
|
|
8083
8475
|
progress.value = (0, import_react_native_reanimated2.withTiming)(visible ? 1 : 0, { duration: 200, easing: import_react_native_reanimated2.Easing.out(import_react_native_reanimated2.Easing.ease) });
|
|
8084
8476
|
}, [progress, visible]);
|
|
8085
8477
|
const animStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => ({
|
|
@@ -8088,7 +8480,7 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8088
8480
|
}));
|
|
8089
8481
|
const bg = theme.scheme === "dark" ? "rgba(39,39,42,0.9)" : "rgba(244,244,245,0.95)";
|
|
8090
8482
|
const border = theme.scheme === "dark" ? withAlpha("#FFFFFF", 0.12) : withAlpha("#000000", 0.08);
|
|
8091
|
-
return /* @__PURE__ */ (0,
|
|
8483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
8092
8484
|
import_react_native_reanimated2.default.View,
|
|
8093
8485
|
{
|
|
8094
8486
|
pointerEvents: visible ? "auto" : "none",
|
|
@@ -8102,8 +8494,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8102
8494
|
style,
|
|
8103
8495
|
animStyle
|
|
8104
8496
|
],
|
|
8105
|
-
children: /* @__PURE__ */ (0,
|
|
8106
|
-
|
|
8497
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
8498
|
+
import_react_native53.View,
|
|
8107
8499
|
{
|
|
8108
8500
|
style: {
|
|
8109
8501
|
width: 44,
|
|
@@ -8121,8 +8513,8 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8121
8513
|
elevation: 5,
|
|
8122
8514
|
opacity: pressed ? 0.85 : 1
|
|
8123
8515
|
},
|
|
8124
|
-
children: /* @__PURE__ */ (0,
|
|
8125
|
-
|
|
8516
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
8517
|
+
import_react_native53.Pressable,
|
|
8126
8518
|
{
|
|
8127
8519
|
onPress,
|
|
8128
8520
|
onPressIn: () => setPressed(true),
|
|
@@ -8139,16 +8531,16 @@ function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
|
8139
8531
|
}
|
|
8140
8532
|
|
|
8141
8533
|
// src/components/chat/ChatHeader.tsx
|
|
8142
|
-
var
|
|
8143
|
-
var
|
|
8534
|
+
var import_react_native54 = require("react-native");
|
|
8535
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
8144
8536
|
function ChatHeader({ left, right, center, style }) {
|
|
8145
|
-
const flattenedStyle =
|
|
8537
|
+
const flattenedStyle = import_react_native54.StyleSheet.flatten([
|
|
8146
8538
|
{
|
|
8147
8539
|
paddingTop: 0
|
|
8148
8540
|
},
|
|
8149
8541
|
style
|
|
8150
8542
|
]);
|
|
8151
|
-
return /* @__PURE__ */ (0,
|
|
8543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
8152
8544
|
StudioSheetHeader,
|
|
8153
8545
|
{
|
|
8154
8546
|
left,
|
|
@@ -8160,13 +8552,13 @@ function ChatHeader({ left, right, center, style }) {
|
|
|
8160
8552
|
}
|
|
8161
8553
|
|
|
8162
8554
|
// src/components/chat/ForkNoticeBanner.tsx
|
|
8163
|
-
var
|
|
8164
|
-
var
|
|
8555
|
+
var import_react_native55 = require("react-native");
|
|
8556
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
8165
8557
|
function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
8166
8558
|
const theme = useTheme();
|
|
8167
8559
|
const resolvedTitle = title ?? (isOwner ? "Remixed app" : "Remix app");
|
|
8168
8560
|
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.");
|
|
8169
|
-
return /* @__PURE__ */ (0,
|
|
8561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
8170
8562
|
Card,
|
|
8171
8563
|
{
|
|
8172
8564
|
variant: "surfaceRaised",
|
|
@@ -8181,8 +8573,8 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8181
8573
|
},
|
|
8182
8574
|
style
|
|
8183
8575
|
],
|
|
8184
|
-
children: /* @__PURE__ */ (0,
|
|
8185
|
-
/* @__PURE__ */ (0,
|
|
8576
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native55.View, { style: { minWidth: 0 }, children: [
|
|
8577
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
8186
8578
|
Text,
|
|
8187
8579
|
{
|
|
8188
8580
|
style: {
|
|
@@ -8196,7 +8588,7 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8196
8588
|
children: resolvedTitle
|
|
8197
8589
|
}
|
|
8198
8590
|
),
|
|
8199
|
-
/* @__PURE__ */ (0,
|
|
8591
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
8200
8592
|
Text,
|
|
8201
8593
|
{
|
|
8202
8594
|
style: {
|
|
@@ -8214,16 +8606,16 @@ function ForkNoticeBanner({ isOwner = true, title, description, style }) {
|
|
|
8214
8606
|
}
|
|
8215
8607
|
|
|
8216
8608
|
// src/components/chat/ChatQueue.tsx
|
|
8217
|
-
var
|
|
8218
|
-
var
|
|
8219
|
-
var
|
|
8609
|
+
var React43 = __toESM(require("react"));
|
|
8610
|
+
var import_react_native56 = require("react-native");
|
|
8611
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
8220
8612
|
function ChatQueue({ items, onRemove }) {
|
|
8221
8613
|
const theme = useTheme();
|
|
8222
|
-
const [expanded, setExpanded] =
|
|
8223
|
-
const [canExpand, setCanExpand] =
|
|
8224
|
-
const [collapsedText, setCollapsedText] =
|
|
8225
|
-
const [removing, setRemoving] =
|
|
8226
|
-
const buildCollapsedText =
|
|
8614
|
+
const [expanded, setExpanded] = React43.useState({});
|
|
8615
|
+
const [canExpand, setCanExpand] = React43.useState({});
|
|
8616
|
+
const [collapsedText, setCollapsedText] = React43.useState({});
|
|
8617
|
+
const [removing, setRemoving] = React43.useState({});
|
|
8618
|
+
const buildCollapsedText = React43.useCallback((lines) => {
|
|
8227
8619
|
var _a, _b;
|
|
8228
8620
|
const line1 = ((_a = lines[0]) == null ? void 0 : _a.text) ?? "";
|
|
8229
8621
|
const line2 = ((_b = lines[1]) == null ? void 0 : _b.text) ?? "";
|
|
@@ -8239,7 +8631,7 @@ function ChatQueue({ items, onRemove }) {
|
|
|
8239
8631
|
return `${line1}
|
|
8240
8632
|
${trimmedLine2}\u2026 `;
|
|
8241
8633
|
}, []);
|
|
8242
|
-
|
|
8634
|
+
React43.useEffect(() => {
|
|
8243
8635
|
if (items.length === 0) return;
|
|
8244
8636
|
const ids = new Set(items.map((item) => item.id));
|
|
8245
8637
|
setExpanded((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
|
|
@@ -8248,8 +8640,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
8248
8640
|
setRemoving((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))));
|
|
8249
8641
|
}, [items]);
|
|
8250
8642
|
if (items.length === 0) return null;
|
|
8251
|
-
return /* @__PURE__ */ (0,
|
|
8252
|
-
|
|
8643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
8644
|
+
import_react_native56.View,
|
|
8253
8645
|
{
|
|
8254
8646
|
style: {
|
|
8255
8647
|
borderWidth: 1,
|
|
@@ -8260,16 +8652,16 @@ ${trimmedLine2}\u2026 `;
|
|
|
8260
8652
|
backgroundColor: "transparent"
|
|
8261
8653
|
},
|
|
8262
8654
|
children: [
|
|
8263
|
-
/* @__PURE__ */ (0,
|
|
8264
|
-
/* @__PURE__ */ (0,
|
|
8655
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Text, { variant: "caption", style: { marginBottom: theme.spacing.sm }, children: "Queue" }),
|
|
8656
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native56.View, { style: { gap: theme.spacing.sm }, children: items.map((item) => {
|
|
8265
8657
|
const isExpanded = Boolean(expanded[item.id]);
|
|
8266
8658
|
const showToggle = Boolean(canExpand[item.id]);
|
|
8267
8659
|
const prompt = item.prompt ?? "";
|
|
8268
8660
|
const moreLabel = "more";
|
|
8269
8661
|
const displayPrompt = !isExpanded && showToggle && collapsedText[item.id] ? collapsedText[item.id] : prompt;
|
|
8270
8662
|
const isRemoving = Boolean(removing[item.id]);
|
|
8271
|
-
return /* @__PURE__ */ (0,
|
|
8272
|
-
|
|
8663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
8664
|
+
import_react_native56.View,
|
|
8273
8665
|
{
|
|
8274
8666
|
style: {
|
|
8275
8667
|
flexDirection: "row",
|
|
@@ -8281,8 +8673,8 @@ ${trimmedLine2}\u2026 `;
|
|
|
8281
8673
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.8 : 0.9)
|
|
8282
8674
|
},
|
|
8283
8675
|
children: [
|
|
8284
|
-
/* @__PURE__ */ (0,
|
|
8285
|
-
!canExpand[item.id] ? /* @__PURE__ */ (0,
|
|
8676
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_react_native56.View, { style: { flex: 1 }, children: [
|
|
8677
|
+
!canExpand[item.id] ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
8286
8678
|
Text,
|
|
8287
8679
|
{
|
|
8288
8680
|
style: { position: "absolute", opacity: 0, zIndex: -1, width: "100%" },
|
|
@@ -8301,14 +8693,14 @@ ${trimmedLine2}\u2026 `;
|
|
|
8301
8693
|
children: prompt
|
|
8302
8694
|
}
|
|
8303
8695
|
) : null,
|
|
8304
|
-
/* @__PURE__ */ (0,
|
|
8696
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
8305
8697
|
Text,
|
|
8306
8698
|
{
|
|
8307
8699
|
variant: "bodyMuted",
|
|
8308
8700
|
numberOfLines: isExpanded ? void 0 : 2,
|
|
8309
8701
|
children: [
|
|
8310
8702
|
displayPrompt,
|
|
8311
|
-
!isExpanded && showToggle ? /* @__PURE__ */ (0,
|
|
8703
|
+
!isExpanded && showToggle ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
8312
8704
|
Text,
|
|
8313
8705
|
{
|
|
8314
8706
|
color: theme.colors.text,
|
|
@@ -8320,18 +8712,18 @@ ${trimmedLine2}\u2026 `;
|
|
|
8320
8712
|
]
|
|
8321
8713
|
}
|
|
8322
8714
|
),
|
|
8323
|
-
showToggle && isExpanded ? /* @__PURE__ */ (0,
|
|
8324
|
-
|
|
8715
|
+
showToggle && isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
8716
|
+
import_react_native56.Pressable,
|
|
8325
8717
|
{
|
|
8326
8718
|
onPress: () => setExpanded((prev) => ({ ...prev, [item.id]: false })),
|
|
8327
8719
|
hitSlop: 6,
|
|
8328
8720
|
style: { alignSelf: "flex-start", marginTop: 4 },
|
|
8329
|
-
children: /* @__PURE__ */ (0,
|
|
8721
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Text, { variant: "captionMuted", color: theme.colors.text, children: "less" })
|
|
8330
8722
|
}
|
|
8331
8723
|
) : null
|
|
8332
8724
|
] }),
|
|
8333
|
-
/* @__PURE__ */ (0,
|
|
8334
|
-
|
|
8725
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
8726
|
+
import_react_native56.Pressable,
|
|
8335
8727
|
{
|
|
8336
8728
|
onPress: () => {
|
|
8337
8729
|
if (!onRemove || isRemoving) return;
|
|
@@ -8346,7 +8738,7 @@ ${trimmedLine2}\u2026 `;
|
|
|
8346
8738
|
},
|
|
8347
8739
|
hitSlop: 8,
|
|
8348
8740
|
style: { alignSelf: "center" },
|
|
8349
|
-
children: isRemoving ? /* @__PURE__ */ (0,
|
|
8741
|
+
children: isRemoving ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native56.ActivityIndicator, { size: "small", color: theme.colors.text }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(IconClose, { size: 14, colorToken: "text" })
|
|
8350
8742
|
}
|
|
8351
8743
|
)
|
|
8352
8744
|
]
|
|
@@ -8360,15 +8752,15 @@ ${trimmedLine2}\u2026 `;
|
|
|
8360
8752
|
}
|
|
8361
8753
|
|
|
8362
8754
|
// src/components/chat/AgentProgressCard.tsx
|
|
8363
|
-
var
|
|
8755
|
+
var import_react_native57 = require("react-native");
|
|
8364
8756
|
|
|
8365
8757
|
// src/components/icons/RemixXLoopLottie.tsx
|
|
8366
8758
|
var import_lottie_react_native = __toESM(require("lottie-react-native"));
|
|
8367
|
-
var
|
|
8759
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
8368
8760
|
var remixXLoopSource = require_remix_x_loop_lottie();
|
|
8369
8761
|
var Lottie = import_lottie_react_native.default;
|
|
8370
8762
|
function RemixXLoopLottie({ size = 24, style }) {
|
|
8371
|
-
return /* @__PURE__ */ (0,
|
|
8763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
8372
8764
|
Lottie,
|
|
8373
8765
|
{
|
|
8374
8766
|
source: remixXLoopSource,
|
|
@@ -8380,7 +8772,7 @@ function RemixXLoopLottie({ size = 24, style }) {
|
|
|
8380
8772
|
}
|
|
8381
8773
|
|
|
8382
8774
|
// src/components/chat/AgentProgressCard.tsx
|
|
8383
|
-
var
|
|
8775
|
+
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
8384
8776
|
function titleForPhase(phase) {
|
|
8385
8777
|
if (phase === "planning") return "Planning";
|
|
8386
8778
|
if (phase === "reasoning") return "Reasoning";
|
|
@@ -8405,8 +8797,8 @@ function AgentProgressCard({ progress }) {
|
|
|
8405
8797
|
const showAnimatedStatusIcon = progress.status === "running";
|
|
8406
8798
|
const subtitle = progress.latestMessage || `Agent is ${phaseLabel.toLowerCase()}...`;
|
|
8407
8799
|
const todo = progress.todoSummary;
|
|
8408
|
-
return /* @__PURE__ */ (0,
|
|
8409
|
-
|
|
8800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
|
|
8801
|
+
import_react_native57.View,
|
|
8410
8802
|
{
|
|
8411
8803
|
style: {
|
|
8412
8804
|
borderWidth: 1,
|
|
@@ -8417,23 +8809,23 @@ function AgentProgressCard({ progress }) {
|
|
|
8417
8809
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.84 : 0.94)
|
|
8418
8810
|
},
|
|
8419
8811
|
children: [
|
|
8420
|
-
/* @__PURE__ */ (0,
|
|
8421
|
-
/* @__PURE__ */ (0,
|
|
8422
|
-
/* @__PURE__ */ (0,
|
|
8423
|
-
/* @__PURE__ */ (0,
|
|
8424
|
-
showAnimatedStatusIcon ? /* @__PURE__ */ (0,
|
|
8812
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_react_native57.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }, children: [
|
|
8813
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Text, { variant: "caption", children: statusLabel }),
|
|
8814
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_react_native57.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8815
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Text, { variant: "captionMuted", children: phaseLabel }),
|
|
8816
|
+
showAnimatedStatusIcon ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RemixXLoopLottie, { size: 20, style: { marginLeft: 8 } }) : null
|
|
8425
8817
|
] })
|
|
8426
8818
|
] }),
|
|
8427
|
-
/* @__PURE__ */ (0,
|
|
8428
|
-
progress.changedFilesCount > 0 ? /* @__PURE__ */ (0,
|
|
8819
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Text, { variant: "bodyMuted", children: subtitle }),
|
|
8820
|
+
progress.changedFilesCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Text, { variant: "captionMuted", style: { marginTop: 8 }, children: [
|
|
8429
8821
|
"Updated files: ",
|
|
8430
8822
|
progress.changedFilesCount
|
|
8431
8823
|
] }) : null,
|
|
8432
|
-
progress.recentFiles.length > 0 ? /* @__PURE__ */ (0,
|
|
8824
|
+
progress.recentFiles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(import_react_native57.View, { style: { marginTop: 6 }, children: progress.recentFiles.map((path) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Text, { variant: "captionMuted", numberOfLines: 1, children: [
|
|
8433
8825
|
"\u2022 ",
|
|
8434
8826
|
path
|
|
8435
8827
|
] }, path)) }) : null,
|
|
8436
|
-
todo ? /* @__PURE__ */ (0,
|
|
8828
|
+
todo ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Text, { variant: "captionMuted", style: { marginTop: 8 }, children: [
|
|
8437
8829
|
"Todos: ",
|
|
8438
8830
|
todo.completed,
|
|
8439
8831
|
"/",
|
|
@@ -8447,8 +8839,8 @@ function AgentProgressCard({ progress }) {
|
|
|
8447
8839
|
}
|
|
8448
8840
|
|
|
8449
8841
|
// src/components/chat/BundleProgressCard.tsx
|
|
8450
|
-
var
|
|
8451
|
-
var
|
|
8842
|
+
var import_react_native58 = require("react-native");
|
|
8843
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
8452
8844
|
function titleForStatus2(status) {
|
|
8453
8845
|
if (status === "succeeded") return "Completed";
|
|
8454
8846
|
if (status === "failed") return "Failed";
|
|
@@ -8460,8 +8852,8 @@ function BundleProgressCard({ progress }) {
|
|
|
8460
8852
|
const percent = Math.round(Math.max(0, Math.min(1, progress.progressValue)) * 100);
|
|
8461
8853
|
const fillColor = progress.status === "failed" ? theme.colors.danger : progress.status === "succeeded" ? theme.colors.success : theme.colors.warning;
|
|
8462
8854
|
const detail = progress.errorMessage || progress.phaseLabel;
|
|
8463
|
-
return /* @__PURE__ */ (0,
|
|
8464
|
-
|
|
8855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
|
|
8856
|
+
import_react_native58.View,
|
|
8465
8857
|
{
|
|
8466
8858
|
accessible: true,
|
|
8467
8859
|
accessibilityRole: "progressbar",
|
|
@@ -8476,15 +8868,15 @@ function BundleProgressCard({ progress }) {
|
|
|
8476
8868
|
backgroundColor: withAlpha(theme.colors.surface, theme.scheme === "dark" ? 0.84 : 0.94)
|
|
8477
8869
|
},
|
|
8478
8870
|
children: [
|
|
8479
|
-
/* @__PURE__ */ (0,
|
|
8480
|
-
/* @__PURE__ */ (0,
|
|
8481
|
-
/* @__PURE__ */ (0,
|
|
8871
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_react_native58.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }, children: [
|
|
8872
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Text, { variant: "caption", children: statusLabel }),
|
|
8873
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(Text, { variant: "captionMuted", children: [
|
|
8482
8874
|
percent,
|
|
8483
8875
|
"%"
|
|
8484
8876
|
] })
|
|
8485
8877
|
] }),
|
|
8486
|
-
/* @__PURE__ */ (0,
|
|
8487
|
-
|
|
8878
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
8879
|
+
import_react_native58.View,
|
|
8488
8880
|
{
|
|
8489
8881
|
style: {
|
|
8490
8882
|
width: "100%",
|
|
@@ -8493,8 +8885,8 @@ function BundleProgressCard({ progress }) {
|
|
|
8493
8885
|
backgroundColor: withAlpha(theme.colors.border, theme.scheme === "dark" ? 0.5 : 0.6),
|
|
8494
8886
|
overflow: "hidden"
|
|
8495
8887
|
},
|
|
8496
|
-
children: /* @__PURE__ */ (0,
|
|
8497
|
-
|
|
8888
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
8889
|
+
import_react_native58.View,
|
|
8498
8890
|
{
|
|
8499
8891
|
style: {
|
|
8500
8892
|
width: `${percent}%`,
|
|
@@ -8505,14 +8897,14 @@ function BundleProgressCard({ progress }) {
|
|
|
8505
8897
|
)
|
|
8506
8898
|
}
|
|
8507
8899
|
),
|
|
8508
|
-
/* @__PURE__ */ (0,
|
|
8900
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Text, { variant: "captionMuted", numberOfLines: 1, style: { marginTop: 8, minHeight: 16 }, children: detail })
|
|
8509
8901
|
]
|
|
8510
8902
|
}
|
|
8511
8903
|
);
|
|
8512
8904
|
}
|
|
8513
8905
|
|
|
8514
8906
|
// src/studio/ui/ChatPanel.tsx
|
|
8515
|
-
var
|
|
8907
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
8516
8908
|
function ChatPanel({
|
|
8517
8909
|
title = "Chat",
|
|
8518
8910
|
messages,
|
|
@@ -8532,14 +8924,15 @@ function ChatPanel({
|
|
|
8532
8924
|
onSend,
|
|
8533
8925
|
onRetryMessage,
|
|
8534
8926
|
isRetryingMessage,
|
|
8927
|
+
onAttachmentLoadError,
|
|
8535
8928
|
queueItems = [],
|
|
8536
8929
|
onRemoveQueueItem,
|
|
8537
8930
|
progress = null
|
|
8538
8931
|
}) {
|
|
8539
8932
|
const theme = useTheme();
|
|
8540
|
-
const listRef =
|
|
8541
|
-
const [nearBottom, setNearBottom] =
|
|
8542
|
-
const handleSend =
|
|
8933
|
+
const listRef = React44.useRef(null);
|
|
8934
|
+
const [nearBottom, setNearBottom] = React44.useState(true);
|
|
8935
|
+
const handleSend = React44.useCallback(
|
|
8543
8936
|
async (text, composerAttachments) => {
|
|
8544
8937
|
const all = composerAttachments ?? attachments;
|
|
8545
8938
|
await onSend(text, all.length > 0 ? all : void 0);
|
|
@@ -8553,25 +8946,25 @@ function ChatPanel({
|
|
|
8553
8946
|
},
|
|
8554
8947
|
[attachments, nearBottom, onClearAttachments, onSend]
|
|
8555
8948
|
);
|
|
8556
|
-
const handleScrollToBottom =
|
|
8949
|
+
const handleScrollToBottom = React44.useCallback(() => {
|
|
8557
8950
|
var _a;
|
|
8558
8951
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
8559
8952
|
}, []);
|
|
8560
|
-
const header = /* @__PURE__ */ (0,
|
|
8953
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
8561
8954
|
ChatHeader,
|
|
8562
8955
|
{
|
|
8563
|
-
left: /* @__PURE__ */ (0,
|
|
8564
|
-
/* @__PURE__ */ (0,
|
|
8565
|
-
onNavigateHome ? /* @__PURE__ */ (0,
|
|
8956
|
+
left: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_react_native59.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8957
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StudioSheetHeaderIconButton, { onPress: onBack, accessibilityLabel: "Back", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IconBack, { size: 20, colorToken: "floatingContent" }) }),
|
|
8958
|
+
onNavigateHome ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StudioSheetHeaderIconButton, { onPress: onNavigateHome, accessibilityLabel: "Home", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IconHome, { size: 20, colorToken: "floatingContent" }) }) : null
|
|
8566
8959
|
] }),
|
|
8567
|
-
right: /* @__PURE__ */ (0,
|
|
8568
|
-
onStartDraw ? /* @__PURE__ */ (0,
|
|
8569
|
-
/* @__PURE__ */ (0,
|
|
8960
|
+
right: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_react_native59.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
8961
|
+
onStartDraw ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StudioSheetHeaderIconButton, { onPress: onStartDraw, accessibilityLabel: "Draw", intent: "danger", style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IconDraw, { size: 20, colorToken: "onDanger" }) }) : null,
|
|
8962
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StudioSheetHeaderIconButton, { onPress: onClose, accessibilityLabel: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IconClose, { size: 20, colorToken: "floatingContent" }) })
|
|
8570
8963
|
] }),
|
|
8571
8964
|
center: null
|
|
8572
8965
|
}
|
|
8573
8966
|
);
|
|
8574
|
-
const topBanner = shouldForkOnEdit ? /* @__PURE__ */ (0,
|
|
8967
|
+
const topBanner = shouldForkOnEdit ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
8575
8968
|
ForkNoticeBanner,
|
|
8576
8969
|
{
|
|
8577
8970
|
isOwner: !shouldForkOnEdit,
|
|
@@ -8580,22 +8973,22 @@ function ChatPanel({
|
|
|
8580
8973
|
) : null;
|
|
8581
8974
|
const showMessagesLoading = Boolean(loading) && messages.length === 0;
|
|
8582
8975
|
if (showMessagesLoading) {
|
|
8583
|
-
return /* @__PURE__ */ (0,
|
|
8584
|
-
/* @__PURE__ */ (0,
|
|
8585
|
-
topBanner ? /* @__PURE__ */ (0,
|
|
8586
|
-
/* @__PURE__ */ (0,
|
|
8587
|
-
/* @__PURE__ */ (0,
|
|
8588
|
-
/* @__PURE__ */ (0,
|
|
8589
|
-
/* @__PURE__ */ (0,
|
|
8976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_react_native59.View, { style: { flex: 1 }, children: [
|
|
8977
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_native59.View, { children: header }),
|
|
8978
|
+
topBanner ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_native59.View, { style: { paddingHorizontal: 16, paddingTop: 8 }, children: topBanner }) : null,
|
|
8979
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_react_native59.View, { style: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24, paddingVertical: 12 }, children: [
|
|
8980
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_native59.ActivityIndicator, {}),
|
|
8981
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_native59.View, { style: { height: 12 } }),
|
|
8982
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Text, { variant: "bodyMuted", children: "Loading messages\u2026" })
|
|
8590
8983
|
] })
|
|
8591
8984
|
] });
|
|
8592
8985
|
}
|
|
8593
8986
|
const bundleProgress = (progress == null ? void 0 : progress.bundle) ?? null;
|
|
8594
|
-
const queueTop = progress || queueItems.length > 0 ? /* @__PURE__ */ (0,
|
|
8595
|
-
progress ? bundleProgress ? /* @__PURE__ */ (0,
|
|
8596
|
-
!progress && queueItems.length > 0 ? /* @__PURE__ */ (0,
|
|
8987
|
+
const queueTop = progress || queueItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_react_native59.View, { style: { gap: theme.spacing.sm }, children: [
|
|
8988
|
+
progress ? bundleProgress ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(BundleProgressCard, { progress: bundleProgress }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(AgentProgressCard, { progress }) : null,
|
|
8989
|
+
!progress && queueItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(ChatQueue, { items: queueItems, onRemove: onRemoveQueueItem }) : null
|
|
8597
8990
|
] }) : null;
|
|
8598
|
-
return /* @__PURE__ */ (0,
|
|
8991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
8599
8992
|
ChatPage,
|
|
8600
8993
|
{
|
|
8601
8994
|
header,
|
|
@@ -8603,18 +8996,19 @@ function ChatPanel({
|
|
|
8603
8996
|
showTypingIndicator,
|
|
8604
8997
|
onRetryMessage,
|
|
8605
8998
|
isRetryingMessage,
|
|
8999
|
+
onAttachmentLoadError,
|
|
8606
9000
|
topBanner,
|
|
8607
9001
|
composerTop: queueTop,
|
|
8608
9002
|
composerHorizontalPadding: 0,
|
|
8609
9003
|
listRef,
|
|
8610
9004
|
onNearBottomChange: setNearBottom,
|
|
8611
|
-
overlay: /* @__PURE__ */ (0,
|
|
9005
|
+
overlay: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
8612
9006
|
ScrollToBottomButton,
|
|
8613
9007
|
{
|
|
8614
9008
|
visible: !nearBottom,
|
|
8615
9009
|
onPress: handleScrollToBottom,
|
|
8616
9010
|
style: { bottom: 80 },
|
|
8617
|
-
children: /* @__PURE__ */ (0,
|
|
9011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(IconArrowDown, { size: 20, colorToken: "floatingContent" })
|
|
8618
9012
|
}
|
|
8619
9013
|
),
|
|
8620
9014
|
composer: {
|
|
@@ -8634,9 +9028,9 @@ function ChatPanel({
|
|
|
8634
9028
|
}
|
|
8635
9029
|
|
|
8636
9030
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
8637
|
-
var
|
|
8638
|
-
var
|
|
8639
|
-
var
|
|
9031
|
+
var React45 = __toESM(require("react"));
|
|
9032
|
+
var import_react_native60 = require("react-native");
|
|
9033
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
8640
9034
|
function ConfirmMergeRequestDialog({
|
|
8641
9035
|
visible,
|
|
8642
9036
|
onOpenChange,
|
|
@@ -8647,14 +9041,14 @@ function ConfirmMergeRequestDialog({
|
|
|
8647
9041
|
onTestFirst
|
|
8648
9042
|
}) {
|
|
8649
9043
|
const theme = useTheme();
|
|
8650
|
-
const close =
|
|
9044
|
+
const close = React45.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
8651
9045
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
8652
|
-
const handleConfirm =
|
|
9046
|
+
const handleConfirm = React45.useCallback(() => {
|
|
8653
9047
|
if (!mergeRequest) return;
|
|
8654
9048
|
onOpenChange(false);
|
|
8655
9049
|
void onConfirm();
|
|
8656
9050
|
}, [mergeRequest, onConfirm, onOpenChange]);
|
|
8657
|
-
const handleTestFirst =
|
|
9051
|
+
const handleTestFirst = React45.useCallback(() => {
|
|
8658
9052
|
if (!mergeRequest) return;
|
|
8659
9053
|
onOpenChange(false);
|
|
8660
9054
|
void onTestFirst(mergeRequest);
|
|
@@ -8666,7 +9060,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8666
9060
|
justifyContent: "center",
|
|
8667
9061
|
alignSelf: "stretch"
|
|
8668
9062
|
};
|
|
8669
|
-
return /* @__PURE__ */ (0,
|
|
9063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
8670
9064
|
Modal,
|
|
8671
9065
|
{
|
|
8672
9066
|
visible,
|
|
@@ -8677,7 +9071,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8677
9071
|
backgroundColor: theme.colors.background
|
|
8678
9072
|
},
|
|
8679
9073
|
children: [
|
|
8680
|
-
/* @__PURE__ */ (0,
|
|
9074
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_react_native60.View, { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
8681
9075
|
Text,
|
|
8682
9076
|
{
|
|
8683
9077
|
style: {
|
|
@@ -8689,9 +9083,9 @@ function ConfirmMergeRequestDialog({
|
|
|
8689
9083
|
children: "Are you sure you want to approve this merge request?"
|
|
8690
9084
|
}
|
|
8691
9085
|
) }),
|
|
8692
|
-
/* @__PURE__ */ (0,
|
|
8693
|
-
/* @__PURE__ */ (0,
|
|
8694
|
-
|
|
9086
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(import_react_native60.View, { style: { marginTop: 16 }, children: [
|
|
9087
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9088
|
+
import_react_native60.View,
|
|
8695
9089
|
{
|
|
8696
9090
|
style: [
|
|
8697
9091
|
fullWidthButtonBase,
|
|
@@ -8700,22 +9094,22 @@ function ConfirmMergeRequestDialog({
|
|
|
8700
9094
|
opacity: canConfirm ? 1 : 0.5
|
|
8701
9095
|
}
|
|
8702
9096
|
],
|
|
8703
|
-
children: /* @__PURE__ */ (0,
|
|
8704
|
-
|
|
9097
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9098
|
+
import_react_native60.Pressable,
|
|
8705
9099
|
{
|
|
8706
9100
|
accessibilityRole: "button",
|
|
8707
9101
|
accessibilityLabel: "Approve Merge",
|
|
8708
9102
|
disabled: !canConfirm,
|
|
8709
9103
|
onPress: handleConfirm,
|
|
8710
9104
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8711
|
-
children: /* @__PURE__ */ (0,
|
|
9105
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Text, { style: { textAlign: "center", color: theme.colors.onPrimary }, children: "Approve Merge" })
|
|
8712
9106
|
}
|
|
8713
9107
|
)
|
|
8714
9108
|
}
|
|
8715
9109
|
),
|
|
8716
|
-
/* @__PURE__ */ (0,
|
|
8717
|
-
/* @__PURE__ */ (0,
|
|
8718
|
-
|
|
9110
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_react_native60.View, { style: { height: 8 } }),
|
|
9111
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9112
|
+
import_react_native60.View,
|
|
8719
9113
|
{
|
|
8720
9114
|
style: [
|
|
8721
9115
|
fullWidthButtonBase,
|
|
@@ -8726,22 +9120,22 @@ function ConfirmMergeRequestDialog({
|
|
|
8726
9120
|
opacity: isBuilding || !mergeRequest ? 0.5 : 1
|
|
8727
9121
|
}
|
|
8728
9122
|
],
|
|
8729
|
-
children: /* @__PURE__ */ (0,
|
|
8730
|
-
|
|
9123
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9124
|
+
import_react_native60.Pressable,
|
|
8731
9125
|
{
|
|
8732
9126
|
accessibilityRole: "button",
|
|
8733
9127
|
accessibilityLabel: isBuilding ? "Preparing\u2026" : "Test edits first",
|
|
8734
9128
|
disabled: isBuilding || !mergeRequest,
|
|
8735
9129
|
onPress: handleTestFirst,
|
|
8736
9130
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8737
|
-
children: /* @__PURE__ */ (0,
|
|
9131
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Text, { style: { textAlign: "center", color: theme.colors.text }, children: isBuilding ? "Preparing\u2026" : "Test edits first" })
|
|
8738
9132
|
}
|
|
8739
9133
|
)
|
|
8740
9134
|
}
|
|
8741
9135
|
),
|
|
8742
|
-
/* @__PURE__ */ (0,
|
|
8743
|
-
/* @__PURE__ */ (0,
|
|
8744
|
-
|
|
9136
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_react_native60.View, { style: { height: 8 } }),
|
|
9137
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9138
|
+
import_react_native60.View,
|
|
8745
9139
|
{
|
|
8746
9140
|
style: [
|
|
8747
9141
|
fullWidthButtonBase,
|
|
@@ -8751,14 +9145,14 @@ function ConfirmMergeRequestDialog({
|
|
|
8751
9145
|
borderColor: theme.colors.border
|
|
8752
9146
|
}
|
|
8753
9147
|
],
|
|
8754
|
-
children: /* @__PURE__ */ (0,
|
|
8755
|
-
|
|
9148
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
9149
|
+
import_react_native60.Pressable,
|
|
8756
9150
|
{
|
|
8757
9151
|
accessibilityRole: "button",
|
|
8758
9152
|
accessibilityLabel: "Cancel",
|
|
8759
9153
|
onPress: close,
|
|
8760
9154
|
style: [fullWidthButtonBase, { flex: 1 }],
|
|
8761
|
-
children: /* @__PURE__ */ (0,
|
|
9155
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Text, { style: { textAlign: "center", color: theme.colors.text }, children: "Cancel" })
|
|
8762
9156
|
}
|
|
8763
9157
|
)
|
|
8764
9158
|
}
|
|
@@ -8770,7 +9164,7 @@ function ConfirmMergeRequestDialog({
|
|
|
8770
9164
|
}
|
|
8771
9165
|
|
|
8772
9166
|
// src/studio/ui/ConfirmMergeFlow.tsx
|
|
8773
|
-
var
|
|
9167
|
+
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
8774
9168
|
function ConfirmMergeFlow({
|
|
8775
9169
|
visible,
|
|
8776
9170
|
onOpenChange,
|
|
@@ -8781,7 +9175,7 @@ function ConfirmMergeFlow({
|
|
|
8781
9175
|
onConfirm,
|
|
8782
9176
|
onTestFirst
|
|
8783
9177
|
}) {
|
|
8784
|
-
return /* @__PURE__ */ (0,
|
|
9178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
8785
9179
|
ConfirmMergeRequestDialog,
|
|
8786
9180
|
{
|
|
8787
9181
|
visible,
|
|
@@ -8803,7 +9197,8 @@ function ConfirmMergeFlow({
|
|
|
8803
9197
|
}
|
|
8804
9198
|
|
|
8805
9199
|
// src/studio/hooks/useOptimisticChatMessages.ts
|
|
8806
|
-
var
|
|
9200
|
+
var React46 = __toESM(require("react"));
|
|
9201
|
+
var import_react_native61 = require("react-native");
|
|
8807
9202
|
function makeOptimisticId() {
|
|
8808
9203
|
return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
|
|
8809
9204
|
}
|
|
@@ -8814,6 +9209,28 @@ function toEpochMs2(createdAt) {
|
|
|
8814
9209
|
const t = Date.parse(String(createdAt));
|
|
8815
9210
|
return Number.isFinite(t) ? t : 0;
|
|
8816
9211
|
}
|
|
9212
|
+
async function resolveAttachmentDimensions(uris) {
|
|
9213
|
+
return Promise.all(
|
|
9214
|
+
uris.map(
|
|
9215
|
+
async (uri) => {
|
|
9216
|
+
try {
|
|
9217
|
+
const { width, height } = await new Promise((resolve, reject) => {
|
|
9218
|
+
import_react_native61.Image.getSize(
|
|
9219
|
+
uri,
|
|
9220
|
+
(w, h) => resolve({ width: w, height: h }),
|
|
9221
|
+
(err) => reject(err)
|
|
9222
|
+
);
|
|
9223
|
+
});
|
|
9224
|
+
if (width > 0 && height > 0) {
|
|
9225
|
+
return { uri, width: Math.round(width), height: Math.round(height) };
|
|
9226
|
+
}
|
|
9227
|
+
} catch {
|
|
9228
|
+
}
|
|
9229
|
+
return { uri };
|
|
9230
|
+
}
|
|
9231
|
+
)
|
|
9232
|
+
);
|
|
9233
|
+
}
|
|
8817
9234
|
function isOptimisticResolvedByServer(chatMessages, o) {
|
|
8818
9235
|
if (o.failed) return false;
|
|
8819
9236
|
const normalize = (s) => s.trim();
|
|
@@ -8842,11 +9259,11 @@ function useOptimisticChatMessages({
|
|
|
8842
9259
|
chatMessages,
|
|
8843
9260
|
onSendChat
|
|
8844
9261
|
}) {
|
|
8845
|
-
const [optimisticChat, setOptimisticChat] =
|
|
8846
|
-
|
|
9262
|
+
const [optimisticChat, setOptimisticChat] = React46.useState([]);
|
|
9263
|
+
React46.useEffect(() => {
|
|
8847
9264
|
setOptimisticChat([]);
|
|
8848
9265
|
}, [threadId]);
|
|
8849
|
-
const messages =
|
|
9266
|
+
const messages = React46.useMemo(() => {
|
|
8850
9267
|
if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
|
|
8851
9268
|
const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
|
|
8852
9269
|
if (unresolved.length === 0) return chatMessages;
|
|
@@ -8856,13 +9273,22 @@ function useOptimisticChatMessages({
|
|
|
8856
9273
|
content: o.content,
|
|
8857
9274
|
createdAt: o.createdAtIso,
|
|
8858
9275
|
kind: "optimistic",
|
|
9276
|
+
attachments: (o.attachments ?? []).map((attachment, index) => ({
|
|
9277
|
+
id: `${o.id}:attachment:${index}`,
|
|
9278
|
+
name: `attachment-${index + 1}.png`,
|
|
9279
|
+
mimeType: "image/png",
|
|
9280
|
+
size: 1,
|
|
9281
|
+
uri: attachment.uri,
|
|
9282
|
+
width: attachment.width,
|
|
9283
|
+
height: attachment.height
|
|
9284
|
+
})),
|
|
8859
9285
|
meta: o.failed ? { kind: "optimistic", event: "send.failed", status: "error" } : { kind: "optimistic", event: "send.pending", status: "info" }
|
|
8860
9286
|
}));
|
|
8861
9287
|
const merged = [...chatMessages, ...optimisticAsChat];
|
|
8862
9288
|
merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
8863
9289
|
return merged;
|
|
8864
9290
|
}, [chatMessages, optimisticChat]);
|
|
8865
|
-
|
|
9291
|
+
React46.useEffect(() => {
|
|
8866
9292
|
if (optimisticChat.length === 0) return;
|
|
8867
9293
|
setOptimisticChat((prev) => {
|
|
8868
9294
|
if (prev.length === 0) return prev;
|
|
@@ -8870,7 +9296,7 @@ function useOptimisticChatMessages({
|
|
|
8870
9296
|
return next.length === prev.length ? prev : next;
|
|
8871
9297
|
});
|
|
8872
9298
|
}, [chatMessages, optimisticChat.length]);
|
|
8873
|
-
const onSend =
|
|
9299
|
+
const onSend = React46.useCallback(
|
|
8874
9300
|
async (text, attachments) => {
|
|
8875
9301
|
if (disableOptimistic) {
|
|
8876
9302
|
await onSendChat(text, attachments);
|
|
@@ -8879,7 +9305,7 @@ function useOptimisticChatMessages({
|
|
|
8879
9305
|
const createdAtIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
8880
9306
|
const baseServerLastId = chatMessages.length > 0 ? chatMessages[chatMessages.length - 1].id : null;
|
|
8881
9307
|
const id = makeOptimisticId();
|
|
8882
|
-
const normalizedAttachments = attachments && attachments.length > 0 ?
|
|
9308
|
+
const normalizedAttachments = attachments && attachments.length > 0 ? await resolveAttachmentDimensions(attachments) : void 0;
|
|
8883
9309
|
setOptimisticChat((prev) => [
|
|
8884
9310
|
...prev,
|
|
8885
9311
|
{
|
|
@@ -8898,8 +9324,9 @@ function useOptimisticChatMessages({
|
|
|
8898
9324
|
},
|
|
8899
9325
|
[chatMessages, disableOptimistic, onSendChat]
|
|
8900
9326
|
);
|
|
8901
|
-
const onRetry =
|
|
9327
|
+
const onRetry = React46.useCallback(
|
|
8902
9328
|
async (messageId) => {
|
|
9329
|
+
var _a;
|
|
8903
9330
|
if (disableOptimistic) return;
|
|
8904
9331
|
const target = optimisticChat.find((m) => m.id === messageId);
|
|
8905
9332
|
if (!target || target.retrying) return;
|
|
@@ -8910,7 +9337,10 @@ function useOptimisticChatMessages({
|
|
|
8910
9337
|
)
|
|
8911
9338
|
);
|
|
8912
9339
|
try {
|
|
8913
|
-
await onSendChat(
|
|
9340
|
+
await onSendChat(
|
|
9341
|
+
target.content,
|
|
9342
|
+
(_a = target.attachments) == null ? void 0 : _a.map((att) => att.uri)
|
|
9343
|
+
);
|
|
8914
9344
|
setOptimisticChat(
|
|
8915
9345
|
(prev) => prev.map((m) => m.id === messageId ? { ...m, retrying: false } : m)
|
|
8916
9346
|
);
|
|
@@ -8922,7 +9352,7 @@ function useOptimisticChatMessages({
|
|
|
8922
9352
|
},
|
|
8923
9353
|
[chatMessages, disableOptimistic, onSendChat, optimisticChat]
|
|
8924
9354
|
);
|
|
8925
|
-
const isRetrying =
|
|
9355
|
+
const isRetrying = React46.useCallback(
|
|
8926
9356
|
(messageId) => {
|
|
8927
9357
|
return optimisticChat.some((m) => m.id === messageId && m.retrying);
|
|
8928
9358
|
},
|
|
@@ -8936,24 +9366,24 @@ var import_studio_control = require("@comergehq/studio-control");
|
|
|
8936
9366
|
|
|
8937
9367
|
// src/components/icons/RemixUpIcon.tsx
|
|
8938
9368
|
var import_react_native_svg3 = __toESM(require("react-native-svg"));
|
|
8939
|
-
var
|
|
9369
|
+
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
8940
9370
|
function RemixUpIcon({ width = 24, height = 24, ...props }) {
|
|
8941
|
-
return /* @__PURE__ */ (0,
|
|
8942
|
-
/* @__PURE__ */ (0,
|
|
9371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_react_native_svg3.default, { viewBox: "0 0 70 49", width, height, fill: "none", ...props, children: [
|
|
9372
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
8943
9373
|
import_react_native_svg3.Path,
|
|
8944
9374
|
{
|
|
8945
9375
|
d: "M34.706 7.62939e-05L34.7656 2.28882e-05L21.44 13.2661L0 34.8401L13.266 48.1061L34.706 26.5321L21.44 13.2661L34.706 7.62939e-05Z",
|
|
8946
9376
|
fill: "#00CBC0"
|
|
8947
9377
|
}
|
|
8948
9378
|
),
|
|
8949
|
-
/* @__PURE__ */ (0,
|
|
9379
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
8950
9380
|
import_react_native_svg3.Path,
|
|
8951
9381
|
{
|
|
8952
9382
|
d: "M47.972 13.266L34.7656 2.28882e-05L34.706 7.62939e-05L47.972 13.266L34.706 26.5321L56.28 48.106L69.546 34.84L47.972 13.266Z",
|
|
8953
9383
|
fill: "#FF1820"
|
|
8954
9384
|
}
|
|
8955
9385
|
),
|
|
8956
|
-
/* @__PURE__ */ (0,
|
|
9386
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
8957
9387
|
import_react_native_svg3.Path,
|
|
8958
9388
|
{
|
|
8959
9389
|
d: "M34.7656 2.28882e-05L21.44 13.2661L34.706 26.5321L47.972 13.266L34.7656 2.28882e-05Z",
|
|
@@ -8964,7 +9394,7 @@ function RemixUpIcon({ width = 24, height = 24, ...props }) {
|
|
|
8964
9394
|
}
|
|
8965
9395
|
|
|
8966
9396
|
// src/studio/ui/StudioOverlay.tsx
|
|
8967
|
-
var
|
|
9397
|
+
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
8968
9398
|
function StudioOverlay({
|
|
8969
9399
|
captureTargetRef,
|
|
8970
9400
|
app,
|
|
@@ -8995,6 +9425,7 @@ function StudioOverlay({
|
|
|
8995
9425
|
chatSending,
|
|
8996
9426
|
chatShowTypingIndicator,
|
|
8997
9427
|
onSendChat,
|
|
9428
|
+
onChatAttachmentLoadError,
|
|
8998
9429
|
chatQueueItems,
|
|
8999
9430
|
onRemoveQueueItem,
|
|
9000
9431
|
chatProgress,
|
|
@@ -9008,15 +9439,15 @@ function StudioOverlay({
|
|
|
9008
9439
|
onSwitchRelatedApp
|
|
9009
9440
|
}) {
|
|
9010
9441
|
const theme = useTheme();
|
|
9011
|
-
const { width } = (0,
|
|
9012
|
-
const [sheetOpen, setSheetOpen] =
|
|
9013
|
-
const sheetOpenRef =
|
|
9014
|
-
const pendingNavigateHomeRef =
|
|
9015
|
-
const [activePage, setActivePage] =
|
|
9016
|
-
const [drawing, setDrawing] =
|
|
9017
|
-
const [chatAttachments, setChatAttachments] =
|
|
9018
|
-
const [commentsAppId, setCommentsAppId] =
|
|
9019
|
-
const [commentsCount, setCommentsCount] =
|
|
9442
|
+
const { width } = (0, import_react_native62.useWindowDimensions)();
|
|
9443
|
+
const [sheetOpen, setSheetOpen] = React47.useState(false);
|
|
9444
|
+
const sheetOpenRef = React47.useRef(sheetOpen);
|
|
9445
|
+
const pendingNavigateHomeRef = React47.useRef(false);
|
|
9446
|
+
const [activePage, setActivePage] = React47.useState("preview");
|
|
9447
|
+
const [drawing, setDrawing] = React47.useState(false);
|
|
9448
|
+
const [chatAttachments, setChatAttachments] = React47.useState([]);
|
|
9449
|
+
const [commentsAppId, setCommentsAppId] = React47.useState(null);
|
|
9450
|
+
const [commentsCount, setCommentsCount] = React47.useState(null);
|
|
9020
9451
|
const threadId = (app == null ? void 0 : app.threadId) ?? null;
|
|
9021
9452
|
const isForking = chatForking || (app == null ? void 0 : app.status) === "forking";
|
|
9022
9453
|
const isBubbleLoading = (app == null ? void 0 : app.status) === "editing" || isBaseBundleDownloading;
|
|
@@ -9029,26 +9460,26 @@ function StudioOverlay({
|
|
|
9029
9460
|
chatMessages,
|
|
9030
9461
|
onSendChat
|
|
9031
9462
|
});
|
|
9032
|
-
const [confirmMrId, setConfirmMrId] =
|
|
9033
|
-
const confirmMr =
|
|
9463
|
+
const [confirmMrId, setConfirmMrId] = React47.useState(null);
|
|
9464
|
+
const confirmMr = React47.useMemo(
|
|
9034
9465
|
() => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
|
|
9035
9466
|
[confirmMrId, incomingMergeRequests]
|
|
9036
9467
|
);
|
|
9037
|
-
const handleSheetOpenChange =
|
|
9468
|
+
const handleSheetOpenChange = React47.useCallback((open) => {
|
|
9038
9469
|
setSheetOpen(open);
|
|
9039
|
-
if (!open)
|
|
9470
|
+
if (!open) import_react_native62.Keyboard.dismiss();
|
|
9040
9471
|
}, []);
|
|
9041
|
-
const closeSheet =
|
|
9472
|
+
const closeSheet = React47.useCallback(() => {
|
|
9042
9473
|
handleSheetOpenChange(false);
|
|
9043
9474
|
}, [handleSheetOpenChange]);
|
|
9044
|
-
const openSheet =
|
|
9045
|
-
const goToChat =
|
|
9475
|
+
const openSheet = React47.useCallback(() => setSheetOpen(true), []);
|
|
9476
|
+
const goToChat = React47.useCallback(() => {
|
|
9046
9477
|
setActivePage("chat");
|
|
9047
9478
|
openSheet();
|
|
9048
9479
|
}, [openSheet]);
|
|
9049
|
-
const backToPreview =
|
|
9050
|
-
if (
|
|
9051
|
-
|
|
9480
|
+
const backToPreview = React47.useCallback(() => {
|
|
9481
|
+
if (import_react_native62.Platform.OS !== "ios") {
|
|
9482
|
+
import_react_native62.Keyboard.dismiss();
|
|
9052
9483
|
setActivePage("preview");
|
|
9053
9484
|
return;
|
|
9054
9485
|
}
|
|
@@ -9060,15 +9491,15 @@ function StudioOverlay({
|
|
|
9060
9491
|
clearTimeout(t);
|
|
9061
9492
|
setActivePage("preview");
|
|
9062
9493
|
};
|
|
9063
|
-
const sub =
|
|
9494
|
+
const sub = import_react_native62.Keyboard.addListener("keyboardDidHide", finalize);
|
|
9064
9495
|
const t = setTimeout(finalize, 350);
|
|
9065
|
-
|
|
9496
|
+
import_react_native62.Keyboard.dismiss();
|
|
9066
9497
|
}, []);
|
|
9067
|
-
const startDraw =
|
|
9498
|
+
const startDraw = React47.useCallback(() => {
|
|
9068
9499
|
setDrawing(true);
|
|
9069
9500
|
closeSheet();
|
|
9070
9501
|
}, [closeSheet]);
|
|
9071
|
-
const handleDrawCapture =
|
|
9502
|
+
const handleDrawCapture = React47.useCallback(
|
|
9072
9503
|
(dataUrl) => {
|
|
9073
9504
|
setChatAttachments((prev) => [...prev, dataUrl]);
|
|
9074
9505
|
setDrawing(false);
|
|
@@ -9077,7 +9508,7 @@ function StudioOverlay({
|
|
|
9077
9508
|
},
|
|
9078
9509
|
[openSheet]
|
|
9079
9510
|
);
|
|
9080
|
-
const toggleSheet =
|
|
9511
|
+
const toggleSheet = React47.useCallback(async () => {
|
|
9081
9512
|
if (!sheetOpen) {
|
|
9082
9513
|
const shouldExitTest = Boolean(testingMrId) || isTesting;
|
|
9083
9514
|
if (shouldExitTest) {
|
|
@@ -9089,7 +9520,7 @@ function StudioOverlay({
|
|
|
9089
9520
|
closeSheet();
|
|
9090
9521
|
}
|
|
9091
9522
|
}, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
|
|
9092
|
-
const handleTestMr =
|
|
9523
|
+
const handleTestMr = React47.useCallback(
|
|
9093
9524
|
async (mr) => {
|
|
9094
9525
|
if (!onTestMr) return;
|
|
9095
9526
|
await onTestMr(mr);
|
|
@@ -9097,46 +9528,46 @@ function StudioOverlay({
|
|
|
9097
9528
|
},
|
|
9098
9529
|
[closeSheet, onTestMr]
|
|
9099
9530
|
);
|
|
9100
|
-
const handleNavigateHome =
|
|
9531
|
+
const handleNavigateHome = React47.useCallback(() => {
|
|
9101
9532
|
if (!onNavigateHome) return;
|
|
9102
|
-
if (
|
|
9533
|
+
if (import_react_native62.Platform.OS !== "android") {
|
|
9103
9534
|
onNavigateHome();
|
|
9104
9535
|
return;
|
|
9105
9536
|
}
|
|
9106
9537
|
if (!sheetOpenRef.current) {
|
|
9107
|
-
|
|
9538
|
+
import_react_native62.InteractionManager.runAfterInteractions(() => {
|
|
9108
9539
|
onNavigateHome();
|
|
9109
9540
|
});
|
|
9110
9541
|
return;
|
|
9111
9542
|
}
|
|
9112
9543
|
pendingNavigateHomeRef.current = true;
|
|
9113
|
-
|
|
9544
|
+
import_react_native62.Keyboard.dismiss();
|
|
9114
9545
|
setActivePage("preview");
|
|
9115
9546
|
closeSheet();
|
|
9116
9547
|
}, [closeSheet, onNavigateHome]);
|
|
9117
|
-
const handleSheetDismiss =
|
|
9118
|
-
if (
|
|
9548
|
+
const handleSheetDismiss = React47.useCallback(() => {
|
|
9549
|
+
if (import_react_native62.Platform.OS !== "android") return;
|
|
9119
9550
|
if (!pendingNavigateHomeRef.current) return;
|
|
9120
9551
|
pendingNavigateHomeRef.current = false;
|
|
9121
|
-
|
|
9552
|
+
import_react_native62.InteractionManager.runAfterInteractions(() => {
|
|
9122
9553
|
onNavigateHome == null ? void 0 : onNavigateHome();
|
|
9123
9554
|
});
|
|
9124
9555
|
}, [onNavigateHome]);
|
|
9125
|
-
|
|
9556
|
+
React47.useEffect(() => {
|
|
9126
9557
|
if (!sheetOpen) {
|
|
9127
9558
|
return;
|
|
9128
9559
|
}
|
|
9129
9560
|
pendingNavigateHomeRef.current = false;
|
|
9130
9561
|
}, [sheetOpen]);
|
|
9131
|
-
|
|
9562
|
+
React47.useEffect(() => {
|
|
9132
9563
|
return () => {
|
|
9133
9564
|
pendingNavigateHomeRef.current = false;
|
|
9134
9565
|
};
|
|
9135
9566
|
}, []);
|
|
9136
|
-
|
|
9567
|
+
React47.useEffect(() => {
|
|
9137
9568
|
sheetOpenRef.current = sheetOpen;
|
|
9138
9569
|
}, [sheetOpen]);
|
|
9139
|
-
|
|
9570
|
+
React47.useEffect(() => {
|
|
9140
9571
|
const poller = (0, import_studio_control.startStudioControlPolling)((action) => {
|
|
9141
9572
|
if (action === "show" && !sheetOpenRef.current) openSheet();
|
|
9142
9573
|
if (action === "hide" && sheetOpenRef.current) closeSheet();
|
|
@@ -9144,17 +9575,17 @@ function StudioOverlay({
|
|
|
9144
9575
|
}, studioControlOptions);
|
|
9145
9576
|
return () => poller.stop();
|
|
9146
9577
|
}, [closeSheet, openSheet, studioControlOptions, toggleSheet]);
|
|
9147
|
-
|
|
9578
|
+
React47.useEffect(() => {
|
|
9148
9579
|
void (0, import_studio_control.publishComergeStudioUIState)(sheetOpen, studioControlOptions);
|
|
9149
9580
|
}, [sheetOpen, studioControlOptions]);
|
|
9150
|
-
return /* @__PURE__ */ (0,
|
|
9151
|
-
/* @__PURE__ */ (0,
|
|
9152
|
-
/* @__PURE__ */ (0,
|
|
9581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_jsx_runtime65.Fragment, { children: [
|
|
9582
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(EdgeGlowFrame, { visible: isTesting, role: "accent", thickness: 40, intensity: 1 }),
|
|
9583
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(StudioBottomSheet, { open: sheetOpen, onOpenChange: handleSheetOpenChange, onDismiss: handleSheetDismiss, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9153
9584
|
StudioSheetPager,
|
|
9154
9585
|
{
|
|
9155
9586
|
activePage,
|
|
9156
9587
|
width,
|
|
9157
|
-
preview: /* @__PURE__ */ (0,
|
|
9588
|
+
preview: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9158
9589
|
PreviewPanel,
|
|
9159
9590
|
{
|
|
9160
9591
|
app,
|
|
@@ -9188,7 +9619,7 @@ function StudioOverlay({
|
|
|
9188
9619
|
onSwitchRelatedApp
|
|
9189
9620
|
}
|
|
9190
9621
|
),
|
|
9191
|
-
chat: /* @__PURE__ */ (0,
|
|
9622
|
+
chat: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9192
9623
|
ChatPanel,
|
|
9193
9624
|
{
|
|
9194
9625
|
messages: optimistic.messages,
|
|
@@ -9208,6 +9639,7 @@ function StudioOverlay({
|
|
|
9208
9639
|
onSend: optimistic.onSend,
|
|
9209
9640
|
onRetryMessage: optimistic.onRetry,
|
|
9210
9641
|
isRetryingMessage: optimistic.isRetrying,
|
|
9642
|
+
onAttachmentLoadError: onChatAttachmentLoadError,
|
|
9211
9643
|
queueItems: queueItemsForChat,
|
|
9212
9644
|
onRemoveQueueItem,
|
|
9213
9645
|
progress: chatProgress
|
|
@@ -9215,7 +9647,7 @@ function StudioOverlay({
|
|
|
9215
9647
|
)
|
|
9216
9648
|
}
|
|
9217
9649
|
) }),
|
|
9218
|
-
showBubble && /* @__PURE__ */ (0,
|
|
9650
|
+
showBubble && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9219
9651
|
Bubble,
|
|
9220
9652
|
{
|
|
9221
9653
|
visible: !sheetOpen && !drawing,
|
|
@@ -9224,10 +9656,10 @@ function StudioOverlay({
|
|
|
9224
9656
|
onPress: toggleSheet,
|
|
9225
9657
|
isLoading: isBubbleLoading,
|
|
9226
9658
|
loadingBorderTone: isBaseBundleDownloading ? "warning" : "default",
|
|
9227
|
-
children: /* @__PURE__ */ (0,
|
|
9659
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_react_native62.View, { style: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, children: isBubbleLoading ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RemixXLoopLottie, { size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RemixUpIcon, { width: 24, height: 24 }) })
|
|
9228
9660
|
}
|
|
9229
9661
|
),
|
|
9230
|
-
/* @__PURE__ */ (0,
|
|
9662
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9231
9663
|
DrawModeOverlay,
|
|
9232
9664
|
{
|
|
9233
9665
|
visible: drawing,
|
|
@@ -9236,7 +9668,7 @@ function StudioOverlay({
|
|
|
9236
9668
|
onCapture: handleDrawCapture
|
|
9237
9669
|
}
|
|
9238
9670
|
),
|
|
9239
|
-
/* @__PURE__ */ (0,
|
|
9671
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9240
9672
|
ConfirmMergeFlow,
|
|
9241
9673
|
{
|
|
9242
9674
|
visible: Boolean(confirmMr),
|
|
@@ -9250,7 +9682,7 @@ function StudioOverlay({
|
|
|
9250
9682
|
onTestFirst: handleTestMr
|
|
9251
9683
|
}
|
|
9252
9684
|
),
|
|
9253
|
-
/* @__PURE__ */ (0,
|
|
9685
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
9254
9686
|
AppCommentsSheet,
|
|
9255
9687
|
{
|
|
9256
9688
|
appId: commentsAppId,
|
|
@@ -9263,7 +9695,7 @@ function StudioOverlay({
|
|
|
9263
9695
|
}
|
|
9264
9696
|
|
|
9265
9697
|
// src/studio/hooks/useEditQueue.ts
|
|
9266
|
-
var
|
|
9698
|
+
var React48 = __toESM(require("react"));
|
|
9267
9699
|
|
|
9268
9700
|
// src/data/apps/edit-queue/remote.ts
|
|
9269
9701
|
var EditQueueRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -9372,17 +9804,17 @@ var editQueueRepository = new EditQueueRepositoryImpl(
|
|
|
9372
9804
|
|
|
9373
9805
|
// src/studio/hooks/useEditQueue.ts
|
|
9374
9806
|
function useEditQueue(appId) {
|
|
9375
|
-
const [items, setItems] =
|
|
9376
|
-
const [loading, setLoading] =
|
|
9377
|
-
const [error, setError] =
|
|
9378
|
-
const activeRequestIdRef =
|
|
9807
|
+
const [items, setItems] = React48.useState([]);
|
|
9808
|
+
const [loading, setLoading] = React48.useState(false);
|
|
9809
|
+
const [error, setError] = React48.useState(null);
|
|
9810
|
+
const activeRequestIdRef = React48.useRef(0);
|
|
9379
9811
|
const foregroundSignal = useForegroundSignal(Boolean(appId));
|
|
9380
|
-
const upsertSorted =
|
|
9812
|
+
const upsertSorted = React48.useCallback((prev, nextItem) => {
|
|
9381
9813
|
const next = prev.some((x) => x.id === nextItem.id) ? prev.map((x) => x.id === nextItem.id ? nextItem : x) : [...prev, nextItem];
|
|
9382
9814
|
next.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
9383
9815
|
return next;
|
|
9384
9816
|
}, []);
|
|
9385
|
-
const refetch =
|
|
9817
|
+
const refetch = React48.useCallback(async () => {
|
|
9386
9818
|
if (!appId) {
|
|
9387
9819
|
setItems([]);
|
|
9388
9820
|
return;
|
|
@@ -9402,10 +9834,10 @@ function useEditQueue(appId) {
|
|
|
9402
9834
|
if (activeRequestIdRef.current === requestId) setLoading(false);
|
|
9403
9835
|
}
|
|
9404
9836
|
}, [appId]);
|
|
9405
|
-
|
|
9837
|
+
React48.useEffect(() => {
|
|
9406
9838
|
void refetch();
|
|
9407
9839
|
}, [refetch]);
|
|
9408
|
-
|
|
9840
|
+
React48.useEffect(() => {
|
|
9409
9841
|
if (!appId) return;
|
|
9410
9842
|
const unsubscribe = editQueueRepository.subscribeEditQueue(appId, {
|
|
9411
9843
|
onInsert: (item) => setItems((prev) => upsertSorted(prev, item)),
|
|
@@ -9414,7 +9846,7 @@ function useEditQueue(appId) {
|
|
|
9414
9846
|
});
|
|
9415
9847
|
return unsubscribe;
|
|
9416
9848
|
}, [appId, upsertSorted, foregroundSignal]);
|
|
9417
|
-
|
|
9849
|
+
React48.useEffect(() => {
|
|
9418
9850
|
if (!appId) return;
|
|
9419
9851
|
if (foregroundSignal <= 0) return;
|
|
9420
9852
|
void refetch();
|
|
@@ -9423,16 +9855,16 @@ function useEditQueue(appId) {
|
|
|
9423
9855
|
}
|
|
9424
9856
|
|
|
9425
9857
|
// src/studio/hooks/useEditQueueActions.ts
|
|
9426
|
-
var
|
|
9858
|
+
var React49 = __toESM(require("react"));
|
|
9427
9859
|
function useEditQueueActions(appId) {
|
|
9428
|
-
const update =
|
|
9860
|
+
const update = React49.useCallback(
|
|
9429
9861
|
async (queueItemId, payload) => {
|
|
9430
9862
|
if (!appId) return;
|
|
9431
9863
|
await editQueueRepository.update(appId, queueItemId, payload);
|
|
9432
9864
|
},
|
|
9433
9865
|
[appId]
|
|
9434
9866
|
);
|
|
9435
|
-
const cancel =
|
|
9867
|
+
const cancel = React49.useCallback(
|
|
9436
9868
|
async (queueItemId) => {
|
|
9437
9869
|
if (!appId) return;
|
|
9438
9870
|
await editQueueRepository.cancel(appId, queueItemId);
|
|
@@ -9443,7 +9875,7 @@ function useEditQueueActions(appId) {
|
|
|
9443
9875
|
}
|
|
9444
9876
|
|
|
9445
9877
|
// src/studio/hooks/useAgentRunProgress.ts
|
|
9446
|
-
var
|
|
9878
|
+
var React50 = __toESM(require("react"));
|
|
9447
9879
|
|
|
9448
9880
|
// src/data/agent-progress/repository.ts
|
|
9449
9881
|
function mapRun(row) {
|
|
@@ -9709,23 +10141,23 @@ function deriveView(run, events, nowMs) {
|
|
|
9709
10141
|
function useAgentRunProgress(threadId, opts) {
|
|
9710
10142
|
var _a;
|
|
9711
10143
|
const enabled = Boolean((opts == null ? void 0 : opts.enabled) ?? true);
|
|
9712
|
-
const [run, setRun] =
|
|
9713
|
-
const [events, setEvents] =
|
|
9714
|
-
const [loading, setLoading] =
|
|
9715
|
-
const [error, setError] =
|
|
9716
|
-
const activeRequestIdRef =
|
|
9717
|
-
const lastSeqRef =
|
|
9718
|
-
const runRef =
|
|
10144
|
+
const [run, setRun] = React50.useState(null);
|
|
10145
|
+
const [events, setEvents] = React50.useState([]);
|
|
10146
|
+
const [loading, setLoading] = React50.useState(false);
|
|
10147
|
+
const [error, setError] = React50.useState(null);
|
|
10148
|
+
const activeRequestIdRef = React50.useRef(0);
|
|
10149
|
+
const lastSeqRef = React50.useRef(0);
|
|
10150
|
+
const runRef = React50.useRef(null);
|
|
9719
10151
|
const foregroundSignal = useForegroundSignal(Boolean(threadId) && enabled);
|
|
9720
|
-
const [bundleTick, setBundleTick] =
|
|
9721
|
-
|
|
10152
|
+
const [bundleTick, setBundleTick] = React50.useState(0);
|
|
10153
|
+
React50.useEffect(() => {
|
|
9722
10154
|
lastSeqRef.current = 0;
|
|
9723
10155
|
runRef.current = null;
|
|
9724
10156
|
}, [threadId]);
|
|
9725
|
-
|
|
10157
|
+
React50.useEffect(() => {
|
|
9726
10158
|
runRef.current = run;
|
|
9727
10159
|
}, [run]);
|
|
9728
|
-
const refetch =
|
|
10160
|
+
const refetch = React50.useCallback(async () => {
|
|
9729
10161
|
if (!threadId || !enabled) {
|
|
9730
10162
|
setRun(null);
|
|
9731
10163
|
setEvents([]);
|
|
@@ -9761,15 +10193,15 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9761
10193
|
if (activeRequestIdRef.current === requestId) setLoading(false);
|
|
9762
10194
|
}
|
|
9763
10195
|
}, [enabled, threadId]);
|
|
9764
|
-
|
|
10196
|
+
React50.useEffect(() => {
|
|
9765
10197
|
void refetch();
|
|
9766
10198
|
}, [refetch]);
|
|
9767
|
-
|
|
10199
|
+
React50.useEffect(() => {
|
|
9768
10200
|
if (!threadId || !enabled) return;
|
|
9769
10201
|
if (foregroundSignal <= 0) return;
|
|
9770
10202
|
void refetch();
|
|
9771
10203
|
}, [enabled, foregroundSignal, refetch, threadId]);
|
|
9772
|
-
|
|
10204
|
+
React50.useEffect(() => {
|
|
9773
10205
|
if (!threadId || !enabled) return;
|
|
9774
10206
|
const unsubRuns = agentProgressRepository.subscribeThreadRuns(threadId, {
|
|
9775
10207
|
onInsert: (nextRun) => {
|
|
@@ -9799,7 +10231,7 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9799
10231
|
});
|
|
9800
10232
|
return unsubRuns;
|
|
9801
10233
|
}, [enabled, threadId, foregroundSignal]);
|
|
9802
|
-
|
|
10234
|
+
React50.useEffect(() => {
|
|
9803
10235
|
if (!enabled || !(run == null ? void 0 : run.id)) return;
|
|
9804
10236
|
const runId = run.id;
|
|
9805
10237
|
const processIncoming = (incoming) => {
|
|
@@ -9831,8 +10263,8 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9831
10263
|
});
|
|
9832
10264
|
return unsubscribe;
|
|
9833
10265
|
}, [enabled, run == null ? void 0 : run.id, foregroundSignal]);
|
|
9834
|
-
const view =
|
|
9835
|
-
|
|
10266
|
+
const view = React50.useMemo(() => deriveView(run, events, Date.now()), [bundleTick, events, run]);
|
|
10267
|
+
React50.useEffect(() => {
|
|
9836
10268
|
var _a2;
|
|
9837
10269
|
if (!((_a2 = view.bundle) == null ? void 0 : _a2.active)) return;
|
|
9838
10270
|
const interval = setInterval(() => {
|
|
@@ -9845,13 +10277,13 @@ function useAgentRunProgress(threadId, opts) {
|
|
|
9845
10277
|
}
|
|
9846
10278
|
|
|
9847
10279
|
// src/studio/hooks/useRelatedApps.ts
|
|
9848
|
-
var
|
|
10280
|
+
var React51 = __toESM(require("react"));
|
|
9849
10281
|
function useRelatedApps(appId) {
|
|
9850
|
-
const [relatedApps, setRelatedApps] =
|
|
9851
|
-
const [loading, setLoading] =
|
|
9852
|
-
const [error, setError] =
|
|
9853
|
-
const requestSeqRef =
|
|
9854
|
-
const fetchRelatedApps =
|
|
10282
|
+
const [relatedApps, setRelatedApps] = React51.useState(null);
|
|
10283
|
+
const [loading, setLoading] = React51.useState(false);
|
|
10284
|
+
const [error, setError] = React51.useState(null);
|
|
10285
|
+
const requestSeqRef = React51.useRef(0);
|
|
10286
|
+
const fetchRelatedApps = React51.useCallback(async () => {
|
|
9855
10287
|
if (!appId) {
|
|
9856
10288
|
setRelatedApps(null);
|
|
9857
10289
|
setError(null);
|
|
@@ -9877,7 +10309,7 @@ function useRelatedApps(appId) {
|
|
|
9877
10309
|
}
|
|
9878
10310
|
}
|
|
9879
10311
|
}, [appId]);
|
|
9880
|
-
|
|
10312
|
+
React51.useEffect(() => {
|
|
9881
10313
|
void fetchRelatedApps();
|
|
9882
10314
|
}, [fetchRelatedApps]);
|
|
9883
10315
|
return {
|
|
@@ -9889,7 +10321,7 @@ function useRelatedApps(appId) {
|
|
|
9889
10321
|
}
|
|
9890
10322
|
|
|
9891
10323
|
// src/studio/ComergeStudio.tsx
|
|
9892
|
-
var
|
|
10324
|
+
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
9893
10325
|
function ComergeStudio({
|
|
9894
10326
|
appId,
|
|
9895
10327
|
clientKey: clientKey2,
|
|
@@ -9905,13 +10337,13 @@ function ComergeStudio({
|
|
|
9905
10337
|
embeddedBaseBundles,
|
|
9906
10338
|
onSystemEvent
|
|
9907
10339
|
}) {
|
|
9908
|
-
const [activeAppId, setActiveAppId] =
|
|
9909
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
9910
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
9911
|
-
const didSyncFromHostRef =
|
|
9912
|
-
const lastNotifiedRef =
|
|
9913
|
-
const platform =
|
|
9914
|
-
const notifyActiveAppChanged =
|
|
10340
|
+
const [activeAppId, setActiveAppId] = React52.useState(appId);
|
|
10341
|
+
const [runtimeAppId, setRuntimeAppId] = React52.useState(appId);
|
|
10342
|
+
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React52.useState(null);
|
|
10343
|
+
const didSyncFromHostRef = React52.useRef(false);
|
|
10344
|
+
const lastNotifiedRef = React52.useRef(null);
|
|
10345
|
+
const platform = React52.useMemo(() => import_react_native63.Platform.OS === "ios" ? "ios" : "android", []);
|
|
10346
|
+
const notifyActiveAppChanged = React52.useCallback(
|
|
9915
10347
|
(nextAppId, source) => {
|
|
9916
10348
|
if (!onActiveAppChanged) return;
|
|
9917
10349
|
const trimmedAppId = nextAppId.trim();
|
|
@@ -9924,28 +10356,28 @@ function ComergeStudio({
|
|
|
9924
10356
|
},
|
|
9925
10357
|
[appKey, onActiveAppChanged]
|
|
9926
10358
|
);
|
|
9927
|
-
const setActiveAppIdWithSource =
|
|
10359
|
+
const setActiveAppIdWithSource = React52.useCallback(
|
|
9928
10360
|
(nextAppId, source) => {
|
|
9929
10361
|
setActiveAppId(nextAppId);
|
|
9930
10362
|
notifyActiveAppChanged(nextAppId, source);
|
|
9931
10363
|
},
|
|
9932
10364
|
[notifyActiveAppChanged]
|
|
9933
10365
|
);
|
|
9934
|
-
|
|
10366
|
+
React52.useEffect(() => {
|
|
9935
10367
|
const source = didSyncFromHostRef.current ? "host_route_sync" : "initial";
|
|
9936
10368
|
didSyncFromHostRef.current = true;
|
|
9937
10369
|
setActiveAppIdWithSource(appId, source);
|
|
9938
10370
|
setRuntimeAppId(appId);
|
|
9939
10371
|
setPendingRuntimeTargetAppId(null);
|
|
9940
10372
|
}, [appId, setActiveAppIdWithSource]);
|
|
9941
|
-
const captureTargetRef =
|
|
9942
|
-
return /* @__PURE__ */ (0,
|
|
10373
|
+
const captureTargetRef = React52.useRef(null);
|
|
10374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
9943
10375
|
StudioBootstrap,
|
|
9944
10376
|
{
|
|
9945
10377
|
clientKey: clientKey2,
|
|
9946
10378
|
analyticsEnabled,
|
|
9947
|
-
fallback: /* @__PURE__ */ (0,
|
|
9948
|
-
children: ({ userId }) => /* @__PURE__ */ (0,
|
|
10379
|
+
fallback: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_react_native63.View, { style: { flex: 1 } }),
|
|
10380
|
+
children: ({ userId }) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_bottom_sheet6.BottomSheetModalProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
9949
10381
|
ComergeStudioInner,
|
|
9950
10382
|
{
|
|
9951
10383
|
userId,
|
|
@@ -9995,11 +10427,11 @@ function ComergeStudioInner({
|
|
|
9995
10427
|
const { app, loading: appLoading } = useApp(activeAppId);
|
|
9996
10428
|
const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
|
|
9997
10429
|
const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
|
|
9998
|
-
const sawEditingOnPendingTargetRef =
|
|
9999
|
-
|
|
10430
|
+
const sawEditingOnPendingTargetRef = React52.useRef(false);
|
|
10431
|
+
React52.useEffect(() => {
|
|
10000
10432
|
sawEditingOnPendingTargetRef.current = false;
|
|
10001
10433
|
}, [pendingRuntimeTargetAppId]);
|
|
10002
|
-
|
|
10434
|
+
React52.useEffect(() => {
|
|
10003
10435
|
if (!pendingRuntimeTargetAppId) return;
|
|
10004
10436
|
if (activeAppId !== pendingRuntimeTargetAppId) return;
|
|
10005
10437
|
if ((app == null ? void 0 : app.status) === "editing") {
|
|
@@ -10017,13 +10449,13 @@ function ComergeStudioInner({
|
|
|
10017
10449
|
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready",
|
|
10018
10450
|
embeddedBaseBundles
|
|
10019
10451
|
});
|
|
10020
|
-
const sawEditingOnActiveAppRef =
|
|
10021
|
-
const [showPostEditPreparing, setShowPostEditPreparing] =
|
|
10022
|
-
|
|
10452
|
+
const sawEditingOnActiveAppRef = React52.useRef(false);
|
|
10453
|
+
const [showPostEditPreparing, setShowPostEditPreparing] = React52.useState(false);
|
|
10454
|
+
React52.useEffect(() => {
|
|
10023
10455
|
sawEditingOnActiveAppRef.current = false;
|
|
10024
10456
|
setShowPostEditPreparing(false);
|
|
10025
10457
|
}, [activeAppId]);
|
|
10026
|
-
|
|
10458
|
+
React52.useEffect(() => {
|
|
10027
10459
|
if (!(app == null ? void 0 : app.id)) return;
|
|
10028
10460
|
if (app.status === "editing") {
|
|
10029
10461
|
sawEditingOnActiveAppRef.current = true;
|
|
@@ -10035,7 +10467,7 @@ function ComergeStudioInner({
|
|
|
10035
10467
|
sawEditingOnActiveAppRef.current = false;
|
|
10036
10468
|
}
|
|
10037
10469
|
}, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
|
|
10038
|
-
|
|
10470
|
+
React52.useEffect(() => {
|
|
10039
10471
|
if (!showPostEditPreparing) return;
|
|
10040
10472
|
const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
10041
10473
|
if (!stillProcessingBaseBundle) {
|
|
@@ -10047,19 +10479,19 @@ function ComergeStudioInner({
|
|
|
10047
10479
|
const editQueue = useEditQueue(activeAppId);
|
|
10048
10480
|
const agentProgress = useAgentRunProgress(threadId, { enabled: enableAgentProgress });
|
|
10049
10481
|
const editQueueActions = useEditQueueActions(activeAppId);
|
|
10050
|
-
const [lastEditQueueInfo, setLastEditQueueInfo] =
|
|
10051
|
-
const lastEditQueueInfoRef =
|
|
10052
|
-
const [suppressQueueUntilResponse, setSuppressQueueUntilResponse] =
|
|
10482
|
+
const [lastEditQueueInfo, setLastEditQueueInfo] = React52.useState(null);
|
|
10483
|
+
const lastEditQueueInfoRef = React52.useRef(null);
|
|
10484
|
+
const [suppressQueueUntilResponse, setSuppressQueueUntilResponse] = React52.useState(false);
|
|
10053
10485
|
const mergeRequests = useMergeRequests({ appId: activeAppId });
|
|
10054
|
-
const hasOpenOutgoingMr =
|
|
10486
|
+
const hasOpenOutgoingMr = React52.useMemo(() => {
|
|
10055
10487
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
10056
10488
|
}, [mergeRequests.lists.outgoing]);
|
|
10057
|
-
const incomingReviewMrs =
|
|
10489
|
+
const incomingReviewMrs = React52.useMemo(() => {
|
|
10058
10490
|
if (!userId) return mergeRequests.lists.incoming;
|
|
10059
10491
|
return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
|
|
10060
10492
|
}, [mergeRequests.lists.incoming, userId]);
|
|
10061
10493
|
const uploader = useAttachmentUpload();
|
|
10062
|
-
const updateLastEditQueueInfo =
|
|
10494
|
+
const updateLastEditQueueInfo = React52.useCallback(
|
|
10063
10495
|
(info) => {
|
|
10064
10496
|
lastEditQueueInfoRef.current = info;
|
|
10065
10497
|
setLastEditQueueInfo(info);
|
|
@@ -10101,13 +10533,13 @@ function ComergeStudioInner({
|
|
|
10101
10533
|
}
|
|
10102
10534
|
});
|
|
10103
10535
|
const chatSendDisabled = false;
|
|
10104
|
-
const [processingMrId, setProcessingMrId] =
|
|
10105
|
-
const [testingMrId, setTestingMrId] =
|
|
10106
|
-
const [syncingUpstream, setSyncingUpstream] =
|
|
10107
|
-
const [upstreamSyncStatus, setUpstreamSyncStatus] =
|
|
10536
|
+
const [processingMrId, setProcessingMrId] = React52.useState(null);
|
|
10537
|
+
const [testingMrId, setTestingMrId] = React52.useState(null);
|
|
10538
|
+
const [syncingUpstream, setSyncingUpstream] = React52.useState(false);
|
|
10539
|
+
const [upstreamSyncStatus, setUpstreamSyncStatus] = React52.useState(null);
|
|
10108
10540
|
const isMrTestBuildInProgress = bundle.loading && bundle.loadingMode === "test";
|
|
10109
10541
|
const isBaseBundleDownloading = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
10110
|
-
const runtimePreparingText =
|
|
10542
|
+
const runtimePreparingText = React52.useMemo(() => {
|
|
10111
10543
|
const status = app == null ? void 0 : app.status;
|
|
10112
10544
|
if (status === "ready" && bundle.bundleStatus === "pending") {
|
|
10113
10545
|
return "Bundling app\u2026 this may take a few minutes";
|
|
@@ -10127,7 +10559,7 @@ function ComergeStudioInner({
|
|
|
10127
10559
|
return "Preparing app\u2026";
|
|
10128
10560
|
}
|
|
10129
10561
|
}, [app == null ? void 0 : app.status, bundle.bundleStatus]);
|
|
10130
|
-
const chatShowTypingIndicator =
|
|
10562
|
+
const chatShowTypingIndicator = React52.useMemo(() => {
|
|
10131
10563
|
var _a2;
|
|
10132
10564
|
if (agentProgress.hasLiveProgress) return false;
|
|
10133
10565
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
@@ -10136,12 +10568,12 @@ function ComergeStudioInner({
|
|
|
10136
10568
|
return payloadType !== "outcome";
|
|
10137
10569
|
}, [agentProgress.hasLiveProgress, thread.raw]);
|
|
10138
10570
|
const showChatProgress = agentProgress.hasLiveProgress || Boolean((_a = agentProgress.view.bundle) == null ? void 0 : _a.active);
|
|
10139
|
-
|
|
10571
|
+
React52.useEffect(() => {
|
|
10140
10572
|
updateLastEditQueueInfo(null);
|
|
10141
10573
|
setSuppressQueueUntilResponse(false);
|
|
10142
10574
|
setUpstreamSyncStatus(null);
|
|
10143
10575
|
}, [activeAppId, updateLastEditQueueInfo]);
|
|
10144
|
-
const handleSyncUpstream =
|
|
10576
|
+
const handleSyncUpstream = React52.useCallback(async () => {
|
|
10145
10577
|
if (!(app == null ? void 0 : app.id)) {
|
|
10146
10578
|
throw new Error("Missing app");
|
|
10147
10579
|
}
|
|
@@ -10154,7 +10586,7 @@ function ComergeStudioInner({
|
|
|
10154
10586
|
setSyncingUpstream(false);
|
|
10155
10587
|
}
|
|
10156
10588
|
}, [activeAppId, app == null ? void 0 : app.id]);
|
|
10157
|
-
|
|
10589
|
+
React52.useEffect(() => {
|
|
10158
10590
|
if (!(lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId)) return;
|
|
10159
10591
|
const stillPresent = editQueue.items.some((item) => item.id === lastEditQueueInfo.queueItemId);
|
|
10160
10592
|
if (!stillPresent) {
|
|
@@ -10162,7 +10594,7 @@ function ComergeStudioInner({
|
|
|
10162
10594
|
setSuppressQueueUntilResponse(false);
|
|
10163
10595
|
}
|
|
10164
10596
|
}, [editQueue.items, lastEditQueueInfo == null ? void 0 : lastEditQueueInfo.queueItemId]);
|
|
10165
|
-
const chatQueueItems =
|
|
10597
|
+
const chatQueueItems = React52.useMemo(() => {
|
|
10166
10598
|
var _a2;
|
|
10167
10599
|
if (suppressQueueUntilResponse && editQueue.items.length <= 1) {
|
|
10168
10600
|
return [];
|
|
@@ -10176,8 +10608,8 @@ function ComergeStudioInner({
|
|
|
10176
10608
|
return editQueue.items;
|
|
10177
10609
|
}, [editQueue.items, lastEditQueueInfo, suppressQueueUntilResponse]);
|
|
10178
10610
|
const { relatedApps, loading: relatedAppsLoading } = useRelatedApps(activeAppId);
|
|
10179
|
-
const [switchingRelatedAppId, setSwitchingRelatedAppId] =
|
|
10180
|
-
const handleOpenRelatedApps =
|
|
10611
|
+
const [switchingRelatedAppId, setSwitchingRelatedAppId] = React52.useState(null);
|
|
10612
|
+
const handleOpenRelatedApps = React52.useCallback(() => {
|
|
10181
10613
|
var _a2;
|
|
10182
10614
|
if (!relatedApps) return;
|
|
10183
10615
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -10186,7 +10618,7 @@ function ComergeStudioInner({
|
|
|
10186
10618
|
for (const remix of relatedApps.remixes) ids.add(remix.id);
|
|
10187
10619
|
void trackRelatedAppsOpened({ appId: relatedApps.current.id, relatedCount: ids.size });
|
|
10188
10620
|
}, [relatedApps]);
|
|
10189
|
-
const handleSwitchRelatedApp =
|
|
10621
|
+
const handleSwitchRelatedApp = React52.useCallback(
|
|
10190
10622
|
async (targetAppId) => {
|
|
10191
10623
|
var _a2;
|
|
10192
10624
|
if (!targetAppId || targetAppId === activeAppId) return;
|
|
@@ -10247,8 +10679,8 @@ function ComergeStudioInner({
|
|
|
10247
10679
|
setRuntimeAppId
|
|
10248
10680
|
]
|
|
10249
10681
|
);
|
|
10250
|
-
return /* @__PURE__ */ (0,
|
|
10251
|
-
/* @__PURE__ */ (0,
|
|
10682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_react_native63.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_react_native63.View, { ref: captureTargetRef, style: { flex: 1 }, collapsable: false, children: [
|
|
10683
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
10252
10684
|
RuntimeRenderer,
|
|
10253
10685
|
{
|
|
10254
10686
|
appKey,
|
|
@@ -10272,7 +10704,7 @@ function ComergeStudioInner({
|
|
|
10272
10704
|
}
|
|
10273
10705
|
}
|
|
10274
10706
|
),
|
|
10275
|
-
/* @__PURE__ */ (0,
|
|
10707
|
+
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
|
|
10276
10708
|
StudioOverlay,
|
|
10277
10709
|
{
|
|
10278
10710
|
captureTargetRef,
|
|
@@ -10329,6 +10761,9 @@ function ComergeStudioInner({
|
|
|
10329
10761
|
chatSending: actions.sending,
|
|
10330
10762
|
chatShowTypingIndicator,
|
|
10331
10763
|
onSendChat: (text, attachments) => actions.sendEdit({ prompt: text, attachments }),
|
|
10764
|
+
onChatAttachmentLoadError: () => {
|
|
10765
|
+
thread.recoverAttachmentUrls();
|
|
10766
|
+
},
|
|
10332
10767
|
chatQueueItems,
|
|
10333
10768
|
onRemoveQueueItem: (id) => editQueueActions.cancel(id),
|
|
10334
10769
|
chatProgress: showChatProgress ? agentProgress.view : null,
|