@adminide-stack/yantra-mobile 12.0.44-alpha.17 → 12.0.44-alpha.20

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.
Files changed (62) hide show
  1. package/lib/components/KeyboardComposerDock.js +10 -1
  2. package/lib/components/KeyboardComposerDock.js.map +1 -1
  3. package/lib/components/NavigationHeader/NavigationHeader.js +15 -16
  4. package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -1
  5. package/lib/features/apps/AppsCatalog.js +2 -1
  6. package/lib/features/apps/AppsCatalog.js.map +1 -1
  7. package/lib/features/apps/resolveSurfaceUrl.js +22 -2
  8. package/lib/features/apps/resolveSurfaceUrl.js.map +1 -1
  9. package/lib/features/attachments/ComposerAttachmentBar.js +64 -0
  10. package/lib/features/attachments/ComposerAttachmentBar.js.map +1 -0
  11. package/lib/features/attachments/MessageAttachmentPreviews.js +77 -0
  12. package/lib/features/attachments/MessageAttachmentPreviews.js.map +1 -0
  13. package/lib/features/attachments/attachmentPreviewUri.js +9 -0
  14. package/lib/features/attachments/attachmentPreviewUri.js.map +1 -0
  15. package/lib/features/attachments/buildGatewayMedia.js +118 -0
  16. package/lib/features/attachments/buildGatewayMedia.js.map +1 -0
  17. package/lib/features/attachments/composerAttachmentHandoff.js +15 -0
  18. package/lib/features/attachments/composerAttachmentHandoff.js.map +1 -0
  19. package/lib/features/attachments/displayUserMessageText.js +19 -0
  20. package/lib/features/attachments/displayUserMessageText.js.map +1 -0
  21. package/lib/features/attachments/historyAttachmentLabel.js +51 -0
  22. package/lib/features/attachments/historyAttachmentLabel.js.map +1 -0
  23. package/lib/features/attachments/isImageAttachment.js +7 -0
  24. package/lib/features/attachments/isImageAttachment.js.map +1 -0
  25. package/lib/features/attachments/preserveAttachmentPreviews.js +41 -0
  26. package/lib/features/attachments/preserveAttachmentPreviews.js.map +1 -0
  27. package/lib/features/attachments/uploadChatAttachments.js +102 -0
  28. package/lib/features/attachments/uploadChatAttachments.js.map +1 -0
  29. package/lib/features/attachments/useImageAttachments.js +102 -7
  30. package/lib/features/attachments/useImageAttachments.js.map +1 -1
  31. package/lib/features/canvas/nativeViewerRegistry.js +8 -1
  32. package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
  33. package/lib/features/canvas/surfaceIndex.js +25 -0
  34. package/lib/features/canvas/surfaceIndex.js.map +1 -0
  35. package/lib/features/canvas/useCanvasSession.js +57 -0
  36. package/lib/features/canvas/useCanvasSession.js.map +1 -0
  37. package/lib/features/chat/ChatTranscript.js +202 -0
  38. package/lib/features/chat/ChatTranscript.js.map +1 -0
  39. package/lib/hooks/useCdecliChannel.js +5 -3
  40. package/lib/hooks/useCdecliChannel.js.map +1 -1
  41. package/lib/hooks/useChatApi.js +32 -15
  42. package/lib/hooks/useChatApi.js.map +1 -1
  43. package/lib/hooks/useChatStream.js +35 -8
  44. package/lib/hooks/useChatStream.js.map +1 -1
  45. package/lib/index.js +1 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/screens/CanvasBoard/index.js +20 -15
  48. package/lib/screens/CanvasBoard/index.js.map +1 -1
  49. package/lib/screens/Chat/index.js +39 -66
  50. package/lib/screens/Chat/index.js.map +1 -1
  51. package/lib/screens/ChatHistory/index.js +2 -8
  52. package/lib/screens/ChatHistory/index.js.map +1 -1
  53. package/lib/screens/Home/HomeScreen.js +57 -21
  54. package/lib/screens/Home/HomeScreen.js.map +1 -1
  55. package/lib/screens/Home/components/ChatHistoryLanding.js +15 -9
  56. package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
  57. package/lib/screens/WebBuilder/index.js.map +1 -1
  58. package/lib/utils/navigateToNewChatHome.js +40 -0
  59. package/lib/utils/navigateToNewChatHome.js.map +1 -0
  60. package/package.json +3 -3
  61. package/lib/features/canvas/canvasCore.js +0 -41
  62. package/lib/features/canvas/canvasCore.js.map +0 -1
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { Feature } from '@common-stack/client-react';\nimport YantraMobileModule from './module';\n\nexport default new Feature(YantraMobileModule);\nexport * from './screens';\nexport { GatewayContextProvider, useGatewayContext } from './contexts/GatewayContext';\nexport { CdecliConnectionProvider, useCdecliConnection } from './contexts/CdecliConnectionContext';\nexport * from './config/constants';\nexport { config } from './config/env-config';\nexport { useCdecliAutoConnect } from './hooks/useCdecliAutoConnect';\nexport { useObtainSystemToken } from './hooks/useObtainSystemToken';\nexport {\n mintSurfaceSystemToken,\n appendSurfaceAuthParams,\n buildCdecliTokenInjection,\n buildSurfaceGateRecoveryScript,\n resolveSurfaceCatalogBackend,\n resolveSurfaceAuthGraphqlUrl,\n} from './hooks/mintSurfaceSystemToken';\nexport { useGatewayConnection, isInstanceNotFoundError } from './hooks/useGatewayConnection';\nexport { usePrerequisiteIds } from './hooks/usePrerequisiteIds';\nexport { useWorkspaceProvisioner } from './hooks/useWorkspaceProvisioner';\nexport { useGatewayRegistry } from './hooks/useGatewayRegistry';\nexport * from './services';\nexport * from './bridge';\nexport {\n YantraBrandLoader,\n YANTRA_LOADER_SIZE_DEFAULT,\n YANTRA_LOADER_SIZE_COMPACT,\n} from './components/YantraBrandLoader';\nexport { default as CustomDrawer } from './components/CustomDrawer';\n// The canvas viewer seam. Exported from the index on purpose: the app (the MF\n// host) registers the federated viewer here and the CanvasBoard screen reads\n// it. Reachability from this entry is what makes rollup emit the registry as a\n// real shared module - as an internal-only file, `registerNativeCanvasViewer`\n// is never called inside the package, so rollup tree-shakes it and constant-\n// folds the screen down to its fallback branch.\nexport { registerNativeCanvasViewer, getNativeCanvasViewer } from './features/canvas/nativeViewerRegistry';\n"],"names":[],"mappings":"uwFAEA,YAAe,IAAI,QAAQ,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { Feature } from '@common-stack/client-react';\nimport YantraMobileModule from './module';\n\nexport default new Feature(YantraMobileModule);\nexport * from './screens';\nexport { GatewayContextProvider, useGatewayContext } from './contexts/GatewayContext';\nexport { CdecliConnectionProvider, useCdecliConnection } from './contexts/CdecliConnectionContext';\nexport * from './config/constants';\nexport { config } from './config/env-config';\nexport { useCdecliAutoConnect } from './hooks/useCdecliAutoConnect';\nexport { useObtainSystemToken } from './hooks/useObtainSystemToken';\nexport {\n mintSurfaceSystemToken,\n appendSurfaceAuthParams,\n buildCdecliTokenInjection,\n buildSurfaceGateRecoveryScript,\n resolveSurfaceCatalogBackend,\n resolveSurfaceAuthGraphqlUrl,\n} from './hooks/mintSurfaceSystemToken';\nexport { useGatewayConnection, isInstanceNotFoundError } from './hooks/useGatewayConnection';\nexport { usePrerequisiteIds } from './hooks/usePrerequisiteIds';\nexport { useWorkspaceProvisioner } from './hooks/useWorkspaceProvisioner';\nexport { useGatewayRegistry } from './hooks/useGatewayRegistry';\nexport * from './services';\nexport * from './bridge';\nexport {\n YantraBrandLoader,\n YANTRA_LOADER_SIZE_DEFAULT,\n YANTRA_LOADER_SIZE_COMPACT,\n} from './components/YantraBrandLoader';\nexport { default as CustomDrawer } from './components/CustomDrawer';\n// The canvas viewer seam. Exported from the index on purpose: the app (the MF\n// host) registers the federated viewer here and the CanvasBoard screen reads\n// it. Reachability from this entry is what makes rollup emit the registry as a\n// real shared module - as an internal-only file, `registerNativeCanvasViewer`\n// is never called inside the package, so rollup tree-shakes it and constant-\n// folds the screen down to its fallback branch.\nexport {\n registerNativeCanvasViewer,\n getNativeCanvasViewer,\n registerNativeCanvasExperience,\n getNativeCanvasExperience,\n} from './features/canvas/nativeViewerRegistry';\n"],"names":[],"mappings":"g0FAEA,YAAe,IAAI,QAAQ,kBAAkB,CAAA"}
@@ -1,25 +1,30 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import {useMemo}from'react';import {useColorScheme,StyleSheet,View,Text}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {useRoute}from'@react-navigation/native';import {getNativeCanvasViewer}from'../../features/canvas/nativeViewerRegistry.js';import {parseBoardState}from'../../features/canvas/canvasCore.js';const EMPTY_BOARD = {
2
- version: 1,
3
- savedAt: 0,
4
- items: [],
5
- zoom: 1
6
- };
7
- function CanvasBoardScreen() {
1
+ import {jsx,jsxs}from'react/jsx-runtime';import {useColorScheme,StyleSheet,View,Text}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {useRoute}from'@react-navigation/native';import {getNativeCanvasExperience}from'../../features/canvas/nativeViewerRegistry.js';import {useCanvasSession}from'../../features/canvas/useCanvasSession.js';function CanvasBoardScreen() {
8
2
  const route = useRoute();
9
3
  const isDark = useColorScheme() === "dark";
10
- const Viewer = getNativeCanvasViewer();
11
- const board = useMemo(() => {
12
- var _a, _b;
13
- const raw = (_a = route.params) == null ? void 0 : _a.board;
14
- return (_b = raw ? parseBoardState(raw) : null) != null ? _b : EMPTY_BOARD;
15
- }, [route.params]);
16
- if (!Viewer) {
4
+ const Experience = getNativeCanvasExperience();
5
+ const {
6
+ token,
7
+ indexUrl,
8
+ error,
9
+ ready
10
+ } = useCanvasSession();
11
+ const params = route.params;
12
+ const channelId = typeof (params == null ? void 0 : params.channelId) === "string" ? params.channelId : void 0;
13
+ if (!Experience) {
17
14
  return /* @__PURE__ */ jsx(SafeAreaView, { style: [styles.fill, isDark && styles.fillDark], children: /* @__PURE__ */ jsxs(View, { style: styles.center, children: [
18
15
  /* @__PURE__ */ jsx(Text, { style: [styles.title, isDark && styles.textLight], children: "Native canvas unavailable" }),
19
16
  /* @__PURE__ */ jsx(Text, { style: [styles.detail, isDark && styles.textMuted], children: "This build does not carry the federation host runtime." })
20
17
  ] }) });
21
18
  }
22
- return /* @__PURE__ */ jsx(SafeAreaView, { style: [styles.fill, isDark && styles.fillDark], edges: ["left", "right", "bottom"], children: /* @__PURE__ */ jsx(Viewer, { board }) });
19
+ return /* @__PURE__ */ jsx(SafeAreaView, { style: [styles.fill, isDark && styles.fillDark], edges: ["left", "right", "bottom"], children: /* @__PURE__ */ jsx(
20
+ Experience,
21
+ {
22
+ token,
23
+ indexUrl,
24
+ channelId,
25
+ sessionError: ready ? error : null
26
+ }
27
+ ) });
23
28
  }
24
29
  const styles = StyleSheet.create({
25
30
  fill: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/screens/CanvasBoard/index.tsx"],"sourcesContent":["/**\n * Native canvas board screen - the first UI reachable through Module\n * Federation on mobile.\n *\n * Opening this screen is what triggers the federated fetch: the injected\n * viewer component lazy-imports `canvas_native/Viewer`, which the MF runtime\n * resolves against the manifest on the canvas-surface origin and downloads at\n * that moment - the viewer's code is NOT in the app binary. An empty board is\n * the deliberate first scope: it renders the remote's own \"This board is\n * empty.\" UI, which is exactly the observable proof that the remote loaded.\n * Board fetch (surface-index read) is the next slice and slots in as a route\n * param without touching the delivery path.\n */\nimport React, { useMemo } from 'react';\nimport { StyleSheet, Text, View, useColorScheme } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { useRoute } from '@react-navigation/native';\nimport { getNativeCanvasViewer } from '../../features/canvas/nativeViewerRegistry';\nimport { parseBoardState, type PersistedCanvasState } from '../../features/canvas/canvasCore';\n\nconst EMPTY_BOARD: PersistedCanvasState = { version: 1, savedAt: 0, items: [], zoom: 1 };\n\nexport interface CanvasBoardRouteParams {\n /** Serialized PersistedCanvasState (v1) to render. Absent -> empty board. */\n board?: unknown;\n}\n\nexport default function CanvasBoardScreen() {\n const route = useRoute();\n const isDark = useColorScheme() === 'dark';\n const Viewer = getNativeCanvasViewer();\n\n const board = useMemo(() => {\n const raw = (route.params as CanvasBoardRouteParams | undefined)?.board;\n return (raw ? parseBoardState(raw) : null) ?? EMPTY_BOARD;\n }, [route.params]);\n\n if (!Viewer) {\n // A build without the federation host (or before App registered the\n // loader). Say so instead of rendering a blank screen.\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]}>\n <View style={styles.center}>\n <Text style={[styles.title, isDark && styles.textLight]}>Native canvas unavailable</Text>\n <Text style={[styles.detail, isDark && styles.textMuted]}>\n This build does not carry the federation host runtime.\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]} edges={['left', 'right', 'bottom']}>\n <Viewer board={board} />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1, backgroundColor: '#f8fafc' },\n fillDark: { backgroundColor: '#0f172a' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24 },\n title: { fontSize: 15, fontWeight: '600', color: '#0f172a', marginBottom: 6 },\n detail: { fontSize: 13, color: '#64748b', textAlign: 'center' },\n textLight: { color: '#f8fafc' },\n textMuted: { color: '#94a3b8' },\n});\n"],"names":[],"mappings":"kYAmBA,MAAM,WAAoC,GAAA;AAAA,EACxC,OAAS,EAAA,CAAA;AAAA,EACT,OAAS,EAAA,CAAA;AAAA,EACT,OAAO,EAAC;AAAA,EACR,IAAM,EAAA;AACR,CAAA;AAKA,SAAwB,iBAAoB,GAAA;AAC1C,EAAA,MAAM,QAAQ,QAAS,EAAA;AACvB,EAAM,MAAA,MAAA,GAAS,gBAAqB,KAAA,MAAA;AACpC,EAAA,MAAM,SAAS,qBAAsB,EAAA;AACrC,EAAM,MAAA,KAAA,GAAQ,QAAQ,MAAM;AAjC9B,IAAA,IAAA,EAAA,EAAA,EAAA;AAkCI,IAAM,MAAA,GAAA,GAAA,CAAO,EAAM,GAAA,KAAA,CAAA,MAAA,KAAN,IAAqD,GAAA,MAAA,GAAA,EAAA,CAAA,KAAA;AAClE,IAAA,OAAA,CAAQ,EAAM,GAAA,GAAA,GAAA,eAAA,CAAgB,GAAG,CAAA,GAAI,SAA7B,IAAsC,GAAA,EAAA,GAAA,WAAA;AAAA,GAC7C,EAAA,CAAC,KAAM,CAAA,MAAM,CAAC,CAAA;AACjB,EAAA,IAAI,CAAC,MAAQ,EAAA;AAGX,IAAA,uBAAQ,GAAA,CAAA,YAAA,EAAA,EAAa,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA,MAAA,IAAU,MAAO,CAAA,QAAQ,CACvD,EAAA,QAAA,kBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,OAAO,MAChB,EAAA,QAAA,EAAA;AAAA,sBAAC,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,CAAC,MAAA,CAAO,OAAO,MAAU,IAAA,MAAA,CAAO,SAAS,CAAA,EAAG,QAAyB,EAAA,2BAAA,EAAA,CAAA;AAAA,sBAClF,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,QAAQ,MAAU,IAAA,MAAA,CAAO,SAAS,CAAA,EAAG,QAE1D,EAAA,wDAAA,EAAA;AAAA,KAAA,EACJ,CACJ,EAAA,CAAA;AAAA;AAEV,EAAA,2BAAQ,YAAa,EAAA,EAAA,KAAA,EAAO,CAAC,MAAO,CAAA,IAAA,EAAM,UAAU,MAAO,CAAA,QAAQ,GAAG,KAAO,EAAA,CAAC,QAAQ,OAAS,EAAA,QAAQ,GAC7F,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA,EAAO,OAAc,CAC1B,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,IAAM,EAAA;AAAA,IACJ,IAAM,EAAA,CAAA;AAAA,IACN,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,QAAU,EAAA;AAAA,IACR,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,CAAA;AAAA,IACN,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,QAAA;AAAA,IAChB,OAAS,EAAA;AAAA,GACX;AAAA,EACA,KAAO,EAAA;AAAA,IACL,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,KAAO,EAAA,SAAA;AAAA,IACP,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA,EAAA;AAAA,IACV,KAAO,EAAA,SAAA;AAAA,IACP,SAAW,EAAA;AAAA,GACb;AAAA,EACA,SAAW,EAAA;AAAA,IACT,KAAO,EAAA;AAAA,GACT;AAAA,EACA,SAAW,EAAA;AAAA,IACT,KAAO,EAAA;AAAA;AAEX,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/screens/CanvasBoard/index.tsx"],"sourcesContent":["/**\n * Native canvas board screen.\n *\n * The screen is deliberately thin. Opening it triggers the federated fetch of\n * the canvas remote, and the remote owns everything after that: reading the\n * user's boards from the SurfaceChannel index, choosing one, and rendering it.\n * That split is what lets a canvas change ship with `cdecli surfaces deploy\n * canvas` instead of an App Store release.\n *\n * The host contributes the two things the remote cannot know: a token the index\n * accepts, and the index endpoint for this environment.\n */\nimport React from 'react';\nimport { StyleSheet, Text, View, useColorScheme } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { useRoute } from '@react-navigation/native';\nimport { getNativeCanvasExperience } from '../../features/canvas/nativeViewerRegistry';\nimport { useCanvasSession } from '../../features/canvas/useCanvasSession';\n\nexport interface CanvasBoardRouteParams {\n /** Open a specific board from the index; otherwise the newest one opens. */\n channelId?: string;\n}\n\nexport default function CanvasBoardScreen() {\n const route = useRoute();\n const isDark = useColorScheme() === 'dark';\n const Experience = getNativeCanvasExperience();\n const { token, indexUrl, error, ready } = useCanvasSession();\n\n const params = route.params as CanvasBoardRouteParams | undefined;\n const channelId = typeof params?.channelId === 'string' ? params.channelId : undefined;\n\n if (!Experience) {\n // A build without the federation host (or before App registered it).\n // Say so instead of rendering a blank screen.\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]}>\n <View style={styles.center}>\n <Text style={[styles.title, isDark && styles.textLight]}>Native canvas unavailable</Text>\n <Text style={[styles.detail, isDark && styles.textMuted]}>\n This build does not carry the federation host runtime.\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]} edges={['left', 'right', 'bottom']}>\n <Experience\n token={token}\n indexUrl={indexUrl}\n channelId={channelId}\n // Until the mint settles, `sessionError` stays null so the remote\n // shows its loading state rather than flashing a failure.\n sessionError={ready ? error : null}\n />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1, backgroundColor: '#f8fafc' },\n fillDark: { backgroundColor: '#0f172a' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24 },\n title: { fontSize: 15, fontWeight: '600', color: '#0f172a', marginBottom: 6 },\n detail: { fontSize: 13, color: '#64748b', textAlign: 'center' },\n textLight: { color: '#f8fafc' },\n textMuted: { color: '#94a3b8' },\n});\n"],"names":[],"mappings":"iXAsBA,SAAwB,iBAAoB,GAAA;AAC1C,EAAA,MAAM,QAAQ,QAAS,EAAA;AACvB,EAAM,MAAA,MAAA,GAAS,gBAAqB,KAAA,MAAA;AACpC,EAAA,MAAM,aAAa,yBAA0B,EAAA;AAC7C,EAAM,MAAA;AAAA,IACJ,KAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,MACE,gBAAiB,EAAA;AACrB,EAAA,MAAM,SAAS,KAAM,CAAA,MAAA;AACrB,EAAA,MAAM,YAAY,QAAO,MAAA,IAAA,IAAA,GAAA,MAAA,GAAA,MAAA,CAAQ,SAAc,CAAA,KAAA,QAAA,GAAW,OAAO,SAAY,GAAA,MAAA;AAC7E,EAAA,IAAI,CAAC,UAAY,EAAA;AAGf,IAAA,uBAAQ,GAAA,CAAA,YAAA,EAAA,EAAa,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA,MAAA,IAAU,MAAO,CAAA,QAAQ,CACvD,EAAA,QAAA,kBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,OAAO,MAChB,EAAA,QAAA,EAAA;AAAA,sBAAC,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,CAAC,MAAA,CAAO,OAAO,MAAU,IAAA,MAAA,CAAO,SAAS,CAAA,EAAG,QAAyB,EAAA,2BAAA,EAAA,CAAA;AAAA,sBAClF,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,QAAQ,MAAU,IAAA,MAAA,CAAO,SAAS,CAAA,EAAG,QAE1D,EAAA,wDAAA,EAAA;AAAA,KAAA,EACJ,CACJ,EAAA,CAAA;AAAA;AAEV,EAAA,uBAAQ,GAAA,CAAA,YAAA,EAAA,EAAa,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA,MAAA,IAAU,MAAO,CAAA,QAAQ,GAAG,KAAO,EAAA,CAAC,MAAQ,EAAA,OAAA,EAAS,QAAQ,CAC7F,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MAAW,KAAA;AAAA,MAAc,QAAA;AAAA,MAAoB,SAAA;AAAA,MAGtD,YAAA,EAAc,QAAQ,KAAQ,GAAA;AAAA;AAAA,GAC1B,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,IAAM,EAAA;AAAA,IACJ,IAAM,EAAA,CAAA;AAAA,IACN,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,QAAU,EAAA;AAAA,IACR,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,CAAA;AAAA,IACN,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,QAAA;AAAA,IAChB,OAAS,EAAA;AAAA,GACX;AAAA,EACA,KAAO,EAAA;AAAA,IACL,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,KAAO,EAAA,SAAA;AAAA,IACP,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA,EAAA;AAAA,IACV,KAAO,EAAA,SAAA;AAAA,IACP,SAAW,EAAA;AAAA,GACb;AAAA,EACA,SAAW,EAAA;AAAA,IACT,KAAO,EAAA;AAAA,GACT;AAAA,EACA,SAAW,EAAA;AAAA,IACT,KAAO,EAAA;AAAA;AAEX,CAAC,CAAA"}
@@ -1,4 +1,4 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import {useMemo,useEffect,useCallback,useState,useRef}from'react';import {useColorScheme,useWindowDimensions,Keyboard,TouchableWithoutFeedback,StyleSheet,View}from'react-native';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {MessagesContainerUI}from'@messenger-box/platform-mobile';import {MessageActionBar}from'../../features/chat/MessageActionBar.js';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {useKeyboardBottomOffset}from'../../hooks/useKeyboardBottomOffset.js';import {KeyboardComposerDock}from'../../components/KeyboardComposerDock.js';import {YantraBrandLoader,YANTRA_LOADER_SIZE_COMPACT}from'../../components/YantraBrandLoader.js';import ThinkingIndicator from'../../components/ThinkingIndicator.js';import {mobileTokens}from'../../theme/mobileTokens.js';import DeepSearchModal from'../Home/components/DeepSearchModal.js';import {normalizeSummaryText,extractDeepSearchSources}from'../Home/deepSearchUtils.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {useImageAttachments}from'../../features/attachments/useImageAttachments.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {requestMicPermission}from'../../features/audio-input/useAudioPermission.js';var __defProp = Object.defineProperty;
1
+ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useMemo,useEffect,useCallback,useState,useRef}from'react';import {useColorScheme,useWindowDimensions,Keyboard,StyleSheet,View}from'react-native';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {MessageActionBar}from'../../features/chat/MessageActionBar.js';import {ChatTranscript}from'../../features/chat/ChatTranscript.js';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {useKeyboardBottomOffset}from'../../hooks/useKeyboardBottomOffset.js';import {KeyboardComposerDock}from'../../components/KeyboardComposerDock.js';import {YantraBrandLoader,YANTRA_LOADER_SIZE_COMPACT}from'../../components/YantraBrandLoader.js';import ThinkingIndicator from'../../components/ThinkingIndicator.js';import {mobileTokens}from'../../theme/mobileTokens.js';import DeepSearchModal from'../Home/components/DeepSearchModal.js';import {normalizeSummaryText,extractDeepSearchSources}from'../Home/deepSearchUtils.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {useImageAttachments}from'../../features/attachments/useImageAttachments.js';import {ComposerAttachmentBar}from'../../features/attachments/ComposerAttachmentBar.js';import {hasComposerAttachments,takeComposerAttachments}from'../../features/attachments/composerAttachmentHandoff.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {requestMicPermission}from'../../features/audio-input/useAudioPermission.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -17,10 +17,6 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- const CHAT_CURRENT_USER = {
21
- id: "user"
22
- };
23
- const renderNoToolbar = () => null;
24
20
  function ChatScreen() {
25
21
  var _a, _b;
26
22
  const navigation = useNavigation();
@@ -45,7 +41,6 @@ function ChatScreen() {
45
41
  const secondaryTextColor = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
46
42
  const insets = useSafeAreaInsets();
47
43
  const {
48
- keyboardHeight,
49
44
  keyboardVisible
50
45
  } = useKeyboardBottomOffset();
51
46
  const cdecli = useCdecliConnection();
@@ -67,6 +62,7 @@ function ChatScreen() {
67
62
  id: `msg-${index}-${msg.role}`,
68
63
  role: msg.role,
69
64
  content: msg.content,
65
+ attachments: msg.attachments,
70
66
  metadata: msg.metadata
71
67
  })), [chat.messages]);
72
68
  const {
@@ -80,22 +76,19 @@ function ChatScreen() {
80
76
  cancel
81
77
  } = chat;
82
78
  const regenerateFrom = useCallback((messageId) => {
83
- var _a2;
79
+ var _a2, _b2;
84
80
  const match = /^msg-(\d+)-assistant$/.exec(messageId);
85
81
  if (!match || !channelId) return;
86
82
  for (let i = Number(match[1]) - 1; i >= 0; i -= 1) {
87
83
  const prior = chat.messages[i];
88
- if ((prior == null ? void 0 : prior.role) === "user" && ((_a2 = prior.content) == null ? void 0 : _a2.trim())) {
89
- void chat.sendMessage(prior.content, void 0, channelId);
84
+ if ((prior == null ? void 0 : prior.role) === "user" && (((_a2 = prior.content) == null ? void 0 : _a2.trim()) || ((_b2 = prior.attachments) == null ? void 0 : _b2.length))) {
85
+ void chat.sendMessage(prior.content, prior.attachments, channelId);
90
86
  return;
91
87
  }
92
88
  }
93
89
  }, [chat, channelId]);
94
90
  const chatBusy = isLoading || isStreaming;
95
91
  const renderMessageActions = useCallback((message) => message.role === "assistant" ? /* @__PURE__ */ jsx(MessageActionBar, { text: message.content, onRegenerate: chatBusy ? void 0 : () => regenerateFrom(message.id) }) : null, [chatBusy, regenerateFrom]);
96
- const messageActionsSlot = {
97
- renderMessageActions
98
- };
99
92
  const imageAttachments = useImageAttachments();
100
93
  const [value, setValue] = useState("");
101
94
  const valueRef = useRef(value);
@@ -103,7 +96,8 @@ function ChatScreen() {
103
96
  const inputRef = useRef(null);
104
97
  const trimmed = value.trim();
105
98
  const hasQuery = trimmed.length > 0;
106
- const canSubmit = hasQuery && Boolean(channelId);
99
+ const hasAttachments = imageAttachments.pending.length > 0;
100
+ const canSubmit = (hasQuery || hasAttachments) && Boolean(channelId);
107
101
  const [activeMode, setActiveMode] = useState(() => params.initialMode === "deep-search" ? "deep-search" : params.initialMode === "build" ? "build" : "chat");
108
102
  const handleModeSwitch = useCallback((mode) => {
109
103
  setActiveMode(mode);
@@ -115,13 +109,15 @@ function ChatScreen() {
115
109
  const autoFiredRef = useRef(false);
116
110
  useEffect(() => {
117
111
  if (autoFiredRef.current) return;
118
- if (!channelId || !initialQuery) return;
112
+ if (!channelId) return;
119
113
  if (cdecli.status !== "connected" && cdecli.status !== "error") return;
114
+ const stashed = hasComposerAttachments(channelId) ? takeComposerAttachments(channelId) : void 0;
115
+ if (!initialQuery && !(stashed == null ? void 0 : stashed.length)) return;
120
116
  autoFiredRef.current = true;
121
117
  if (isDeepSearchMode) {
122
118
  setIsDeepSearchModalOpen(true);
123
119
  }
124
- void sendMessage(initialQuery, initialAttachments, channelId);
120
+ void sendMessage(initialQuery != null ? initialQuery : "", stashed, channelId);
125
121
  try {
126
122
  navigation.setParams({
127
123
  initialQuery: null,
@@ -132,8 +128,9 @@ function ChatScreen() {
132
128
  }, [channelId, initialQuery, initialAttachments, sendMessage, navigation, cdecli.status, isDeepSearchMode]);
133
129
  const handleSend = useCallback((text) => {
134
130
  var _a2;
131
+ const pending = imageAttachments.forSend();
135
132
  const t = (text != null ? text : valueRef.current).trim();
136
- if (!t || !channelId) return;
133
+ if (!t && !(pending == null ? void 0 : pending.length) || !channelId) return;
137
134
  setValue("");
138
135
  (_a2 = inputRef.current) == null ? void 0 : _a2.clear();
139
136
  if (isBuildMode) {
@@ -151,7 +148,7 @@ function ChatScreen() {
151
148
  if (isDeepSearchMode) {
152
149
  setIsDeepSearchModalOpen(true);
153
150
  }
154
- void sendMessage(t, imageAttachments.forSend(), channelId);
151
+ void sendMessage(t, pending, channelId);
155
152
  imageAttachments.clear();
156
153
  }, [channelId, sendMessage, isDeepSearchMode, isBuildMode, navigation, params.orgName, imageAttachments]);
157
154
  const handleValueChange = useCallback((e) => {
@@ -202,7 +199,6 @@ function ChatScreen() {
202
199
  if ((response != null ? response : "").trim()) return false;
203
200
  return ((_a2 = messages[messages.length - 1]) == null ? void 0 : _a2.role) === "user";
204
201
  }, [isLoading, isStreaming, messages, response]);
205
- const composerScrollBottomPadding = 24 + (keyboardVisible ? keyboardHeight : 0);
206
202
  const [isDeepSearchModalOpen, setIsDeepSearchModalOpen] = useState(false);
207
203
  const [researchProcessOpen, setResearchProcessOpen] = useState(true);
208
204
  const [sourcesAccordionOpen, setSourcesAccordionOpen] = useState(true);
@@ -269,20 +265,24 @@ function ChatScreen() {
269
265
  // dependency with its permission strings declared in app.json.
270
266
  camera: {
271
267
  enabled: true,
272
- loading: imageAttachments.busy,
268
+ loading: imageAttachments.busyKind === "camera",
273
269
  onClick: () => {
274
270
  void imageAttachments.captureFromCamera();
275
271
  }
276
272
  },
277
273
  image: {
278
274
  enabled: true,
279
- loading: imageAttachments.busy,
275
+ loading: imageAttachments.busyKind === "library",
280
276
  onClick: () => {
281
277
  void imageAttachments.pickFromLibrary();
282
278
  }
283
279
  },
284
280
  attach: {
285
- enabled: false
281
+ enabled: true,
282
+ loading: imageAttachments.busyKind === "documents",
283
+ onClick: () => {
284
+ void imageAttachments.pickDocuments();
285
+ }
286
286
  }
287
287
  }), [imageAttachments]);
288
288
  const inputPlaceholder = isDeepSearchMode ? "Research anything..." : isBuildMode ? "Describe an app to build..." : "Ask anything...";
@@ -297,7 +297,7 @@ function ChatScreen() {
297
297
  onSubmitEditing: () => handleSend()
298
298
  }), [value, handleValueChange, inputPlaceholder, channelId, handleSend]);
299
299
  const micSendButton = useMemo(() => ({
300
- hasContent: hasQuery,
300
+ hasContent: hasQuery || hasAttachments,
301
301
  onSend: () => handleSend(),
302
302
  onMic: handleMicPress,
303
303
  disabled: !channelId,
@@ -305,16 +305,16 @@ function ChatScreen() {
305
305
  isLoading: canSubmit ? false : isLoading,
306
306
  onStop: isStreaming && !canSubmit ? cancel : void 0,
307
307
  steerable: isLoading || isStreaming
308
- }), [canSubmit, handleSend, handleMicPress, isLoading, channelId, isStreaming, cancel, hasQuery]);
308
+ }), [canSubmit, handleSend, handleMicPress, isLoading, channelId, isStreaming, cancel, hasQuery, hasAttachments]);
309
309
  const isHydrating = messagesLoading && messages.length === 0 && !response;
310
- const isWaitingForGateway = !autoFiredRef.current && !!channelId && !!initialQuery && cdecli.status !== "connected" && cdecli.status !== "error";
310
+ const isWaitingForGateway = !autoFiredRef.current && !!channelId && (!!initialQuery || hasComposerAttachments(channelId)) && cdecli.status !== "connected" && cdecli.status !== "error";
311
311
  const showSendingLoader = waitingForAssistant;
312
312
  const pinSendingLoaderNearComposer = messages.length > 0 || Boolean((response != null ? response : "").trim());
313
313
  return /* @__PURE__ */ jsxs(SafeAreaView, { edges: ["left", "right"], style: {
314
314
  flex: 1,
315
315
  backgroundColor: surfaceColor
316
316
  }, children: [
317
- /* @__PURE__ */ jsx(TouchableWithoutFeedback, { onPress: Keyboard.dismiss, accessible: false, children: /* @__PURE__ */ jsxs(Box, { flex: 1, width: "100%", position: "relative", children: [
317
+ /* @__PURE__ */ jsxs(Box, { flex: 1, width: "100%", position: "relative", children: [
318
318
  (chatError || cdecli.error) && /* @__PURE__ */ jsx(Box, { mb: "$2", mx: "$4", p: "$3", borderRadius: "$md", style: {
319
319
  backgroundColor: isDark ? "#2b1a1d" : "#fef2f2",
320
320
  borderWidth: 1,
@@ -342,55 +342,25 @@ function ChatScreen() {
342
342
  /* @__PURE__ */ jsx(Text, { style: [styles.statusText, {
343
343
  color: secondaryTextColor
344
344
  }], children: "Connecting gateway\u2026" })
345
- ] }) : /* @__PURE__ */ jsx(Box, { flex: 1, width: "100%", alignSelf: "stretch", children: /* @__PURE__ */ jsx(
346
- MessagesContainerUI,
347
- __spreadProps(__spreadValues({
348
- mode: "chat",
349
- showBackButton: false,
350
- compactTop: true,
351
- isKeyboardInternallyHandled: false
352
- }, messageActionsSlot), {
353
- messagesContainerStyle: {
354
- paddingHorizontal: 0,
355
- paddingTop: 0,
356
- paddingBottom: composerScrollBottomPadding,
357
- margin: 0,
358
- marginTop: 0,
359
- alignSelf: "center",
360
- width: contentMaxWidth
361
- },
362
- listContentStyle: {
363
- paddingTop: 0,
364
- paddingBottom: composerScrollBottomPadding,
365
- margin: 0,
366
- marginTop: 0,
367
- width: contentMaxWidth,
368
- alignSelf: "center",
369
- justifyContent: "flex-end"
370
- },
371
- messages: transcriptRows,
372
- streamingContent: response,
373
- currentUser: CHAT_CURRENT_USER,
374
- onSend: handleSend,
375
- disabled: !channelId,
376
- isLoading,
377
- onStop: isStreaming ? cancel : void 0,
378
- renderPlanInputToolbar: renderNoToolbar,
379
- renderBuildInputToolbar: renderNoToolbar
380
- })
381
- ) }),
345
+ ] }) : /* @__PURE__ */ jsx(Box, { flex: 1, width: "100%", alignSelf: "stretch", children: /* @__PURE__ */ jsx(ChatTranscript, { messages: transcriptRows, streamingContent: response, renderMessageActions, isDark, keyboardVisible, listContentStyle: {
346
+ paddingTop: 12,
347
+ paddingBottom: 8,
348
+ margin: 0,
349
+ width: contentMaxWidth,
350
+ alignSelf: "center"
351
+ } }) }),
382
352
  showSendingLoader && !pinSendingLoaderNearComposer ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: styles.sendingLoaderEmptyState, children: /* @__PURE__ */ jsx(ThinkingIndicator, { color: secondaryTextColor }) }) : null,
383
353
  /* @__PURE__ */ jsxs(KeyboardComposerDock, { closedInset: insets.bottom, keyboardVisible, children: [
384
354
  showSendingLoader && pinSendingLoaderNearComposer ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: styles.sendingLoaderInDock, children: /* @__PURE__ */ jsx(ThinkingIndicator, { color: secondaryTextColor }) }) : null,
385
355
  /* @__PURE__ */ jsxs(View, { style: [styles.bottomComposerInner, {
386
356
  width: contentMaxWidth
387
357
  }], children: [
388
- voiceError ? /* @__PURE__ */ jsx(View, { style: [styles.voiceErrorBanner, {
358
+ voiceError || imageAttachments.error ? /* @__PURE__ */ jsx(View, { style: [styles.voiceErrorBanner, {
389
359
  backgroundColor: isDark ? "#2b1a1d" : "#fef2f2",
390
360
  borderColor: isDark ? "#7f1d1d" : "#fecaca"
391
361
  }], children: /* @__PURE__ */ jsx(Text, { style: [styles.voiceErrorText, {
392
362
  color: isDark ? "#fecaca" : "#991b1b"
393
- }], children: voiceError }) }) : null,
363
+ }], children: voiceError || imageAttachments.error }) }) : null,
394
364
  showAudioRecorder ? (
395
365
  /*
396
366
  * Render-time JS errors thrown by `useAudioRecorder`
@@ -403,10 +373,13 @@ function ChatScreen() {
403
373
  * release / TestFlight.
404
374
  */
405
375
  /* @__PURE__ */ jsx(MicErrorBoundary, { onCancel: handleRecorderCancel, onError: handleRecorderError, children: /* @__PURE__ */ jsx(AudioRecorderPanel, { isDark, onTranscriptionComplete: handleTranscriptionComplete, onCancel: handleRecorderCancel, onError: handleRecorderError }) })
406
- ) : /* @__PURE__ */ jsx(InputToolBar, { inputConfig, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton })
376
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
377
+ /* @__PURE__ */ jsx(ComposerAttachmentBar, { attachments: imageAttachments.pending, onRemove: imageAttachments.remove, isDark }),
378
+ /* @__PURE__ */ jsx(InputToolBar, { inputConfig, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton })
379
+ ] })
407
380
  ] })
408
381
  ] })
409
- ] }) }),
382
+ ] }),
410
383
  isDeepSearchMode ? /* @__PURE__ */ jsx(DeepSearchModal, { visible: isDeepSearchModalOpen, query: deepSearchQuery, summaryText: deepSearchSummary, sources: deepSearchSources, isStreaming, researchProcessOpen, sourcesAccordionOpen, onToggleResearchProcess: () => setResearchProcessOpen((prev) => !prev), onToggleSourcesAccordion: () => setSourcesAccordionOpen((prev) => !prev), onRetry: handleDeepSearchRetry, onStop: cancel, onClose: handleDeepSearchClose }) : null
411
384
  ] });
412
385
  }