@adminide-stack/yantra-mobile 12.0.69-alpha.9 → 12.0.70-alpha.0

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 (522) hide show
  1. package/lib/components/GatewayConnector/GatewayConnector.js +2 -2
  2. package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -1
  3. package/lib/components/KeyboardComposerDock.js +8 -1
  4. package/lib/components/KeyboardComposerDock.js.map +1 -1
  5. package/lib/components/NavigationHeader/NavigationHeader.js +2 -2
  6. package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -1
  7. package/lib/config/env-config.js +4 -0
  8. package/lib/config/env-config.js.map +1 -1
  9. package/lib/contexts/ChatLiveStreamContext.js +4 -1
  10. package/lib/contexts/ChatLiveStreamContext.js.map +1 -1
  11. package/lib/features/agent-chat/NativeAgentChat.js +2 -0
  12. package/lib/features/agent-chat/NativeAgentChat.js.map +1 -1
  13. package/lib/features/apps/AppsCatalog.js +2 -2
  14. package/lib/features/apps/AppsCatalog.js.map +1 -1
  15. package/lib/features/audio-input/MicErrorBoundary.js +2 -2
  16. package/lib/features/audio-input/MicErrorBoundary.js.map +1 -1
  17. package/lib/features/canvas/AudioEditorExperience.js +308 -0
  18. package/lib/features/canvas/AudioEditorExperience.js.map +1 -0
  19. package/lib/features/canvas/CanvasAgentChatPane.js +310 -0
  20. package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -0
  21. package/lib/features/canvas/CanvasBoardsGrid.js +414 -0
  22. package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -0
  23. package/lib/features/canvas/CanvasChatResultCard.js +113 -0
  24. package/lib/features/canvas/CanvasChatResultCard.js.map +1 -0
  25. package/lib/features/canvas/CanvasEditToolsPanel.js +179 -0
  26. package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -0
  27. package/lib/features/canvas/CanvasExperience.js +859 -0
  28. package/lib/features/canvas/CanvasExperience.js.map +1 -0
  29. package/lib/features/canvas/CanvasGeneratePanel.js +514 -0
  30. package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -0
  31. package/lib/features/canvas/CanvasLibrarySheet.js +355 -0
  32. package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -0
  33. package/lib/features/canvas/CanvasLooksPanel.js +184 -0
  34. package/lib/features/canvas/CanvasLooksPanel.js.map +1 -0
  35. package/lib/features/canvas/CanvasTasksPanel.js +138 -0
  36. package/lib/features/canvas/CanvasTasksPanel.js.map +1 -0
  37. package/lib/features/canvas/CanvasTemplatesPanel.js +226 -0
  38. package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -0
  39. package/lib/features/canvas/CanvasToolDock.js +423 -0
  40. package/lib/features/canvas/CanvasToolDock.js.map +1 -0
  41. package/lib/features/canvas/FrameExtractorExperience.js +242 -0
  42. package/lib/features/canvas/FrameExtractorExperience.js.map +1 -0
  43. package/lib/features/canvas/ImageEditorExperience.js +491 -0
  44. package/lib/features/canvas/ImageEditorExperience.js.map +1 -0
  45. package/lib/features/canvas/InfluencerStudioExperience.js +288 -0
  46. package/lib/features/canvas/InfluencerStudioExperience.js.map +1 -0
  47. package/lib/features/canvas/MoodboardExperience.js +205 -0
  48. package/lib/features/canvas/MoodboardExperience.js.map +1 -0
  49. package/lib/features/canvas/NativeCanvasViewer.js +929 -0
  50. package/lib/features/canvas/NativeCanvasViewer.js.map +1 -0
  51. package/lib/features/canvas/PromoContextFields.js +150 -0
  52. package/lib/features/canvas/PromoContextFields.js.map +1 -0
  53. package/lib/features/canvas/SetStudioExperience.js +323 -0
  54. package/lib/features/canvas/SetStudioExperience.js.map +1 -0
  55. package/lib/features/canvas/VideoClipsExperience.js +175 -0
  56. package/lib/features/canvas/VideoClipsExperience.js.map +1 -0
  57. package/lib/features/canvas/VideoEditExperience.js +824 -0
  58. package/lib/features/canvas/VideoEditExperience.js.map +1 -0
  59. package/lib/features/canvas/VideoEditorExperience.js +3050 -0
  60. package/lib/features/canvas/VideoEditorExperience.js.map +1 -0
  61. package/lib/features/canvas/VideoGeneratorExperience.js +415 -0
  62. package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -0
  63. package/lib/features/canvas/aiEdit.js +53 -0
  64. package/lib/features/canvas/aiEdit.js.map +1 -0
  65. package/lib/features/canvas/canvasAgentChat.js +76 -0
  66. package/lib/features/canvas/canvasAgentChat.js.map +1 -0
  67. package/lib/features/canvas/canvasBoardsCatalog.js +59 -0
  68. package/lib/features/canvas/canvasBoardsCatalog.js.map +1 -0
  69. package/lib/features/canvas/canvasBoardsSnapshot.js +14 -1
  70. package/lib/features/canvas/canvasBoardsSnapshot.js.map +1 -1
  71. package/lib/features/canvas/canvasChatDisplay.js +38 -0
  72. package/lib/features/canvas/canvasChatDisplay.js.map +1 -0
  73. package/lib/features/canvas/canvasChatTemplates.js +219 -0
  74. package/lib/features/canvas/canvasChatTemplates.js.map +1 -0
  75. package/lib/features/canvas/canvasCore.js +138 -1
  76. package/lib/features/canvas/canvasCore.js.map +1 -1
  77. package/lib/features/canvas/canvasEditOps.js +224 -0
  78. package/lib/features/canvas/canvasEditOps.js.map +1 -0
  79. package/lib/features/canvas/canvasTasks.js +187 -0
  80. package/lib/features/canvas/canvasTasks.js.map +1 -0
  81. package/lib/features/canvas/designPromptTemplates.js +3084 -0
  82. package/lib/features/canvas/designPromptTemplates.js.map +1 -0
  83. package/lib/features/canvas/editTools.js +54 -0
  84. package/lib/features/canvas/editTools.js.map +1 -0
  85. package/lib/features/canvas/extendVideo.js +5 -0
  86. package/lib/features/canvas/extendVideo.js.map +1 -0
  87. package/lib/features/canvas/frameExtract.js +33 -0
  88. package/lib/features/canvas/frameExtract.js.map +1 -0
  89. package/lib/features/canvas/generationModels.js +201 -0
  90. package/lib/features/canvas/generationModels.js.map +1 -0
  91. package/lib/features/canvas/influencer/influencerPipeline.js +170 -0
  92. package/lib/features/canvas/influencer/influencerPipeline.js.map +1 -0
  93. package/lib/features/canvas/influencer/productReel.js +72 -0
  94. package/lib/features/canvas/influencer/productReel.js.map +1 -0
  95. package/lib/features/canvas/influencer/reelPlan.js +159 -0
  96. package/lib/features/canvas/influencer/reelPlan.js.map +1 -0
  97. package/lib/features/canvas/moodboardCore.js +13 -0
  98. package/lib/features/canvas/moodboardCore.js.map +1 -0
  99. package/lib/features/canvas/promoProjectImport.js +99 -0
  100. package/lib/features/canvas/promoProjectImport.js.map +1 -0
  101. package/lib/features/canvas/promoVideo.js +312 -0
  102. package/lib/features/canvas/promoVideo.js.map +1 -0
  103. package/lib/features/canvas/recorder/CameraRecorderExperience.js +109 -0
  104. package/lib/features/canvas/recorder/CameraRecorderExperience.js.map +1 -0
  105. package/lib/features/canvas/sessionIdentity.js +28 -1
  106. package/lib/features/canvas/sessionIdentity.js.map +1 -1
  107. package/lib/features/canvas/set/SetViewportWebView.js +133 -0
  108. package/lib/features/canvas/set/SetViewportWebView.js.map +1 -0
  109. package/lib/features/canvas/set/cameraPath.js +194 -0
  110. package/lib/features/canvas/set/cameraPath.js.map +1 -0
  111. package/lib/features/canvas/set/setProject.js +24 -0
  112. package/lib/features/canvas/set/setProject.js.map +1 -0
  113. package/lib/features/canvas/storageLibrary.js +184 -0
  114. package/lib/features/canvas/storageLibrary.js.map +1 -0
  115. package/lib/features/canvas/studioCatalog.js +129 -0
  116. package/lib/features/canvas/studioCatalog.js.map +1 -0
  117. package/lib/features/canvas/studioLooks.js +189 -0
  118. package/lib/features/canvas/studioLooks.js.map +1 -0
  119. package/lib/features/canvas/surfaceIndex.js +63 -1
  120. package/lib/features/canvas/surfaceIndex.js.map +1 -1
  121. package/lib/features/canvas/templateImport/invideoNative.js +221 -0
  122. package/lib/features/canvas/templateImport/invideoNative.js.map +1 -0
  123. package/lib/features/canvas/templateImport/loadTemplate.js +43 -0
  124. package/lib/features/canvas/templateImport/loadTemplate.js.map +1 -0
  125. package/lib/features/canvas/templateImport/renderConfig.js +93 -0
  126. package/lib/features/canvas/templateImport/renderConfig.js.map +1 -0
  127. package/lib/features/canvas/useStudioCatalogTemplates.js +134 -0
  128. package/lib/features/canvas/useStudioCatalogTemplates.js.map +1 -0
  129. package/lib/features/canvas/video3d.js +109 -0
  130. package/lib/features/canvas/video3d.js.map +1 -0
  131. package/lib/features/canvas/videoClips.js +42 -0
  132. package/lib/features/canvas/videoClips.js.map +1 -0
  133. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +120 -0
  134. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -0
  135. package/lib/features/canvas/videoEditor/agent/agentLoop.js +69 -0
  136. package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -0
  137. package/lib/features/canvas/videoEditor/agent/brainClient.js +45 -0
  138. package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -0
  139. package/lib/features/canvas/videoEditor/agent/cutTools.js +129 -0
  140. package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -0
  141. package/lib/features/canvas/videoEditor/editorModel.js +346 -0
  142. package/lib/features/canvas/videoEditor/editorModel.js.map +1 -0
  143. package/lib/features/canvas/videoEditor/exportRenderer.js +214 -0
  144. package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -0
  145. package/lib/features/canvas/videoEditor/filters.js +41 -0
  146. package/lib/features/canvas/videoEditor/filters.js.map +1 -0
  147. package/lib/features/canvas/videoEditor/mediaActions.js +57 -0
  148. package/lib/features/canvas/videoEditor/mediaActions.js.map +1 -0
  149. package/lib/features/canvas/videoEditor/remoteMediaClient.js +129 -0
  150. package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -0
  151. package/lib/features/canvas/videoEditor/solidColorPng.js +115 -0
  152. package/lib/features/canvas/videoEditor/solidColorPng.js.map +1 -0
  153. package/lib/features/canvas/videoEditor/videoEditOps.js +191 -0
  154. package/lib/features/canvas/videoEditor/videoEditOps.js.map +1 -0
  155. package/lib/features/canvas/videoEditor/videoProjectsStore.js +82 -0
  156. package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -0
  157. package/lib/features/canvas/videoRenderer.js +8 -0
  158. package/lib/features/canvas/videoRenderer.js.map +1 -0
  159. package/lib/features/canvas/withRemoteSafeArea.js +2 -2
  160. package/lib/features/canvas/withRemoteSafeArea.js.map +1 -1
  161. package/lib/features/characters/characterStudioProps.js +14 -0
  162. package/lib/features/characters/characterStudioProps.js.map +1 -0
  163. package/lib/features/chat/ChatCodeBlock.js +7 -3
  164. package/lib/features/chat/ChatCodeBlock.js.map +1 -1
  165. package/lib/features/chat/ChatTranscript.js +7 -3
  166. package/lib/features/chat/ChatTranscript.js.map +1 -1
  167. package/lib/features/chat/ChatWidgetCard.js +13 -0
  168. package/lib/features/chat/ChatWidgetCard.js.map +1 -0
  169. package/lib/features/chat/ConnectorConnectCard.js +166 -0
  170. package/lib/features/chat/ConnectorConnectCard.js.map +1 -0
  171. package/lib/features/chat/ConnectorConnectPrompt.js +272 -0
  172. package/lib/features/chat/ConnectorConnectPrompt.js.map +1 -0
  173. package/lib/features/chat/MessageActionBar.js.map +1 -1
  174. package/lib/features/chat/QueuedFollowUps.js +71 -0
  175. package/lib/features/chat/QueuedFollowUps.js.map +1 -0
  176. package/lib/features/chat/chatWidgets.js +37 -0
  177. package/lib/features/chat/chatWidgets.js.map +1 -0
  178. package/lib/features/chat/connectorConnect.js +207 -0
  179. package/lib/features/chat/connectorConnect.js.map +1 -0
  180. package/lib/features/chat/connectorConnectHandbacks.js +55 -0
  181. package/lib/features/chat/connectorConnectHandbacks.js.map +1 -0
  182. package/lib/features/design/DesignEditorExperience.js +643 -0
  183. package/lib/features/design/DesignEditorExperience.js.map +1 -0
  184. package/lib/features/design/DesignExperience.js +444 -0
  185. package/lib/features/design/DesignExperience.js.map +1 -0
  186. package/lib/features/design/designCore.js +298 -0
  187. package/lib/features/design/designCore.js.map +1 -0
  188. package/lib/features/design/designIndex.js +150 -0
  189. package/lib/features/design/designIndex.js.map +1 -0
  190. package/lib/features/design/exportDesign.js +133 -0
  191. package/lib/features/design/exportDesign.js.map +1 -0
  192. package/lib/features/job-search/ApplicationsPanel.js +907 -0
  193. package/lib/features/job-search/ApplicationsPanel.js.map +1 -0
  194. package/lib/features/job-search/ContactsPanel.js +627 -0
  195. package/lib/features/job-search/ContactsPanel.js.map +1 -0
  196. package/lib/features/job-search/InsightsPanel.js +299 -0
  197. package/lib/features/job-search/InsightsPanel.js.map +1 -0
  198. package/lib/features/job-search/InterviewPanel.js +637 -0
  199. package/lib/features/job-search/InterviewPanel.js.map +1 -0
  200. package/lib/features/job-search/JdPastePrompt.js +130 -0
  201. package/lib/features/job-search/JdPastePrompt.js.map +1 -0
  202. package/lib/features/job-search/JobCard.js +199 -0
  203. package/lib/features/job-search/JobCard.js.map +1 -0
  204. package/lib/features/job-search/JobDetailSheet.js +255 -0
  205. package/lib/features/job-search/JobDetailSheet.js.map +1 -0
  206. package/lib/features/job-search/JobSearchAgentChatPane.js +377 -0
  207. package/lib/features/job-search/JobSearchAgentChatPane.js.map +1 -0
  208. package/lib/features/job-search/JobSearchExperience.js +1324 -0
  209. package/lib/features/job-search/JobSearchExperience.js.map +1 -0
  210. package/lib/features/job-search/JobSearchLocationField.js +231 -0
  211. package/lib/features/job-search/JobSearchLocationField.js.map +1 -0
  212. package/lib/features/job-search/ProfilePanel.js +679 -0
  213. package/lib/features/job-search/ProfilePanel.js.map +1 -0
  214. package/lib/features/job-search/RepliesPanel.js +344 -0
  215. package/lib/features/job-search/RepliesPanel.js.map +1 -0
  216. package/lib/features/job-search/SavedPanel.js +297 -0
  217. package/lib/features/job-search/SavedPanel.js.map +1 -0
  218. package/lib/features/job-search/chat/widgetContent.js +29 -0
  219. package/lib/features/job-search/chat/widgetContent.js.map +1 -0
  220. package/lib/features/job-search/cvText.js +91 -0
  221. package/lib/features/job-search/cvText.js.map +1 -0
  222. package/lib/features/job-search/jobAgentSwipe.js +7 -0
  223. package/lib/features/job-search/jobAgentSwipe.js.map +1 -0
  224. package/lib/features/job-search/jobSearchClient.js +184 -0
  225. package/lib/features/job-search/jobSearchClient.js.map +1 -0
  226. package/lib/features/job-search/jobSearchExec.js +14 -0
  227. package/lib/features/job-search/jobSearchExec.js.map +1 -0
  228. package/lib/features/job-search/jobSearchRuntime.js +50 -0
  229. package/lib/features/job-search/jobSearchRuntime.js.map +1 -0
  230. package/lib/features/job-search/jobSearchTheme.js +44 -0
  231. package/lib/features/job-search/jobSearchTheme.js.map +1 -0
  232. package/lib/features/job-search/savedJobs.js +85 -0
  233. package/lib/features/job-search/savedJobs.js.map +1 -0
  234. package/lib/features/job-search/searchHistory.js +117 -0
  235. package/lib/features/job-search/searchHistory.js.map +1 -0
  236. package/lib/features/job-search/types.js +36 -0
  237. package/lib/features/job-search/types.js.map +1 -0
  238. package/lib/features/job-search/useJobSearchSession.js +558 -0
  239. package/lib/features/job-search/useJobSearchSession.js.map +1 -0
  240. package/lib/features/messaging/ChatComponents.js +529 -0
  241. package/lib/features/messaging/ChatComponents.js.map +1 -0
  242. package/lib/features/messaging/ChatInviteDeepLink.js +116 -0
  243. package/lib/features/messaging/ChatInviteDeepLink.js.map +1 -0
  244. package/lib/features/messaging/ContactsScreen.js +288 -0
  245. package/lib/features/messaging/ContactsScreen.js.map +1 -0
  246. package/lib/features/messaging/ConversationListScreen.js +147 -0
  247. package/lib/features/messaging/ConversationListScreen.js.map +1 -0
  248. package/lib/features/messaging/MessageActions.js +290 -0
  249. package/lib/features/messaging/MessageActions.js.map +1 -0
  250. package/lib/features/messaging/NativeChatExperience.js +189 -0
  251. package/lib/features/messaging/NativeChatExperience.js.map +1 -0
  252. package/lib/features/messaging/RegistrationScreen.js +11 -14
  253. package/lib/features/messaging/RegistrationScreen.js.map +1 -1
  254. package/lib/features/messaging/ThreadScreen.js +215 -0
  255. package/lib/features/messaging/ThreadScreen.js.map +1 -0
  256. package/lib/features/messaging/chatInviteLink.js +52 -0
  257. package/lib/features/messaging/chatInviteLink.js.map +1 -0
  258. package/lib/features/messaging/chatModel.js +278 -0
  259. package/lib/features/messaging/chatModel.js.map +1 -0
  260. package/lib/features/messaging/chatOperations.js +106 -1
  261. package/lib/features/messaging/chatOperations.js.map +1 -1
  262. package/lib/features/messaging/emojiCatalog.js +60 -0
  263. package/lib/features/messaging/emojiCatalog.js.map +1 -0
  264. package/lib/features/messaging/emojiKeywords.js +1592 -0
  265. package/lib/features/messaging/emojiKeywords.js.map +1 -0
  266. package/lib/features/messaging/nativeChatChannelQuery.js +27 -0
  267. package/lib/features/messaging/nativeChatChannelQuery.js.map +1 -0
  268. package/lib/features/messaging/phoneNumbers.js +52 -1
  269. package/lib/features/messaging/phoneNumbers.js.map +1 -1
  270. package/lib/features/messaging/sha256.js +68 -0
  271. package/lib/features/messaging/sha256.js.map +1 -0
  272. package/lib/features/messaging/useChatData.js +421 -0
  273. package/lib/features/messaging/useChatData.js.map +1 -0
  274. package/lib/features/messaging/useContactMatches.js +191 -0
  275. package/lib/features/messaging/useContactMatches.js.map +1 -0
  276. package/lib/features/messaging/usePhoneVerification.js +12 -12
  277. package/lib/features/messaging/usePhoneVerification.js.map +1 -1
  278. package/lib/features/messaging/yantraChatOrg.js +8 -3
  279. package/lib/features/messaging/yantraChatOrg.js.map +1 -1
  280. package/lib/features/resume/AnnotateModal.js +100 -0
  281. package/lib/features/resume/AnnotateModal.js.map +1 -0
  282. package/lib/features/resume/AnnotationBar.js +69 -0
  283. package/lib/features/resume/AnnotationBar.js.map +1 -0
  284. package/lib/features/resume/ExportSheet.js +105 -0
  285. package/lib/features/resume/ExportSheet.js.map +1 -0
  286. package/lib/features/resume/ResumeAgentChatPane.js +95 -0
  287. package/lib/features/resume/ResumeAgentChatPane.js.map +1 -0
  288. package/lib/features/resume/ResumeEditor.js +676 -0
  289. package/lib/features/resume/ResumeEditor.js.map +1 -0
  290. package/lib/features/resume/ResumeExperience.js +235 -0
  291. package/lib/features/resume/ResumeExperience.js.map +1 -0
  292. package/lib/features/resume/ResumeListPanel.js +262 -0
  293. package/lib/features/resume/ResumeListPanel.js.map +1 -0
  294. package/lib/features/resume/ResumeToolbar.js +236 -0
  295. package/lib/features/resume/ResumeToolbar.js.map +1 -0
  296. package/lib/features/resume/annotations.js +17 -0
  297. package/lib/features/resume/annotations.js.map +1 -0
  298. package/lib/features/resume/documentCss.js +52 -0
  299. package/lib/features/resume/documentCss.js.map +1 -0
  300. package/lib/features/resume/draft.js +89 -0
  301. package/lib/features/resume/draft.js.map +1 -0
  302. package/lib/features/resume/exportResume.js +43 -0
  303. package/lib/features/resume/exportResume.js.map +1 -0
  304. package/lib/features/resume/pickResumePhoto.js +22 -0
  305. package/lib/features/resume/pickResumePhoto.js.map +1 -0
  306. package/lib/features/resume/renderResume.js +121 -0
  307. package/lib/features/resume/renderResume.js.map +1 -0
  308. package/lib/features/resume/resumeClient.js +69 -0
  309. package/lib/features/resume/resumeClient.js.map +1 -0
  310. package/lib/features/resume/resumeExec.js +14 -0
  311. package/lib/features/resume/resumeExec.js.map +1 -0
  312. package/lib/features/resume/resumeIndex.js +244 -0
  313. package/lib/features/resume/resumeIndex.js.map +1 -0
  314. package/lib/features/resume/resumeRuntime.js +50 -0
  315. package/lib/features/resume/resumeRuntime.js.map +1 -0
  316. package/lib/features/resume/resumeTheme.js +34 -0
  317. package/lib/features/resume/resumeTheme.js.map +1 -0
  318. package/lib/features/resume/resumeToolbox.js +49 -0
  319. package/lib/features/resume/resumeToolbox.js.map +1 -0
  320. package/lib/features/resume/templates.js +90 -0
  321. package/lib/features/resume/templates.js.map +1 -0
  322. package/lib/features/resume/types.js +10 -0
  323. package/lib/features/resume/types.js.map +1 -0
  324. package/lib/features/resume/useResumeSession.js +183 -0
  325. package/lib/features/resume/useResumeSession.js.map +1 -0
  326. package/lib/features/shopping/DealsPanel.js +254 -0
  327. package/lib/features/shopping/DealsPanel.js.map +1 -0
  328. package/lib/features/shopping/HistoryPanel.js +147 -0
  329. package/lib/features/shopping/HistoryPanel.js.map +1 -0
  330. package/lib/features/shopping/OrdersPanel.js +157 -0
  331. package/lib/features/shopping/OrdersPanel.js.map +1 -0
  332. package/lib/features/shopping/ProductCard.js +326 -0
  333. package/lib/features/shopping/ProductCard.js.map +1 -0
  334. package/lib/features/shopping/ProductDetailSheet.js +313 -0
  335. package/lib/features/shopping/ProductDetailSheet.js.map +1 -0
  336. package/lib/features/shopping/ProductFilterBar.js +153 -0
  337. package/lib/features/shopping/ProductFilterBar.js.map +1 -0
  338. package/lib/features/shopping/ProductPhoto.js +27 -0
  339. package/lib/features/shopping/ProductPhoto.js.map +1 -0
  340. package/lib/features/shopping/SavedPanel.js +139 -0
  341. package/lib/features/shopping/SavedPanel.js.map +1 -0
  342. package/lib/features/shopping/ShoppingAgentChatPane.js +436 -0
  343. package/lib/features/shopping/ShoppingAgentChatPane.js.map +1 -0
  344. package/lib/features/shopping/ShoppingExperience.js +888 -0
  345. package/lib/features/shopping/ShoppingExperience.js.map +1 -0
  346. package/lib/features/shopping/TrendingSections.js +199 -0
  347. package/lib/features/shopping/TrendingSections.js.map +1 -0
  348. package/lib/features/shopping/WatchlistPanel.js +148 -0
  349. package/lib/features/shopping/WatchlistPanel.js.map +1 -0
  350. package/lib/features/shopping/catalog.js +238 -0
  351. package/lib/features/shopping/catalog.js.map +1 -0
  352. package/lib/features/shopping/chat/ShoppingChatResultCard.js +175 -0
  353. package/lib/features/shopping/chat/ShoppingChatResultCard.js.map +1 -0
  354. package/lib/features/shopping/chat/streamAssistantReply.js +34 -0
  355. package/lib/features/shopping/chat/streamAssistantReply.js.map +1 -0
  356. package/lib/features/shopping/chat/widgetContent.js +233 -0
  357. package/lib/features/shopping/chat/widgetContent.js.map +1 -0
  358. package/lib/features/shopping/hooks/useTrendingProducts.js +162 -0
  359. package/lib/features/shopping/hooks/useTrendingProducts.js.map +1 -0
  360. package/lib/features/shopping/productImage.js +42 -0
  361. package/lib/features/shopping/productImage.js.map +1 -0
  362. package/lib/features/shopping/savedProducts.js +84 -0
  363. package/lib/features/shopping/savedProducts.js.map +1 -0
  364. package/lib/features/shopping/services/catalogActions.js +166 -0
  365. package/lib/features/shopping/services/catalogActions.js.map +1 -0
  366. package/lib/features/shopping/services/parsePriceCheckIntent.js +58 -0
  367. package/lib/features/shopping/services/parsePriceCheckIntent.js.map +1 -0
  368. package/lib/features/shopping/services/parseShoppingIntent.js +67 -0
  369. package/lib/features/shopping/services/parseShoppingIntent.js.map +1 -0
  370. package/lib/features/shopping/services/productAvailability.js +25 -0
  371. package/lib/features/shopping/services/productAvailability.js.map +1 -0
  372. package/lib/features/shopping/services/productFilters.js +72 -0
  373. package/lib/features/shopping/services/productFilters.js.map +1 -0
  374. package/lib/features/shopping/services/retailerUrl.js +75 -0
  375. package/lib/features/shopping/services/retailerUrl.js.map +1 -0
  376. package/lib/features/shopping/services/shoppingChatReply.js +46 -0
  377. package/lib/features/shopping/services/shoppingChatReply.js.map +1 -0
  378. package/lib/features/shopping/services/shoppingProductSearch.js +336 -0
  379. package/lib/features/shopping/services/shoppingProductSearch.js.map +1 -0
  380. package/lib/features/shopping/services/shoppingSearchConnectorClient.js +41 -0
  381. package/lib/features/shopping/services/shoppingSearchConnectorClient.js.map +1 -0
  382. package/lib/features/shopping/shopAgentSwipe.js +7 -0
  383. package/lib/features/shopping/shopAgentSwipe.js.map +1 -0
  384. package/lib/features/shopping/shoppingCart.js +116 -0
  385. package/lib/features/shopping/shoppingCart.js.map +1 -0
  386. package/lib/features/shopping/shoppingExec.js +14 -0
  387. package/lib/features/shopping/shoppingExec.js.map +1 -0
  388. package/lib/features/shopping/shoppingHistoryStore.js +176 -0
  389. package/lib/features/shopping/shoppingHistoryStore.js.map +1 -0
  390. package/lib/features/shopping/shoppingRuntime.js +63 -0
  391. package/lib/features/shopping/shoppingRuntime.js.map +1 -0
  392. package/lib/features/shopping/timeAgo.js +14 -0
  393. package/lib/features/shopping/timeAgo.js.map +1 -0
  394. package/lib/features/shopping/useShoppingSearch.js +262 -0
  395. package/lib/features/shopping/useShoppingSearch.js.map +1 -0
  396. package/lib/features/travel/BookHeaderGlow.js +48 -0
  397. package/lib/features/travel/BookHeaderGlow.js.map +1 -0
  398. package/lib/features/travel/BookingsPanel.js +29 -0
  399. package/lib/features/travel/BookingsPanel.js.map +1 -0
  400. package/lib/features/travel/DiscoverPanel.js +155 -0
  401. package/lib/features/travel/DiscoverPanel.js.map +1 -0
  402. package/lib/features/travel/FlightCompareBar.js +86 -0
  403. package/lib/features/travel/FlightCompareBar.js.map +1 -0
  404. package/lib/features/travel/FlightDealsBoard.js +100 -0
  405. package/lib/features/travel/FlightDealsBoard.js.map +1 -0
  406. package/lib/features/travel/HistoryPanel.js +82 -0
  407. package/lib/features/travel/HistoryPanel.js.map +1 -0
  408. package/lib/features/travel/PopularDestinations.js +144 -0
  409. package/lib/features/travel/PopularDestinations.js.map +1 -0
  410. package/lib/features/travel/SavedPanel.js +27 -0
  411. package/lib/features/travel/SavedPanel.js.map +1 -0
  412. package/lib/features/travel/TravelAgentChatPane.js +303 -0
  413. package/lib/features/travel/TravelAgentChatPane.js.map +1 -0
  414. package/lib/features/travel/TravelBookHero.js +425 -0
  415. package/lib/features/travel/TravelBookHero.js.map +1 -0
  416. package/lib/features/travel/TravelDatesField.js +234 -0
  417. package/lib/features/travel/TravelDatesField.js.map +1 -0
  418. package/lib/features/travel/TravelDetailSheet.js +106 -0
  419. package/lib/features/travel/TravelDetailSheet.js.map +1 -0
  420. package/lib/features/travel/TravelExperience.js +624 -0
  421. package/lib/features/travel/TravelExperience.js.map +1 -0
  422. package/lib/features/travel/TravelGuestsField.js +85 -0
  423. package/lib/features/travel/TravelGuestsField.js.map +1 -0
  424. package/lib/features/travel/TravelLanding.js +318 -0
  425. package/lib/features/travel/TravelLanding.js.map +1 -0
  426. package/lib/features/travel/TravelLocationField.js +179 -0
  427. package/lib/features/travel/TravelLocationField.js.map +1 -0
  428. package/lib/features/travel/TravelPropertyCard.js +266 -0
  429. package/lib/features/travel/TravelPropertyCard.js.map +1 -0
  430. package/lib/features/travel/TravelPropertyPhoto.js +22 -0
  431. package/lib/features/travel/TravelPropertyPhoto.js.map +1 -0
  432. package/lib/features/travel/TravelRailFlyout.js +79 -0
  433. package/lib/features/travel/TravelRailFlyout.js.map +1 -0
  434. package/lib/features/travel/TravelResultsMap.js +126 -0
  435. package/lib/features/travel/TravelResultsMap.js.map +1 -0
  436. package/lib/features/travel/WorkspacePanel.js +148 -0
  437. package/lib/features/travel/WorkspacePanel.js.map +1 -0
  438. package/lib/features/travel/appNav.js +244 -0
  439. package/lib/features/travel/appNav.js.map +1 -0
  440. package/lib/features/travel/calendarDays.js +50 -0
  441. package/lib/features/travel/calendarDays.js.map +1 -0
  442. package/lib/features/travel/catalog.js +72 -0
  443. package/lib/features/travel/catalog.js.map +1 -0
  444. package/lib/features/travel/chat/TravelChatResultCard.js +107 -0
  445. package/lib/features/travel/chat/TravelChatResultCard.js.map +1 -0
  446. package/lib/features/travel/chat/widgetContent.js +107 -0
  447. package/lib/features/travel/chat/widgetContent.js.map +1 -0
  448. package/lib/features/travel/flightDeals.js +65 -0
  449. package/lib/features/travel/flightDeals.js.map +1 -0
  450. package/lib/features/travel/mapCoordinates.js +36 -0
  451. package/lib/features/travel/mapCoordinates.js.map +1 -0
  452. package/lib/features/travel/parseTravelIntent.js +303 -0
  453. package/lib/features/travel/parseTravelIntent.js.map +1 -0
  454. package/lib/features/travel/savedStays.js +66 -0
  455. package/lib/features/travel/savedStays.js.map +1 -0
  456. package/lib/features/travel/services/flightDealsBoard.js +111 -0
  457. package/lib/features/travel/services/flightDealsBoard.js.map +1 -0
  458. package/lib/features/travel/services/flightSearchConnectorClient.js +42 -0
  459. package/lib/features/travel/services/flightSearchConnectorClient.js.map +1 -0
  460. package/lib/features/travel/services/geocodeLocation.js +79 -0
  461. package/lib/features/travel/services/geocodeLocation.js.map +1 -0
  462. package/lib/features/travel/services/placePredictions.js +113 -0
  463. package/lib/features/travel/services/placePredictions.js.map +1 -0
  464. package/lib/features/travel/services/resolveOriginCity.js +27 -0
  465. package/lib/features/travel/services/resolveOriginCity.js.map +1 -0
  466. package/lib/features/travel/services/resortifiConnectorClient.js +76 -0
  467. package/lib/features/travel/services/resortifiConnectorClient.js.map +1 -0
  468. package/lib/features/travel/services/travelFlightSearch.js +289 -0
  469. package/lib/features/travel/services/travelFlightSearch.js.map +1 -0
  470. package/lib/features/travel/services/travelPropertySearch.js +377 -0
  471. package/lib/features/travel/services/travelPropertySearch.js.map +1 -0
  472. package/lib/features/travel/travelAgentSwipe.js +7 -0
  473. package/lib/features/travel/travelAgentSwipe.js.map +1 -0
  474. package/lib/features/travel/travelExec.js +14 -0
  475. package/lib/features/travel/travelExec.js.map +1 -0
  476. package/lib/features/travel/travelHistoryStore.js +108 -0
  477. package/lib/features/travel/travelHistoryStore.js.map +1 -0
  478. package/lib/features/travel/travelRuntime.js +62 -0
  479. package/lib/features/travel/travelRuntime.js.map +1 -0
  480. package/lib/features/travel/types.js +9 -0
  481. package/lib/features/travel/types.js.map +1 -0
  482. package/lib/features/travel/useTravelSearch.js +330 -0
  483. package/lib/features/travel/useTravelSearch.js.map +1 -0
  484. package/lib/features/travel/workspaceContent.js +548 -0
  485. package/lib/features/travel/workspaceContent.js.map +1 -0
  486. package/lib/hooks/useCdecliChannel.js +128 -6
  487. package/lib/hooks/useCdecliChannel.js.map +1 -1
  488. package/lib/hooks/useChatApi.js +4 -2
  489. package/lib/hooks/useChatApi.js.map +1 -1
  490. package/lib/hooks/useChatStream.js +77 -63
  491. package/lib/hooks/useChatStream.js.map +1 -1
  492. package/lib/hooks/useHostConnectorCard.js +24 -0
  493. package/lib/hooks/useHostConnectorCard.js.map +1 -0
  494. package/lib/hooks/useObtainSystemToken.js +23 -5
  495. package/lib/hooks/useObtainSystemToken.js.map +1 -1
  496. package/lib/hooks/webViewRetentionPolicy.js +1 -0
  497. package/lib/hooks/webViewRetentionPolicy.js.map +1 -1
  498. package/lib/index.js +1 -1
  499. package/lib/index.js.map +1 -1
  500. package/lib/screens/Chat/index.js +51 -22
  501. package/lib/screens/Chat/index.js.map +1 -1
  502. package/lib/screens/ChatNative/index.js +13 -2
  503. package/lib/screens/ChatNative/index.js.map +1 -1
  504. package/lib/screens/Home/HomeScreen.js +3 -3
  505. package/lib/screens/Home/HomeScreen.js.map +1 -1
  506. package/lib/screens/Home/components/ChatHistoryLanding.js +32 -32
  507. package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
  508. package/lib/screens/JobSearchNative/useJobSearchHostChat.js +12 -6
  509. package/lib/screens/JobSearchNative/useJobSearchHostChat.js.map +1 -1
  510. package/lib/screens/ResumeNative/useResumeHostChat.js +12 -6
  511. package/lib/screens/ResumeNative/useResumeHostChat.js.map +1 -1
  512. package/lib/screens/ShoppingNative/useShoppingHostChat.js +12 -6
  513. package/lib/screens/ShoppingNative/useShoppingHostChat.js.map +1 -1
  514. package/lib/screens/TravelNative/useTravelHostChat.js +12 -6
  515. package/lib/screens/TravelNative/useTravelHostChat.js.map +1 -1
  516. package/lib/screens/WebBuilder/WebViewWithNavigation.js +2 -2
  517. package/lib/screens/WebBuilder/WebViewWithNavigation.js.map +1 -1
  518. package/lib/services/brainQuickReply.js +38 -1
  519. package/lib/services/brainQuickReply.js.map +1 -1
  520. package/lib/state/chatThreadMerge.js +6 -1
  521. package/lib/state/chatThreadMerge.js.map +1 -1
  522. package/package.json +6 -4
@@ -0,0 +1,3050 @@
1
+ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useState,useMemo,useRef,useEffect,useCallback}from'react';import {StyleSheet,useWindowDimensions,Platform,Alert,View,Text,Pressable,FlatList,ActivityIndicator,TextInput,ScrollView}from'react-native';import {KeyboardAwareScreen,KeyboardLiftSpacer}from'../../components/KeyboardComposerDock.js';import {dismissKeyboard}from'../../utils/keyboardController.js';import {GestureHandlerRootView,Gesture,GestureDetector}from'react-native-gesture-handler';import {MaterialCommunityIcons}from'@expo/vector-icons';import {Image}from'expo-image';import {getVideoPreviewRenderer}from'./videoRenderer.js';import {friendlyMediaError,resultUrl,generationMediaUrl}from'./videoEditor/mediaActions.js';import {clipFromItem,emptyTimeline,timelineDuration,updateClip,clipFromColor,textClipAt,newSegment,buildExportSpec,removeClip,moveClip,trimClip,SPEED_PRESETS,SPEED_CURVES,TEXT_PRESETS,updateText,removeText,MOTION_MOVES,MOTION_STRENGTHS,CLIP_TRANSITIONS,moveIdOf,kenBurnsFor,DEFAULT_IMAGE_SEC,clipTimelineSec}from'./videoEditor/editorModel.js';import {filterById,FILTER_PRESETS}from'./videoEditor/filters.js';import {useSafeInsets}from'./withRemoteSafeArea.js';import {buildVideoGenerateParams,STATIC_VIDEO_MODELS}from'./generationModels.js';import {mapDesignCorpus,playableTemplatePreviewUrl}from'./canvasChatTemplates.js';import {config}from'../../config/env-config.js';import {useStudioCatalogTemplates}from'./useStudioCatalogTemplates.js';import {DESIGN_PROMPT_TEMPLATES}from'./designPromptTemplates.js';import {templateHasUsableConfig,loadTemplateTimeline}from'./templateImport/loadTemplate.js';import {loadVideoProjects,projectHasWork,newVideoProjectId,snapshotProject,upsertVideoProject,persistVideoProjects,relativeProjectTime}from'./videoEditor/videoProjectsStore.js';import {AgentCutPane}from'./videoEditor/agent/AgentCutPane.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function nextProjectTitle(rows, currentTitle) {
21
+ const used = new Set(rows.map((row) => row.title.trim()));
22
+ used.add(currentTitle.trim());
23
+ if (!used.has("Untitled project")) return "Untitled project";
24
+ let n = 2;
25
+ while (used.has(`Untitled project ${n}`)) n += 1;
26
+ return `Untitled project ${n}`;
27
+ }
28
+ const TABS = [{
29
+ id: "projects",
30
+ icon: "folder-open-outline",
31
+ label: "Projects"
32
+ }, {
33
+ id: "media",
34
+ icon: "image-plus",
35
+ label: "Media"
36
+ }, {
37
+ id: "templates",
38
+ icon: "view-grid-outline",
39
+ label: "Templates"
40
+ }, {
41
+ id: "text",
42
+ icon: "format-title",
43
+ label: "Text"
44
+ }, {
45
+ id: "elements",
46
+ icon: "shape-outline",
47
+ label: "Elements"
48
+ }, {
49
+ id: "music",
50
+ icon: "music",
51
+ label: "Music"
52
+ }, {
53
+ id: "voiceover",
54
+ icon: "microphone-outline",
55
+ label: "Voiceover"
56
+ }, {
57
+ id: "captions",
58
+ icon: "closed-caption",
59
+ label: "Captions"
60
+ }, {
61
+ id: "audio",
62
+ icon: "waveform",
63
+ label: "Audio"
64
+ }, {
65
+ id: "logo",
66
+ icon: "postage-stamp",
67
+ label: "Logo"
68
+ }, {
69
+ id: "agent",
70
+ icon: "robot-outline",
71
+ label: "AI cut"
72
+ }];
73
+ const SEGMENT_KINDS = [{
74
+ kind: "speed",
75
+ label: "Speed",
76
+ hint: "Play this range faster or slower",
77
+ icon: "speedometer"
78
+ }, {
79
+ kind: "zoom",
80
+ label: "Zoom",
81
+ hint: "Punch in on a spot for this range",
82
+ icon: "magnify-plus-outline"
83
+ }, {
84
+ kind: "crop",
85
+ label: "Crop",
86
+ hint: "Show only a region for this range",
87
+ icon: "crop"
88
+ }, {
89
+ kind: "trim",
90
+ label: "Trim",
91
+ hint: "Skip this range in playback and export",
92
+ icon: "content-cut"
93
+ }];
94
+ const SCENE_COLORS = ["#101014", "#f4f4f5", "#1d4ed8", "#7c2d12"];
95
+ const SPEED_CURVE_LABEL = {
96
+ constant: "Constant",
97
+ "ease-in": "Ease in",
98
+ "ease-out": "Ease out",
99
+ pulse: "Pulse"
100
+ };
101
+ function loadEditorWebView() {
102
+ try {
103
+ return require("react-native-webview").WebView;
104
+ } catch (e) {
105
+ return null;
106
+ }
107
+ }
108
+ function canvasDocumentBase() {
109
+ const raw = (config.CANVAS_SURFACE_URL || "").trim();
110
+ if (/^https:\/\//i.test(raw) && !/localhost/i.test(raw)) {
111
+ return raw.endsWith("/") ? raw : `${raw}/`;
112
+ }
113
+ const template = config.SURFACE_URL_TEMPLATE || "https://{slug}-surface.yantra-app-v1.cdebase.dev/";
114
+ return template.replace("{slug}", "canvas").replace(/\/?$/, "/");
115
+ }
116
+ function htmlVideoPage(src, poster) {
117
+ const esc = (value) => value.replace(/&/g, "&").replace(/"/g, """);
118
+ const posterAttr = poster ? ` poster="${esc(poster)}"` : "";
119
+ return `<!DOCTYPE html><html><head>
120
+ <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
121
+ <style>html,body{margin:0;height:100%;background:#000}video{width:100%;height:100%;object-fit:contain;background:#000}</style>
122
+ </head><body>
123
+ <video src="${esc(src)}"${posterAttr} autoplay loop controls playsinline webkit-playsinline></video>
124
+ </body></html>`;
125
+ }
126
+ function TemplateWebPreview({
127
+ src,
128
+ poster
129
+ }) {
130
+ const WebView = loadEditorWebView();
131
+ const playable = playableTemplatePreviewUrl(src);
132
+ if (!playable || !WebView) {
133
+ return poster ? /* @__PURE__ */ jsx(Image, { source: {
134
+ uri: poster
135
+ }, style: styles.templatePreviewImage, contentFit: "contain" }) : null;
136
+ }
137
+ return /* @__PURE__ */ jsx(WebView, { source: {
138
+ html: htmlVideoPage(playable, poster),
139
+ baseUrl: canvasDocumentBase()
140
+ }, style: styles.templateWebView, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, javaScriptEnabled: true, allowsFullscreenVideo: true, originWhitelist: ["*"], mixedContentMode: "always", setSupportMultipleWindows: false, scrollEnabled: false });
141
+ }
142
+ function TemplateCatalogCard({
143
+ row,
144
+ generating,
145
+ using,
146
+ onGenerate,
147
+ onPreview,
148
+ onUse
149
+ }) {
150
+ const canPreview = Boolean(row.coverVideo || row.cover);
151
+ const canUse = Boolean(onUse && templateHasUsableConfig(row));
152
+ return /* @__PURE__ */ jsxs(View, { style: styles.templateCard, children: [
153
+ row.cover ? /* @__PURE__ */ jsx(Image, { source: {
154
+ uri: row.cover
155
+ }, style: styles.templateCover, contentFit: "cover" }) : /* @__PURE__ */ jsx(View, { style: [styles.templateCover, styles.mediaThumbVideo], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "movie-open-outline", size: 22, color: "#9A9AA5" }) }),
156
+ /* @__PURE__ */ jsx(Text, { style: styles.templateTitle, numberOfLines: 2, children: row.title }),
157
+ /* @__PURE__ */ jsxs(View, { style: styles.templateActions, children: [
158
+ canUse ? /* @__PURE__ */ jsxs(Pressable, { onPress: () => onUse == null ? void 0 : onUse(row), disabled: using || generating, style: [styles.templateGenerate, (using || generating) && styles.disabled], accessibilityRole: "button", accessibilityLabel: `Use template ${row.title}`, children: [
159
+ using ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#F2F2F5", size: "small" }) : /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "layers-outline", size: 13, color: "#F2F2F5" }),
160
+ /* @__PURE__ */ jsx(Text, { style: styles.templateGenerateLabel, numberOfLines: 1, children: "Use" })
161
+ ] }) : /* @__PURE__ */ jsxs(Pressable, { onPress: () => onGenerate(row), disabled: generating || !row.prompt.trim(), style: [styles.templateGenerate, (generating || !row.prompt.trim()) && styles.disabled], accessibilityRole: "button", accessibilityLabel: `Generate ${row.title}`, children: [
162
+ generating ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#F2F2F5", size: "small" }) : /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "auto-fix", size: 13, color: "#F2F2F5" }),
163
+ /* @__PURE__ */ jsx(Text, { style: styles.templateGenerateLabel, numberOfLines: 1, children: "Generate" })
164
+ ] }),
165
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => onPreview(row), disabled: !canPreview, style: [styles.templatePreviewBtn, !canPreview && styles.disabled], accessibilityRole: "button", accessibilityLabel: `Preview ${row.title}`, children: [
166
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "play", size: 13, color: "#D8D8E0" }),
167
+ /* @__PURE__ */ jsx(Text, { style: styles.templatePreviewLabel, numberOfLines: 1, children: "Preview" })
168
+ ] })
169
+ ] })
170
+ ] });
171
+ }
172
+ function VideoEditorExperience({
173
+ items,
174
+ seedItemId,
175
+ onClose,
176
+ onExport,
177
+ onPickLocalMedia,
178
+ runAction,
179
+ uploadMedia,
180
+ audioRecorder,
181
+ apolloClient,
182
+ projectTitle,
183
+ initialTimeline,
184
+ initialLogoSrc,
185
+ token,
186
+ indexUrl,
187
+ initialRailTab
188
+ }) {
189
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
190
+ const insets = useSafeInsets();
191
+ const {
192
+ width: windowWidth
193
+ } = useWindowDimensions();
194
+ const templateCols = windowWidth >= 700 ? 3 : 2;
195
+ const [deviceMedia, setDeviceMedia] = useState([]);
196
+ const [logoSrc, setLogoSrc] = useState(initialLogoSrc != null ? initialLogoSrc : null);
197
+ const media = useMemo(() => [...deviceMedia, ...items].filter((i) => i.type === "image" || i.type === "video" || i.type === "audio"), [items, deviceMedia]);
198
+ const [timeline, setTimeline] = useState(() => {
199
+ if (initialTimeline && (initialTimeline.clips.length > 0 || initialTimeline.texts.length > 0)) {
200
+ return initialTimeline;
201
+ }
202
+ const bin = items.filter((i) => i.type === "image" || i.type === "video");
203
+ if (seedItemId) {
204
+ const seed = bin.find((i) => i.id === seedItemId);
205
+ return {
206
+ clips: seed ? [clipFromItem(seed)] : [],
207
+ texts: []
208
+ };
209
+ }
210
+ return {
211
+ clips: [],
212
+ texts: []
213
+ };
214
+ });
215
+ const [selectedClipId, setSelectedClipId] = useState((_b = (_a = timeline.clips[0]) == null ? void 0 : _a.id) != null ? _b : null);
216
+ const [selectedTextId, setSelectedTextId] = useState(null);
217
+ const [tab, setTab] = useState("media");
218
+ const [railTab, setRailTab] = useState(() => {
219
+ const seed = initialRailTab;
220
+ if (seed === "agent" || seed === "media" || seed === "projects") return seed;
221
+ return null;
222
+ });
223
+ const [recordOn, setRecordOn] = useState(false);
224
+ const [recordOpen, setRecordOpen] = useState(false);
225
+ const [recordError, setRecordError] = useState(null);
226
+ const [micTakeOn, setMicTakeOn] = useState(false);
227
+ const [segmentMenuOpen, setSegmentMenuOpen] = useState(false);
228
+ const [selectedSegmentId, setSelectedSegmentId] = useState(null);
229
+ const [audioPrompt, setAudioPrompt] = useState("");
230
+ const [audioBusy, setAudioBusy] = useState(false);
231
+ const [stageTool, setStageTool] = useState(null);
232
+ const [aiPrompt, setAiPrompt] = useState("");
233
+ const [aiBusy, setAiBusy] = useState(false);
234
+ const [usingTemplateId, setUsingTemplateId] = useState(null);
235
+ const [notice, setNotice] = useState(null);
236
+ const [playing, setPlaying] = useState(false);
237
+ const [playhead, setPlayhead] = useState(0);
238
+ const [sourceSec, setSourceSec] = useState({});
239
+ const [scrub, setScrub] = useState({
240
+ sec: 0,
241
+ nonce: 0
242
+ });
243
+ const [dirty, setDirty] = useState(false);
244
+ const [mediaBusy, setMediaBusy] = useState(false);
245
+ const [uploadStatus, setUploadStatus] = useState(null);
246
+ const [templateQuery, setTemplateQuery] = useState("");
247
+ const [templateSearch, setTemplateSearch] = useState("");
248
+ const [templatePreview, setTemplatePreview] = useState(null);
249
+ const pickLock = useRef(false);
250
+ const [projectRows, setProjectRows] = useState([]);
251
+ const [activeProjectId, setActiveProjectId] = useState(null);
252
+ const [localTitle, setLocalTitle] = useState(() => (projectTitle == null ? void 0 : projectTitle.trim()) || "Untitled project");
253
+ const [renameId, setRenameId] = useState(null);
254
+ const [renameDraft, setRenameDraft] = useState("");
255
+ const timelineRef = useRef(timeline);
256
+ timelineRef.current = timeline;
257
+ const titleRef = useRef(localTitle);
258
+ titleRef.current = localTitle;
259
+ const logoRef = useRef(logoSrc);
260
+ logoRef.current = logoSrc;
261
+ const activeIdRef = useRef(activeProjectId);
262
+ activeIdRef.current = activeProjectId;
263
+ const rowsRef = useRef(projectRows);
264
+ rowsRef.current = projectRows;
265
+ useEffect(() => {
266
+ let live = true;
267
+ void loadVideoProjects().then((rows) => {
268
+ if (live) setProjectRows(rows);
269
+ });
270
+ return () => {
271
+ live = false;
272
+ };
273
+ }, []);
274
+ useEffect(() => {
275
+ if (timeline.clips.length === 0 && playing) setPlaying(false);
276
+ }, [timeline.clips.length, playing]);
277
+ const flushProject = useCallback(() => {
278
+ var _a2;
279
+ const current = timelineRef.current;
280
+ if (!projectHasWork(current)) return;
281
+ const id = (_a2 = activeIdRef.current) != null ? _a2 : newVideoProjectId();
282
+ if (!activeIdRef.current) {
283
+ activeIdRef.current = id;
284
+ setActiveProjectId(id);
285
+ }
286
+ const snap = snapshotProject(id, titleRef.current, current, logoRef.current);
287
+ const next = upsertVideoProject(rowsRef.current, snap);
288
+ rowsRef.current = next;
289
+ setProjectRows(next);
290
+ persistVideoProjects(next);
291
+ setDirty(false);
292
+ }, []);
293
+ useEffect(() => {
294
+ if (!dirty || !projectHasWork(timeline)) return void 0;
295
+ const handle = setTimeout(() => flushProject(), 800);
296
+ return () => clearTimeout(handle);
297
+ }, [dirty, timeline, localTitle, logoSrc, flushProject]);
298
+ const applyNewProject = useCallback((name) => {
299
+ var _a2;
300
+ dismissKeyboard();
301
+ setRenameId(null);
302
+ const current = timelineRef.current;
303
+ let rows = rowsRef.current;
304
+ if (projectHasWork(current) || activeIdRef.current) {
305
+ const id = (_a2 = activeIdRef.current) != null ? _a2 : newVideoProjectId();
306
+ rows = upsertVideoProject(rows, snapshotProject(id, titleRef.current, current, logoRef.current));
307
+ }
308
+ const title = name.trim() || nextProjectTitle(rows, titleRef.current);
309
+ const newId = newVideoProjectId();
310
+ const blank = emptyTimeline();
311
+ rows = upsertVideoProject(rows, snapshotProject(newId, title, blank, null));
312
+ rowsRef.current = rows;
313
+ persistVideoProjects(rows);
314
+ setProjectRows(rows);
315
+ timelineRef.current = blank;
316
+ logoRef.current = null;
317
+ activeIdRef.current = newId;
318
+ titleRef.current = title;
319
+ setTimeline(blank);
320
+ setLogoSrc(null);
321
+ setSelectedClipId(null);
322
+ setSelectedTextId(null);
323
+ setActiveProjectId(newId);
324
+ setLocalTitle(title);
325
+ setDirty(false);
326
+ setPlaying(false);
327
+ setPlayhead(0);
328
+ setStageTool(null);
329
+ setRailTab("projects");
330
+ setTab("projects");
331
+ setNotice(`Created \u201C${title}\u201D. Tap Open Media to add clips.`);
332
+ }, []);
333
+ const startNewProject = useCallback(() => {
334
+ const suggested = nextProjectTitle(rowsRef.current, titleRef.current);
335
+ if (Platform.OS === "ios") {
336
+ Alert.prompt("New project", "Name this cut, then add clips from Media.", [{
337
+ text: "Cancel",
338
+ style: "cancel"
339
+ }, {
340
+ text: "Create",
341
+ onPress: (value) => applyNewProject(value || suggested)
342
+ }], "plain-text", suggested);
343
+ return;
344
+ }
345
+ Alert.alert("New project", `Create \u201C${suggested}\u201D?`, [{
346
+ text: "Cancel",
347
+ style: "cancel"
348
+ }, {
349
+ text: "Create",
350
+ onPress: () => applyNewProject(suggested)
351
+ }]);
352
+ }, [applyNewProject]);
353
+ const openSavedProject = useCallback((row) => {
354
+ var _a2, _b2, _c2, _d2;
355
+ flushProject();
356
+ setTimeline({
357
+ clips: [...row.timeline.clips],
358
+ texts: [...row.timeline.texts],
359
+ segments: row.timeline.segments ? [...row.timeline.segments] : [],
360
+ voiceover: (_a2 = row.timeline.voiceover) != null ? _a2 : null,
361
+ soundtrack: (_b2 = row.timeline.soundtrack) != null ? _b2 : null
362
+ });
363
+ setLogoSrc(row.logoSrc);
364
+ setActiveProjectId(row.id);
365
+ activeIdRef.current = row.id;
366
+ setLocalTitle(row.title);
367
+ setSelectedClipId((_d2 = (_c2 = row.timeline.clips[0]) == null ? void 0 : _c2.id) != null ? _d2 : null);
368
+ setSelectedTextId(null);
369
+ setDirty(false);
370
+ setPlaying(false);
371
+ setRailTab(null);
372
+ }, [flushProject]);
373
+ const deleteSavedProject = useCallback((id) => {
374
+ const next = rowsRef.current.filter((row) => row.id !== id);
375
+ rowsRef.current = next;
376
+ setProjectRows(next);
377
+ persistVideoProjects(next);
378
+ if (activeIdRef.current !== id) return;
379
+ setTimeline(emptyTimeline());
380
+ setLogoSrc(null);
381
+ setSelectedClipId(null);
382
+ setSelectedTextId(null);
383
+ setActiveProjectId(null);
384
+ activeIdRef.current = null;
385
+ setLocalTitle("Untitled project");
386
+ setDirty(false);
387
+ setRailTab(null);
388
+ }, []);
389
+ useEffect(() => {
390
+ const handle = setTimeout(() => setTemplateSearch(templateQuery.trim()), templateQuery.trim() ? 300 : 0);
391
+ return () => clearTimeout(handle);
392
+ }, [templateQuery]);
393
+ const videoCorpus = useMemo(() => mapDesignCorpus("video", DESIGN_PROMPT_TEMPLATES), []);
394
+ const {
395
+ templates,
396
+ loading: templatesLoading,
397
+ loadingMore: templatesLoadingMore,
398
+ loadMore: fetchMoreTemplates
399
+ } = useStudioCatalogTemplates(templateSearch, apolloClient, runAction, videoCorpus);
400
+ const loadMoreTemplates = useCallback(() => {
401
+ fetchMoreTemplates();
402
+ }, [fetchMoreTemplates]);
403
+ const templateGrid = useMemo(() => {
404
+ const rows = [];
405
+ for (let i = 0; i < templates.length; i += templateCols) {
406
+ rows.push(templates.slice(i, i + templateCols));
407
+ }
408
+ return rows;
409
+ }, [templateCols, templates]);
410
+ const selected = (_c = timeline.clips.find((c) => c.id === selectedClipId)) != null ? _c : null;
411
+ const selectedIndex = selected ? timeline.clips.indexOf(selected) : -1;
412
+ const selectedText = (_d = timeline.texts.find((t) => t.id === selectedTextId)) != null ? _d : null;
413
+ const total = timelineDuration(timeline.clips);
414
+ const patchSelected = useCallback((patch) => {
415
+ if (!selectedClipId) return;
416
+ setDirty(true);
417
+ setTimeline((t) => updateClip(t, selectedClipId, patch));
418
+ }, [selectedClipId]);
419
+ const addClip = useCallback((item) => {
420
+ const clip = clipFromItem(item);
421
+ setDirty(true);
422
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
423
+ clips: [...t.clips, clip]
424
+ }));
425
+ setSelectedClipId(clip.id);
426
+ setSelectedTextId(null);
427
+ setRailTab(null);
428
+ setNotice("Added to the timeline");
429
+ }, []);
430
+ const addBlankScene = useCallback(() => {
431
+ const clip = clipFromColor("#101014");
432
+ const title = textClipAt(0, {
433
+ text: "Build your own scene",
434
+ x: 0.5,
435
+ y: 0.46
436
+ });
437
+ setDirty(true);
438
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
439
+ clips: [...t.clips, clip],
440
+ texts: [...t.texts, title]
441
+ }));
442
+ setSelectedClipId(clip.id);
443
+ setSelectedTextId(title.id);
444
+ setRailTab(null);
445
+ setNotice("Blank scene added \u2014 edit the title or open Media.");
446
+ }, []);
447
+ const previewStudioTemplate = useCallback((row) => {
448
+ const sample = playableTemplatePreviewUrl(row.coverVideo);
449
+ if (sample) {
450
+ setPlaying(false);
451
+ setTemplatePreview({
452
+ src: sample,
453
+ poster: row.cover,
454
+ title: row.title,
455
+ kind: "video",
456
+ aspect: row.aspect
457
+ });
458
+ return;
459
+ }
460
+ if (row.cover) {
461
+ setPlaying(false);
462
+ setTemplatePreview({
463
+ src: row.cover,
464
+ poster: row.cover,
465
+ title: row.title,
466
+ kind: "image",
467
+ aspect: row.aspect
468
+ });
469
+ return;
470
+ }
471
+ setNotice("This template has no sample to preview.");
472
+ }, []);
473
+ const useStudioTemplate = useCallback(async (row) => {
474
+ var _a2, _b2, _c2, _d2;
475
+ if (!templateHasUsableConfig(row) || usingTemplateId) return;
476
+ setUsingTemplateId(row.id);
477
+ setNotice(null);
478
+ try {
479
+ const imported = await loadTemplateTimeline(row);
480
+ setDirty(true);
481
+ setTimeline(imported.timeline);
482
+ setSelectedClipId((_b2 = (_a2 = imported.timeline.clips[0]) == null ? void 0 : _a2.id) != null ? _b2 : null);
483
+ setSelectedTextId((_d2 = (_c2 = imported.timeline.texts[0]) == null ? void 0 : _c2.id) != null ? _d2 : null);
484
+ if (imported.logoSrc) setLogoSrc(imported.logoSrc);
485
+ setRailTab(null);
486
+ setNotice(`Loaded \u201C${imported.title}\u201D \xB7 ${imported.scenes} scene${imported.scenes === 1 ? "" : "s"} (${imported.aspect})`);
487
+ } catch (err) {
488
+ setNotice(err instanceof Error ? err.message : "Could not load the template");
489
+ } finally {
490
+ setUsingTemplateId(null);
491
+ }
492
+ }, [usingTemplateId]);
493
+ const addText = useCallback((preset) => {
494
+ const text = textClipAt(playhead, preset);
495
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
496
+ texts: [...t.texts, text]
497
+ }));
498
+ setSelectedTextId(text.id);
499
+ setTab("text");
500
+ }, [playhead]);
501
+ const pickIntoLibrary = useCallback((source) => {
502
+ if (!onPickLocalMedia || pickLock.current) return;
503
+ pickLock.current = true;
504
+ onPickLocalMedia((message) => {
505
+ setMediaBusy(true);
506
+ setUploadStatus(message);
507
+ }, source).then((picked) => {
508
+ if (picked.length === 0) return;
509
+ setDeviceMedia((prev) => [...picked, ...prev]);
510
+ const visual = picked.find((p) => p.type === "image" || p.type === "video");
511
+ if (visual && timelineRef.current.clips.length === 0) {
512
+ addClip(visual);
513
+ return;
514
+ }
515
+ setRailTab("media");
516
+ setTab("media");
517
+ setNotice(picked.length === 1 ? "In Media \u2014 tap it to add to the timeline" : `${picked.length} items in Media \u2014 tap one to add`);
518
+ }).catch((err) => {
519
+ setNotice(friendlyMediaError(err, "media pick"));
520
+ }).finally(() => {
521
+ pickLock.current = false;
522
+ setMediaBusy(false);
523
+ setUploadStatus(null);
524
+ });
525
+ }, [onPickLocalMedia, addClip]);
526
+ const pickLogo = useCallback(() => {
527
+ if (!onPickLocalMedia || pickLock.current) return;
528
+ pickLock.current = true;
529
+ onPickLocalMedia((message) => {
530
+ setMediaBusy(true);
531
+ setUploadStatus(message);
532
+ }, "library").then((picked) => {
533
+ const image = picked.find((p) => p.type === "image");
534
+ if (image) {
535
+ setLogoSrc(image.src);
536
+ setDeviceMedia((prev) => [...picked, ...prev]);
537
+ } else if (picked.length) {
538
+ setNotice("Pick an image for the logo.");
539
+ }
540
+ }).catch((err) => {
541
+ setNotice(friendlyMediaError(err, "logo pick"));
542
+ }).finally(() => {
543
+ pickLock.current = false;
544
+ setMediaBusy(false);
545
+ setUploadStatus(null);
546
+ });
547
+ }, [onPickLocalMedia]);
548
+ const captureFromRecord = useCallback((source) => {
549
+ if (!onPickLocalMedia) {
550
+ setRecordError("Recording needs the host camera and library seam.");
551
+ return;
552
+ }
553
+ if (pickLock.current) return;
554
+ pickLock.current = true;
555
+ setRecordOn(true);
556
+ setRecordError(null);
557
+ onPickLocalMedia((message) => {
558
+ setMediaBusy(true);
559
+ setUploadStatus(message);
560
+ }, source).then((picked) => {
561
+ var _a2;
562
+ if (picked.length === 0) return;
563
+ setDeviceMedia((prev) => [...picked, ...prev]);
564
+ const visual = picked.find((p) => p.type === "image" || p.type === "video");
565
+ if (visual) {
566
+ addClip(visual);
567
+ setRecordOpen(false);
568
+ return;
569
+ }
570
+ if (((_a2 = picked[0]) == null ? void 0 : _a2.type) === "audio") {
571
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
572
+ soundtrack: {
573
+ audioUrl: picked[0].src,
574
+ mode: "mix",
575
+ title: picked[0].generatedAssetName || "Recording"
576
+ }
577
+ }));
578
+ setDirty(true);
579
+ setRecordOpen(false);
580
+ setNotice("Recording added as the soundtrack.");
581
+ return;
582
+ }
583
+ setNotice("Saved in Media \u2014 tap it to add to the timeline.");
584
+ }).catch((err) => {
585
+ setRecordError(friendlyMediaError(err, "record"));
586
+ }).finally(() => {
587
+ pickLock.current = false;
588
+ setRecordOn(false);
589
+ setMediaBusy(false);
590
+ setUploadStatus(null);
591
+ });
592
+ }, [onPickLocalMedia, addClip]);
593
+ const toggleMicTake = useCallback(() => {
594
+ if (!audioRecorder || !uploadMedia) {
595
+ setRecordError("Microphone recording needs the host recorder. Use Voiceover after opening that tab.");
596
+ return;
597
+ }
598
+ if (micTakeOn) {
599
+ audioRecorder.stop().then(async (uri) => {
600
+ setMicTakeOn(false);
601
+ if (!uri) return;
602
+ const url = await uploadMedia(uri);
603
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
604
+ voiceover: {
605
+ audioUrl: url,
606
+ mode: "mix",
607
+ voiceLabel: "Recorded take"
608
+ }
609
+ }));
610
+ setDirty(true);
611
+ setRecordOpen(false);
612
+ setNotice("Voice take added under Audio.");
613
+ }).catch((err) => {
614
+ setMicTakeOn(false);
615
+ setRecordError(friendlyMediaError(err, "record"));
616
+ });
617
+ return;
618
+ }
619
+ audioRecorder.start().then(() => setMicTakeOn(true)).catch((err) => setRecordError(friendlyMediaError(err, "record")));
620
+ }, [audioRecorder, uploadMedia, micTakeOn]);
621
+ const dropSegment = useCallback((kind) => {
622
+ if (timeline.clips.length === 0) {
623
+ setNotice("Add a scene first \u2014 segments sit across the cut.");
624
+ return;
625
+ }
626
+ const seg = newSegment(kind, playhead, Math.max(total.knownSec, 2));
627
+ setTimeline((t) => {
628
+ var _a2;
629
+ return __spreadProps(__spreadValues({}, t), {
630
+ segments: [...(_a2 = t.segments) != null ? _a2 : [], seg]
631
+ });
632
+ });
633
+ setSelectedSegmentId(seg.id);
634
+ setSegmentMenuOpen(false);
635
+ setDirty(true);
636
+ }, [playhead, timeline.clips.length, total.knownSec]);
637
+ const generateAiAudio = useCallback(() => {
638
+ const prompt = audioPrompt.trim();
639
+ if (!runAction || !prompt || audioBusy) return;
640
+ setAudioBusy(true);
641
+ runAction("yantra-audio", "YANTRA_AUDIO_RUN_PROMPT", {
642
+ prompt,
643
+ model: "fal-ai/elevenlabs/music",
644
+ durationSec: 15,
645
+ format: "mp3"
646
+ }).then((result) => {
647
+ const url = resultUrl(result, "RUN_PROMPT");
648
+ setDeviceMedia((prev) => [{
649
+ id: `audio-${Date.now()}`,
650
+ type: "audio",
651
+ src: url,
652
+ x: 0,
653
+ y: 0,
654
+ width: 1,
655
+ height: 1,
656
+ zIndex: 0,
657
+ generatedAssetName: prompt.slice(0, 28)
658
+ }, ...prev]);
659
+ setRailTab("media");
660
+ setTab("media");
661
+ setAudioPrompt("");
662
+ }).catch((err) => setNotice(friendlyMediaError(err, "AI audio"))).finally(() => setAudioBusy(false));
663
+ }, [audioBusy, audioPrompt, runAction]);
664
+ const generateAiScene = useCallback((promptOverride, opts) => {
665
+ var _a2;
666
+ const prompt = (promptOverride != null ? promptOverride : aiPrompt).trim();
667
+ if (!runAction || !prompt || aiBusy) return;
668
+ setAiBusy(true);
669
+ setNotice(null);
670
+ setTemplatePreview(null);
671
+ const still = (selected == null ? void 0 : selected.type) === "image" ? selected.src : void 0;
672
+ const aspect = (opts == null ? void 0 : opts.aspect) === "9:16" || (opts == null ? void 0 : opts.aspect) === "16:9" || (opts == null ? void 0 : opts.aspect) === "1:1" ? opts.aspect : promptOverride ? "9:16" : "16:9";
673
+ runAction("yantra-video-generation", "YANTRA_VIDEO_GENERATION_GENERATE", buildVideoGenerateParams(__spreadProps(__spreadValues({
674
+ prompt,
675
+ aspectRatio: aspect
676
+ }, promptOverride ? {} : {
677
+ model: (_a2 = STATIC_VIDEO_MODELS[0]) == null ? void 0 : _a2.id
678
+ }), {
679
+ referenceImageUrl: still
680
+ }))).then((result) => {
681
+ const url = generationMediaUrl(result);
682
+ addClip({
683
+ id: `ai-${Date.now()}`,
684
+ type: "video",
685
+ src: url,
686
+ x: 0,
687
+ y: 0,
688
+ width: 640,
689
+ height: 360,
690
+ zIndex: 1,
691
+ generatedAssetName: `Scene \xB7 ${prompt.slice(0, 24)}`
692
+ });
693
+ setAiPrompt("");
694
+ if (!(opts == null ? void 0 : opts.stayOnTemplates)) {
695
+ setRailTab("media");
696
+ setTab("media");
697
+ }
698
+ }).catch((err) => setNotice(friendlyMediaError(err, "AI scene"))).finally(() => setAiBusy(false));
699
+ }, [addClip, aiBusy, aiPrompt, runAction, selected]);
700
+ const onPreviewTime = useCallback((currentSec, durationSec) => {
701
+ setPlayhead(currentSec);
702
+ if (selectedClipId && durationSec > 0) {
703
+ setSourceSec((prev) => prev[selectedClipId] === durationSec ? prev : __spreadProps(__spreadValues({}, prev), {
704
+ [selectedClipId]: durationSec
705
+ }));
706
+ }
707
+ }, [selectedClipId]);
708
+ const exportTimeline = useCallback(() => {
709
+ if (timeline.clips.length === 0) {
710
+ setNotice("Add clips to the timeline first.");
711
+ return;
712
+ }
713
+ flushProject();
714
+ setRailTab(null);
715
+ if (onExport) onExport(buildExportSpec(timeline));
716
+ else setNotice("Export renders through the yantra-video service - not wired in this host yet.");
717
+ }, [flushProject, timeline, onExport]);
718
+ const previewPlay = useCallback(() => {
719
+ if (timeline.clips.length === 0) {
720
+ setNotice("Add a clip from Media, then tap Preview.");
721
+ return;
722
+ }
723
+ setRailTab(null);
724
+ setPlaying((on) => !on);
725
+ }, [timeline.clips.length]);
726
+ const VideoPreview = getVideoPreviewRenderer();
727
+ const selectedFilter = filterById((_e = selected == null ? void 0 : selected.filter) != null ? _e : "none");
728
+ const selectedSource = selected ? sourceSec[selected.id] : void 0;
729
+ const projectList = useMemo(() => {
730
+ if (activeProjectId && projectRows.some((row) => row.id === activeProjectId)) return projectRows;
731
+ return [{
732
+ id: "__current__",
733
+ title: localTitle,
734
+ timeline,
735
+ logoSrc,
736
+ updatedAt: Date.now()
737
+ }, ...projectRows];
738
+ }, [activeProjectId, localTitle, timeline, logoSrc, projectRows]);
739
+ return /* @__PURE__ */ jsx(GestureHandlerRootView, { style: styles.root, children: /* @__PURE__ */ jsxs(KeyboardAwareScreen, { style: styles.root, testID: "video-editor", children: [
740
+ /* @__PURE__ */ jsxs(View, { style: styles.header, children: [
741
+ /* @__PURE__ */ jsxs(View, { style: styles.headerCopy, children: [
742
+ /* @__PURE__ */ jsx(Text, { style: styles.headerProject, numberOfLines: 1, children: localTitle }),
743
+ /* @__PURE__ */ jsxs(Text, { style: styles.headerSaved, children: [
744
+ dirty ? "Unsaved" : "Saved",
745
+ /* @__PURE__ */ jsx(Text, { style: styles.headerSavedDim, children: " \xB7 30 fps MP4" })
746
+ ] })
747
+ ] }),
748
+ /* @__PURE__ */ jsx(Pressable, { onPress: previewPlay, disabled: timeline.clips.length === 0, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: playing ? "Pause preview" : "Preview", style: timeline.clips.length === 0 ? styles.disabled : styles.headerGhostBtn, children: /* @__PURE__ */ jsx(Text, { style: styles.headerGhost, children: playing ? "Pause" : "Preview" }) }),
749
+ /* @__PURE__ */ jsx(Pressable, { onPress: exportTimeline, disabled: timeline.clips.length === 0, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: "Export video", accessibilityHint: timeline.clips.length === 0 ? "Add a scene or clip before exporting" : void 0, style: [styles.exportBtn, timeline.clips.length === 0 ? styles.disabled : null], children: /* @__PURE__ */ jsx(Text, { style: styles.exportBtnLabel, children: "Export" }) }),
750
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => {
751
+ flushProject();
752
+ dismissKeyboard();
753
+ onClose();
754
+ }, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: "Close editor", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 22, color: "#E8E8EE" }) })
755
+ ] }),
756
+ /* @__PURE__ */ jsxs(View, { style: styles.workspace, children: [
757
+ railTab || recordOpen ? /* @__PURE__ */ jsxs(View, { style: [styles.sheet, railTab === "templates" && !recordOpen ? styles.sheetTall : null], children: [
758
+ /* @__PURE__ */ jsxs(View, { style: styles.sheetHead, children: [
759
+ /* @__PURE__ */ jsx(Text, { style: styles.sheetTitle, children: recordOpen ? "Record" : (_g = (_f = TABS.find((entry) => entry.id === railTab)) == null ? void 0 : _f.label) != null ? _g : "Tools" }),
760
+ railTab === "projects" && !recordOpen ? /* @__PURE__ */ jsxs(Pressable, { onPress: startNewProject, style: styles.sheetNewBtn, accessibilityRole: "button", accessibilityLabel: "New project", children: [
761
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 14, color: "#101013" }),
762
+ /* @__PURE__ */ jsx(Text, { style: styles.sheetNewBtnLabel, children: "New" })
763
+ ] }) : null,
764
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => {
765
+ setRailTab(null);
766
+ setRecordOpen(false);
767
+ setMicTakeOn(false);
768
+ }, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: "Close tools", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 18, color: "#F2F2F5" }) })
769
+ ] }),
770
+ railTab === "templates" && !recordOpen ? /* @__PURE__ */ jsx(View, { style: styles.templateSheetBody, children: /* @__PURE__ */ jsx(FlatList, { data: templateGrid, keyExtractor: (pair) => pair.map((row) => row.id).join(":"), keyboardShouldPersistTaps: "handled", style: styles.templateList, contentContainerStyle: styles.templateListInner, extraData: `${templatesLoadingMore}:${templates.length}`, ListHeaderComponent: /* @__PURE__ */ jsxs(View, { style: styles.templatesPane, children: [
771
+ /* @__PURE__ */ jsxs(View, { style: styles.searchField, children: [
772
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "magnify", size: 20, color: "#8A8A94" }),
773
+ /* @__PURE__ */ jsx(TextInput, { value: templateQuery, onChangeText: setTemplateQuery, placeholder: "Search templates\u2026", placeholderTextColor: "#6A6A74", style: styles.searchInput, autoCorrect: false, autoCapitalize: "none", autoFocus: false, returnKeyType: "search", accessibilityLabel: "Search templates", onSubmitEditing: () => setTemplateSearch(templateQuery.trim()) }),
774
+ templateQuery.length > 0 ? /* @__PURE__ */ jsx(Pressable, { onPress: () => {
775
+ setTemplateQuery("");
776
+ setTemplateSearch("");
777
+ dismissKeyboard();
778
+ }, style: styles.searchClear, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: "Clear search", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close-circle", size: 18, color: "#8A8A94" }) }) : null
779
+ ] }),
780
+ templatesLoading && templates.length === 0 ? /* @__PURE__ */ jsx(View, { style: styles.emptyPanel, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: "#E8E8EE" }) }) : templates.length === 0 ? /* @__PURE__ */ jsxs(View, { style: styles.emptyPanel, children: [
781
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "view-grid-outline", size: 22, color: "#6A6A74" }),
782
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyTitle, children: "No templates" }),
783
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyDetail, children: templateSearch ? "No templates match that search." : "The studio catalog is empty in this environment." })
784
+ ] }) : null
785
+ ] }), ListFooterComponent: templates.length === 0 ? null : /* @__PURE__ */ jsx(View, { style: styles.templateLoadBar, children: /* @__PURE__ */ jsx(Pressable, { onPress: loadMoreTemplates, disabled: templatesLoadingMore, style: [styles.loadMoreBtn, templatesLoadingMore ? styles.disabled : null], accessibilityRole: "button", accessibilityLabel: "Load more templates", children: templatesLoadingMore ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#101013" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
786
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chevron-down", size: 20, color: "#101013" }),
787
+ /* @__PURE__ */ jsx(Text, { style: styles.loadMoreBtnLabel, children: "Load more" })
788
+ ] }) }) }), renderItem: ({
789
+ item: pair
790
+ }) => /* @__PURE__ */ jsxs(View, { style: styles.templateRow, children: [
791
+ pair.map((row) => /* @__PURE__ */ jsx(TemplateCatalogCard, { row, generating: aiBusy, using: usingTemplateId === row.id, onGenerate: (item) => generateAiScene(item.prompt, {
792
+ stayOnTemplates: true,
793
+ aspect: item.aspect
794
+ }), onPreview: previewStudioTemplate, onUse: (item) => void useStudioTemplate(item) }, row.id)),
795
+ pair.length < templateCols ? /* @__PURE__ */ jsx(View, { style: {
796
+ flex: 1
797
+ } }) : null
798
+ ] }) }) }) : /* @__PURE__ */ jsx(ScrollView, { style: styles.sidePaneScroll, contentContainerStyle: styles.sidePaneInner, keyboardShouldPersistTaps: "always", children: /* @__PURE__ */ jsx(View, { style: styles.panel, children: recordOpen ? /* @__PURE__ */ jsxs(View, { style: styles.recordPane, children: [
799
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Web records the screen, a window, or the camera, then drops the take on the timeline. On the phone that is camera, mic, or the library \u2014 screen capture stays on desktop." }),
800
+ recordError ? /* @__PURE__ */ jsx(Text, { style: styles.recordError, children: recordError }) : null,
801
+ [{
802
+ id: "camera-video",
803
+ icon: "video-outline",
804
+ label: "Record video",
805
+ hint: "Rear camera, up to 2 minutes"
806
+ }, {
807
+ id: "camera-photo",
808
+ icon: "camera-outline",
809
+ label: "Take photo",
810
+ hint: "Still lands as a scene"
811
+ }, {
812
+ id: "library",
813
+ icon: "image-multiple-outline",
814
+ label: "Photo Library",
815
+ hint: "Same as Open Media"
816
+ }, {
817
+ id: "file",
818
+ icon: "folder-outline",
819
+ label: "Choose file",
820
+ hint: "Video, image, or audio"
821
+ }].map((row) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => captureFromRecord(row.id), disabled: recordOn || !onPickLocalMedia, style: [styles.recordRow, (recordOn || !onPickLocalMedia) && styles.disabled], accessibilityRole: "button", children: [
822
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: row.icon, size: 22, color: "#F2F2F5" }),
823
+ /* @__PURE__ */ jsxs(View, { style: styles.segmentMenuCopy, children: [
824
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuLabel, children: row.label }),
825
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuHint, children: row.hint })
826
+ ] })
827
+ ] }, row.id)),
828
+ /* @__PURE__ */ jsxs(Pressable, { onPress: toggleMicTake, disabled: !audioRecorder, style: [styles.recordRow, !audioRecorder && styles.disabled], accessibilityRole: "button", children: [
829
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: micTakeOn ? "stop-circle-outline" : "microphone-outline", size: 22, color: micTakeOn ? "#F87171" : "#F2F2F5" }),
830
+ /* @__PURE__ */ jsxs(View, { style: styles.segmentMenuCopy, children: [
831
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuLabel, children: micTakeOn ? "Stop voice take" : "Record voice" }),
832
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuHint, children: audioRecorder ? "Adds a voiceover on the Audio lane" : "Host microphone is not wired in this build" })
833
+ ] })
834
+ ] })
835
+ ] }) : railTab === "media" ? /* @__PURE__ */ jsxs(View, { style: styles.mediaPane, children: [
836
+ onPickLocalMedia ? /* @__PURE__ */ jsx(View, { style: styles.pickRow, children: [{
837
+ id: "library",
838
+ icon: "image-multiple-outline",
839
+ label: "Photos"
840
+ }, {
841
+ id: "camera",
842
+ icon: "camera-outline",
843
+ label: "Camera"
844
+ }, {
845
+ id: "file",
846
+ icon: "folder-outline",
847
+ label: "Files"
848
+ }].map((source) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => pickIntoLibrary(source.id), disabled: mediaBusy, style: [styles.pickBtn, mediaBusy && styles.disabled], accessibilityRole: "button", accessibilityLabel: `Upload from ${source.label}`, children: [
849
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: source.icon, size: 18, color: "#E8E8EE" }),
850
+ /* @__PURE__ */ jsx(Text, { style: styles.pickBtnLabel, children: source.label })
851
+ ] }, source.id)) }) : null,
852
+ media.length === 0 ? /* @__PURE__ */ jsxs(View, { style: styles.emptyPanel, children: [
853
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "image-plus", size: 22, color: "#6A6A74" }),
854
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyTitle, children: "No media yet" }),
855
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyDetail, children: "Upload from this phone, or tap a clip from this canvas to add it to the timeline." })
856
+ ] }) : /* @__PURE__ */ jsx(View, { style: styles.mediaGrid, children: media.map((item) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
857
+ if (item.type === "audio") {
858
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
859
+ soundtrack: {
860
+ audioUrl: item.src,
861
+ mode: "mix",
862
+ title: item.generatedAssetName || "Audio"
863
+ }
864
+ }));
865
+ setRailTab("music");
866
+ setTab("music");
867
+ return;
868
+ }
869
+ addClip(item);
870
+ }, style: styles.mediaTile, children: [
871
+ item.type === "image" ? /* @__PURE__ */ jsx(Image, { source: {
872
+ uri: item.src
873
+ }, style: styles.mediaThumb, contentFit: "cover" }) : /* @__PURE__ */ jsx(View, { style: [styles.mediaThumb, styles.mediaThumbVideo], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: item.type === "audio" ? "music" : "play", size: 18, color: "#9A9AA5" }) }),
874
+ /* @__PURE__ */ jsx(View, { style: styles.mediaAdd, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 12, color: "#0A0A0C" }) })
875
+ ] }, item.id)) })
876
+ ] }) : railTab === "projects" ? /* @__PURE__ */ jsxs(View, { style: styles.projectsPane, children: [
877
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "A project is a saved timeline. Create one, then add clips from Media." }),
878
+ /* @__PURE__ */ jsxs(Pressable, { onPress: startNewProject, style: styles.solidBtn, accessibilityRole: "button", accessibilityLabel: "New project", children: [
879
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 16, color: "#101013" }),
880
+ /* @__PURE__ */ jsx(Text, { style: styles.solidBtnLabel, children: "Create project" })
881
+ ] }),
882
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: dirty ? "Unsaved changes \u2014 saves as soon as you edit." : projectHasWork(timeline) ? "All changes saved" : "Saves as soon as you edit." }),
883
+ projectList.map((row) => {
884
+ const current = row.id === "__current__" || row.id === activeProjectId;
885
+ const clips = row.timeline.clips.length;
886
+ const isDraft = row.id === "__current__";
887
+ return /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
888
+ if (isDraft) return;
889
+ openSavedProject(row);
890
+ }, style: [styles.projectRow, current && styles.projectRowOn], children: [
891
+ renameId === row.id ? /* @__PURE__ */ jsx(TextInput, { value: renameDraft, onChangeText: setRenameDraft, onSubmitEditing: () => {
892
+ const title = renameDraft.trim() || "Untitled project";
893
+ const next = upsertVideoProject(projectRows, __spreadProps(__spreadValues({}, row), {
894
+ title
895
+ }));
896
+ persistVideoProjects(next);
897
+ setProjectRows(next);
898
+ if (row.id === activeProjectId) setLocalTitle(title);
899
+ setRenameId(null);
900
+ }, autoFocus: true, style: styles.renameInput }) : /* @__PURE__ */ jsxs(View, { style: styles.projectRowCopy, children: [
901
+ /* @__PURE__ */ jsx(Text, { style: styles.projectRowTitle, numberOfLines: 1, children: row.title }),
902
+ /* @__PURE__ */ jsxs(Text, { style: styles.projectRowMeta, children: [
903
+ clips,
904
+ " clip",
905
+ clips === 1 ? "" : "s",
906
+ " \xB7",
907
+ " ",
908
+ relativeProjectTime(row.updatedAt)
909
+ ] })
910
+ ] }),
911
+ !isDraft ? /* @__PURE__ */ jsxs(Fragment, { children: [
912
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => {
913
+ setRenameId(row.id);
914
+ setRenameDraft(row.title);
915
+ }, hitSlop: 8, accessibilityLabel: "Rename project", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "pencil-outline", size: 16, color: "#8B8B96" }) }),
916
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => deleteSavedProject(row.id), hitSlop: 8, accessibilityLabel: "Delete project", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "trash-can-outline", size: 16, color: "#FF6B6B" }) })
917
+ ] }) : /* @__PURE__ */ jsx(Text, { style: styles.projectRowMeta, children: "Current" })
918
+ ] }, row.id);
919
+ })
920
+ ] }) : tab === "ai" ? /* @__PURE__ */ jsxs(View, { children: [
921
+ /* @__PURE__ */ jsx(Text, { style: styles.panelBarTitle, children: "Create with AI" }),
922
+ /* @__PURE__ */ jsx(TextInput, { value: aiPrompt, onChangeText: setAiPrompt, placeholder: "Continue the scene\u2026", placeholderTextColor: "#5A5A66", style: styles.textInput, multiline: true }),
923
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => generateAiScene(), disabled: aiBusy || !aiPrompt.trim(), style: [styles.chip, styles.chipActive, styles.chipWide], children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: aiBusy ? "Generating\u2026" : "Generate scene" }) })
924
+ ] }) : railTab === "elements" ? /* @__PURE__ */ jsxs(View, { children: [
925
+ /* @__PURE__ */ jsx(Text, { style: styles.panelBarTitle, children: "Blank scene" }),
926
+ /* @__PURE__ */ jsx(View, { style: styles.panelRow, children: SCENE_COLORS.map((color) => /* @__PURE__ */ jsx(Pressable, { onPress: () => {
927
+ const clip = clipFromColor(color);
928
+ setDirty(true);
929
+ setTimeline((t) => __spreadProps(__spreadValues({}, t), {
930
+ clips: [...t.clips, clip]
931
+ }));
932
+ setSelectedClipId(clip.id);
933
+ setNotice("Blank scene added");
934
+ }, style: [styles.sceneSwatch, {
935
+ backgroundColor: color
936
+ }], accessibilityRole: "button", accessibilityLabel: `Add blank scene ${color}` }, color)) }),
937
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Adds a colored still at the end of the timeline \u2014 hold duration in clip tools." })
938
+ ] }) : railTab === "logo" ? /* @__PURE__ */ jsxs(View, { children: [
939
+ logoSrc ? /* @__PURE__ */ jsx(Image, { source: {
940
+ uri: logoSrc
941
+ }, style: styles.logoPreview, contentFit: "contain" }) : /* @__PURE__ */ jsx(Text, { style: styles.panelEmpty, children: "A brand mark that rides every frame and exports with the video." }),
942
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
943
+ /* @__PURE__ */ jsx(Pressable, { onPress: pickLogo, disabled: mediaBusy, style: [styles.chip, styles.chipActive, mediaBusy && styles.disabled], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: logoSrc ? "Replace logo" : "Upload logo" }) }),
944
+ logoSrc ? /* @__PURE__ */ jsx(Pressable, { onPress: () => setLogoSrc(null), style: styles.chip, children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipDanger], children: "Remove" }) }) : null
945
+ ] })
946
+ ] }) : tab === "trim" ? selected ? /* @__PURE__ */ jsx(TrimPanel, { clip: selected, sourceSec: selectedSource, onTrim: (start, end) => patchSelected(trimClip(selected, start, end)), onImageDuration: (sec) => patchSelected({
947
+ durationSec: sec
948
+ }), onMove: (dir) => setTimeline((t) => moveClip(t, selected.id, dir)), onRemove: () => {
949
+ setTimeline((t) => removeClip(t, selected.id));
950
+ setSelectedClipId(null);
951
+ }, canMoveLeft: selectedIndex > 0, canMoveRight: selectedIndex >= 0 && selectedIndex < timeline.clips.length - 1 }) : /* @__PURE__ */ jsx(Text, { style: styles.panelEmpty, children: "Pick a clip on the timeline to change its timing, trim, motion, look and audio." }) : tab === "filter" && selected ? /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.panelRow, children: FILTER_PRESETS.map((preset) => {
952
+ const active = selected.filter === preset.id;
953
+ return /* @__PURE__ */ jsxs(Pressable, { onPress: () => patchSelected({
954
+ filter: preset.id
955
+ }), style: styles.filterTile, accessibilityRole: "button", accessibilityState: {
956
+ selected: active
957
+ }, children: [
958
+ /* @__PURE__ */ jsxs(View, { style: [styles.filterThumb, active && styles.filterThumbActive], children: [
959
+ selected.type === "image" ? /* @__PURE__ */ jsx(Image, { source: {
960
+ uri: selected.src
961
+ }, style: StyleSheet.absoluteFill, contentFit: "cover" }) : /* @__PURE__ */ jsx(View, { style: [StyleSheet.absoluteFill, styles.mediaThumbVideo] }),
962
+ preset.overlays.map(([color, opacity]) => /* @__PURE__ */ jsx(View, { style: [StyleSheet.absoluteFill, {
963
+ backgroundColor: color,
964
+ opacity
965
+ }] }, `${color}-${opacity}`)),
966
+ preset.id === "none" ? /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "cancel", size: 18, color: "#9A9AA5", style: styles.filterNoneGlyph }) : null
967
+ ] }),
968
+ /* @__PURE__ */ jsx(Text, { style: [styles.filterLabel, active && styles.filterLabelActive], children: preset.label })
969
+ ] }, preset.id);
970
+ }) }) : tab === "speed" && selected ? /* @__PURE__ */ jsxs(View, { children: [
971
+ /* @__PURE__ */ jsx(View, { style: styles.panelRow, children: SPEED_PRESETS.map((speed) => {
972
+ const active = selected.speed === speed;
973
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => patchSelected({
974
+ speed
975
+ }), style: [styles.chip, active && styles.chipActive], accessibilityRole: "button", accessibilityState: {
976
+ selected: active
977
+ }, children: /* @__PURE__ */ jsxs(Text, { style: [styles.chipLabel, active && styles.chipLabelActive], children: [
978
+ speed,
979
+ "\xD7"
980
+ ] }) }, speed);
981
+ }) }),
982
+ /* @__PURE__ */ jsx(View, { style: styles.panelRow, children: SPEED_CURVES.map((curve) => {
983
+ const active = selected.speedCurve === curve;
984
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => patchSelected({
985
+ speedCurve: curve
986
+ }), style: [styles.chip, active && styles.chipActive], accessibilityRole: "button", accessibilityState: {
987
+ selected: active
988
+ }, children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, active && styles.chipLabelActive], children: SPEED_CURVE_LABEL[curve] }) }, curve);
989
+ }) }),
990
+ selected.speedCurve !== "constant" ? /* @__PURE__ */ jsxs(Text, { style: styles.panelHint, children: [
991
+ "Curves render on export; preview plays ",
992
+ selected.speed,
993
+ "\xD7."
994
+ ] }) : null
995
+ ] }) : railTab === "text" ? /* @__PURE__ */ jsxs(View, { children: [
996
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.panelRow, children: TEXT_PRESETS.map((preset) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => addText({
997
+ text: preset.text,
998
+ x: preset.x,
999
+ y: preset.y
1000
+ }), style: styles.textPreset, accessibilityRole: "button", accessibilityLabel: `Add ${preset.label}`, children: [
1001
+ /* @__PURE__ */ jsx(Text, { style: styles.textPresetSample, numberOfLines: 1, children: preset.text }),
1002
+ /* @__PURE__ */ jsx(Text, { style: styles.textPresetLabel, children: preset.label })
1003
+ ] }, preset.id)) }),
1004
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Lands at the playhead. Tap the preview to edit, drag to place." }),
1005
+ selectedText ? /* @__PURE__ */ jsxs(Fragment, { children: [
1006
+ /* @__PURE__ */ jsx(TextInput, { value: selectedText.text, onChangeText: (text) => setTimeline((t) => updateText(t, selectedText.id, {
1007
+ text
1008
+ })), style: styles.textInput, placeholder: "Title", placeholderTextColor: "#5A5A66", selectionColor: "#8B7CFF", selectTextOnFocus: true, returnKeyType: "done", onSubmitEditing: dismissKeyboard }),
1009
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1010
+ /* @__PURE__ */ jsx(Stepper, { label: "Start", value: `${selectedText.startSec.toFixed(1)}s`, onLess: () => setTimeline((t) => updateText(t, selectedText.id, {
1011
+ startSec: Math.max(0, selectedText.startSec - 0.5)
1012
+ })), onMore: () => setTimeline((t) => updateText(t, selectedText.id, {
1013
+ startSec: selectedText.startSec + 0.5
1014
+ })) }),
1015
+ /* @__PURE__ */ jsx(Stepper, { label: "For", value: `${selectedText.durationSec.toFixed(1)}s`, onLess: () => setTimeline((t) => updateText(t, selectedText.id, {
1016
+ durationSec: Math.max(0.5, selectedText.durationSec - 0.5)
1017
+ })), onMore: () => setTimeline((t) => updateText(t, selectedText.id, {
1018
+ durationSec: selectedText.durationSec + 0.5
1019
+ })) }),
1020
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => {
1021
+ setTimeline((t) => removeText(t, selectedText.id));
1022
+ setSelectedTextId(null);
1023
+ }, style: styles.chip, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipDanger], children: "Remove" }) })
1024
+ ] })
1025
+ ] }) : null
1026
+ ] }) : railTab === "music" ? /* @__PURE__ */ jsx(SoundtrackPanel, { runAction, soundtrack: (_h = timeline.soundtrack) != null ? _h : null, totalSec: total.knownSec, onSoundtrack: (soundtrack) => setTimeline((t) => __spreadProps(__spreadValues({}, t), {
1027
+ soundtrack
1028
+ })), onNotice: setNotice }) : railTab === "voiceover" ? /* @__PURE__ */ jsx(VoicePanel, { runAction, uploadMedia, audioRecorder, voiceover: (_i = timeline.voiceover) != null ? _i : null, selectedClip: selected, onVoiceover: (voiceover) => setTimeline((t) => __spreadProps(__spreadValues({}, t), {
1029
+ voiceover
1030
+ })), onNotice: setNotice }) : railTab === "agent" ? /* @__PURE__ */ jsx(AgentCutPane, { timeline, setTimeline, token, indexUrl }) : railTab === "captions" ? /* @__PURE__ */ jsxs(View, { children: [
1031
+ /* @__PURE__ */ jsx(Text, { style: styles.panelBarTitle, children: "Captions" }),
1032
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "One captions lane \u2014 add at the playhead, then tap a row to edit." }),
1033
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => {
1034
+ const preset = TEXT_PRESETS.find((p) => p.id === "caption");
1035
+ addText(preset ? {
1036
+ text: preset.text,
1037
+ x: preset.x,
1038
+ y: preset.y
1039
+ } : {
1040
+ text: "Caption",
1041
+ x: 0.5,
1042
+ y: 0.86
1043
+ });
1044
+ }, style: [styles.chip, styles.chipActive, styles.chipWide], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: "Add caption at playhead" }) }),
1045
+ timeline.texts.length === 0 ? /* @__PURE__ */ jsx(Text, { style: styles.panelEmpty, children: "No captions yet." }) : timeline.texts.map((row) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
1046
+ setSelectedTextId(row.id);
1047
+ setTab("text");
1048
+ }, style: styles.captionRow, children: [
1049
+ /* @__PURE__ */ jsx(Text, { style: styles.captionRowText, numberOfLines: 1, children: row.text || "Caption" }),
1050
+ /* @__PURE__ */ jsxs(Text, { style: styles.captionRowMeta, children: [
1051
+ row.startSec.toFixed(1),
1052
+ "s"
1053
+ ] })
1054
+ ] }, row.id))
1055
+ ] }) : railTab === "audio" ? /* @__PURE__ */ jsxs(View, { children: [
1056
+ /* @__PURE__ */ jsx(Text, { style: styles.panelBarTitle, children: "AI audio" }),
1057
+ /* @__PURE__ */ jsx(TextInput, { value: audioPrompt, onChangeText: setAudioPrompt, placeholder: "Music or narration prompt\u2026", placeholderTextColor: "#5A5A66", style: styles.textInput, multiline: true }),
1058
+ /* @__PURE__ */ jsx(Pressable, { onPress: generateAiAudio, disabled: audioBusy || !audioPrompt.trim(), style: [styles.chip, styles.chipActive, styles.chipWide], children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: audioBusy ? "Generating\u2026" : "Generate" }) }),
1059
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Lands in the media library \u2014 tap it there to add to the timeline. Mood music with auto-duck lives under Music." })
1060
+ ] }) : tab === "segment" ? /* @__PURE__ */ jsxs(View, { children: [
1061
+ /* @__PURE__ */ jsx(Text, { style: styles.panelBarTitle, children: "Segment" }),
1062
+ selectedSegmentId && ((_j = timeline.segments) != null ? _j : []).find((s) => s.id === selectedSegmentId) ? /* @__PURE__ */ jsxs(Text, { style: styles.panelEmpty, children: [
1063
+ (_l = ((_k = timeline.segments) != null ? _k : []).find((s) => s.id === selectedSegmentId)) == null ? void 0 : _l.name,
1064
+ " ",
1065
+ "\xB7 2s range at the playhead. Hide the segment lane to switch it off."
1066
+ ] }) : /* @__PURE__ */ jsx(Text, { style: styles.panelEmpty, children: "Speed, zoom, crop or trim a 2s range at the playhead." })
1067
+ ] }) : /* @__PURE__ */ jsx(Text, { style: styles.panelEmpty, children: "Pick a clip on the timeline to change its timing, trim, motion, look and audio." }) }) })
1068
+ ] }) : null,
1069
+ /* @__PURE__ */ jsxs(View, { style: styles.stageCol, children: [
1070
+ /* @__PURE__ */ jsx(View, { style: styles.stageWell, onTouchStart: dismissKeyboard, children: /* @__PURE__ */ jsx(View, { style: styles.stage, children: selected === null ? /* @__PURE__ */ jsxs(View, { style: styles.stageEmptyCopy, children: [
1071
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "filmstrip-box-multiple", size: 32, color: "#6A6A74" }),
1072
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyTitle, children: "Start a scene" }),
1073
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyDetail, children: "Drop in a photo, a camera take, or a blank card \u2014 the same doors as the web studio." }),
1074
+ /* @__PURE__ */ jsxs(View, { style: styles.stageEmptyActions, children: [
1075
+ /* @__PURE__ */ jsxs(Pressable, { onPress: addBlankScene, style: styles.solidBtn, accessibilityRole: "button", accessibilityLabel: "Add blank scene", children: [
1076
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 16, color: "#101013" }),
1077
+ /* @__PURE__ */ jsx(Text, { style: styles.solidBtnLabel, children: "Blank scene" })
1078
+ ] }),
1079
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
1080
+ setRailTab("media");
1081
+ setTab("media");
1082
+ }, style: styles.ghostBtn, accessibilityRole: "button", children: [
1083
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "image-plus", size: 16, color: "#F2F2F5" }),
1084
+ /* @__PURE__ */ jsx(Text, { style: styles.ghostBtnLabel, children: "Open Media" })
1085
+ ] })
1086
+ ] })
1087
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1088
+ selected.type === "video" && VideoPreview ? /* @__PURE__ */ jsx(VideoPreview, { src: selected.src, playing, rate: selected.speed, volume: selected.volume, muted: selected.muted, trimStartSec: selected.trimStartSec, trimEndSec: selected.trimEndSec, scrubToSec: scrub.sec, scrubNonce: scrub.nonce, onTime: onPreviewTime }) : selected.type === "video" ? /* @__PURE__ */ jsxs(View, { style: styles.stageEmpty, children: [
1089
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "play-circle-outline", size: 40, color: "#4A4A55" }),
1090
+ /* @__PURE__ */ jsx(Text, { style: styles.stageEmptyDetail, children: "Video preview needs the host's player - editing still works." })
1091
+ ] }) : /* @__PURE__ */ jsx(Image, { source: {
1092
+ uri: selected.src
1093
+ }, style: StyleSheet.absoluteFill, contentFit: "contain" }),
1094
+ selectedFilter.overlays.map(([color, opacity]) => /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: [StyleSheet.absoluteFill, {
1095
+ backgroundColor: color,
1096
+ opacity
1097
+ }] }, `${color}-${opacity}`)),
1098
+ timeline.texts.map((t) => /* @__PURE__ */ jsx(DraggableText, { text: t.text, x: t.x, y: t.y, active: t.id === selectedTextId, onSelect: () => {
1099
+ setSelectedTextId(t.id);
1100
+ setTab("text");
1101
+ }, onMove: (x, y) => setTimeline((tl) => updateText(tl, t.id, {
1102
+ x,
1103
+ y
1104
+ })) }, t.id)),
1105
+ logoSrc ? /* @__PURE__ */ jsx(Image, { source: {
1106
+ uri: logoSrc
1107
+ }, style: styles.logoOverlay, contentFit: "contain", pointerEvents: "none" }) : null,
1108
+ /* @__PURE__ */ jsxs(View, { style: styles.stageToolbar, children: [
1109
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setStageTool((t) => t === "animate" ? null : "animate"), style: [styles.stagePill, selected.kenBurns && styles.stagePillOn], children: /* @__PURE__ */ jsx(Text, { style: styles.stagePillLabel, children: "Animate" }) }),
1110
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setStageTool((t) => t === "look" ? null : "look"), style: [styles.stagePill, selected.filter !== "none" && styles.stagePillOn], children: /* @__PURE__ */ jsx(Text, { style: styles.stagePillLabel, children: "Look" }) }),
1111
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setStageTool((t) => t === "transition" ? null : "transition"), style: [styles.stagePill, selected.transitionIn && styles.stagePillOn], children: /* @__PURE__ */ jsx(Text, { style: styles.stagePillLabel, children: "Transition" }) })
1112
+ ] })
1113
+ ] }) }) }),
1114
+ selected && stageTool ? /* @__PURE__ */ jsxs(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.stageToolRow, children: [
1115
+ stageTool === "animate" ? MOTION_MOVES.map((m) => {
1116
+ const on = moveIdOf(selected.kenBurns) === m.id;
1117
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => {
1118
+ var _a2, _b2, _c2, _d2;
1119
+ return patchSelected({
1120
+ kenBurns: kenBurnsFor(m.id, Math.max((_b2 = (_a2 = selected.kenBurns) == null ? void 0 : _a2.zoomStart) != null ? _b2 : 1.3, (_d2 = (_c2 = selected.kenBurns) == null ? void 0 : _c2.zoomEnd) != null ? _d2 : 1.3))
1121
+ });
1122
+ }, style: [styles.chip, on && styles.chipActive], children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, on && styles.chipLabelActive], children: m.label }) }, m.id);
1123
+ }) : null,
1124
+ stageTool === "animate" && selected.kenBurns ? MOTION_STRENGTHS.map((s) => /* @__PURE__ */ jsx(Pressable, { onPress: () => patchSelected({
1125
+ kenBurns: kenBurnsFor(moveIdOf(selected.kenBurns), s.zoom)
1126
+ }), style: styles.chip, children: /* @__PURE__ */ jsx(Text, { style: styles.chipLabel, children: s.label }) }, s.id)) : null,
1127
+ stageTool === "look" ? FILTER_PRESETS.map((preset) => {
1128
+ const on = selected.filter === preset.id;
1129
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => patchSelected({
1130
+ filter: preset.id
1131
+ }), style: [styles.chip, on && styles.chipActive], children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, on && styles.chipLabelActive], children: preset.label }) }, preset.id);
1132
+ }) : null,
1133
+ stageTool === "transition" ? CLIP_TRANSITIONS.map((fx) => {
1134
+ var _a2;
1135
+ const on = ((_a2 = selected.transitionIn) == null ? void 0 : _a2.effect) === fx;
1136
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => patchSelected({
1137
+ transitionIn: on ? null : {
1138
+ effect: fx,
1139
+ durationMs: 1e3
1140
+ }
1141
+ }), style: [styles.chip, on && styles.chipActive], children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, on && styles.chipLabelActive], children: fx }) }, fx);
1142
+ }) : null
1143
+ ] }) : null,
1144
+ /* @__PURE__ */ jsx(TimelineTrack, { timeline, selectedClipId, selectedTextId, selectedSegmentId, segmentMenuOpen, playing, playhead, totalSec: total.knownSec, onTogglePlay: previewPlay, onSkipStart: () => {
1145
+ setPlaying(false);
1146
+ setPlayhead(0);
1147
+ setScrub((s) => ({
1148
+ sec: 0,
1149
+ nonce: s.nonce + 1
1150
+ }));
1151
+ }, onSkipEnd: () => {
1152
+ setPlaying(false);
1153
+ setPlayhead(total.knownSec);
1154
+ setScrub((s) => ({
1155
+ sec: total.knownSec,
1156
+ nonce: s.nonce + 1
1157
+ }));
1158
+ }, onToggleSegmentMenu: () => setSegmentMenuOpen((v) => !v), onAddSegment: dropSegment, onSelectSegment: (id) => {
1159
+ setSelectedSegmentId(id);
1160
+ setTab("segment");
1161
+ }, compact: timeline.clips.length === 0, onAddScene: addBlankScene, onLayers: () => {
1162
+ setRailTab("elements");
1163
+ setTab("elements");
1164
+ }, onSelectClip: (id) => {
1165
+ setSelectedClipId(id);
1166
+ setPlaying(false);
1167
+ setStageTool(null);
1168
+ setRailTab(null);
1169
+ }, onSelectText: (id) => {
1170
+ setSelectedTextId(id);
1171
+ setRailTab("text");
1172
+ setTab("text");
1173
+ } }),
1174
+ selected && !railTab ? /* @__PURE__ */ jsxs(View, { style: styles.clipInspector, children: [
1175
+ /* @__PURE__ */ jsx(Text, { style: styles.clipInspectorTitle, numberOfLines: 1, children: selected.name }),
1176
+ /* @__PURE__ */ jsx(TrimPanel, { clip: selected, sourceSec: selectedSource, onTrim: (start, end) => patchSelected(trimClip(selected, start, end)), onImageDuration: (sec) => patchSelected({
1177
+ durationSec: sec
1178
+ }), onMove: (dir) => setTimeline((t) => moveClip(t, selected.id, dir)), onRemove: () => {
1179
+ setTimeline((t) => removeClip(t, selected.id));
1180
+ setSelectedClipId(null);
1181
+ }, canMoveLeft: selectedIndex > 0, canMoveRight: selectedIndex >= 0 && selectedIndex < timeline.clips.length - 1 })
1182
+ ] }) : null
1183
+ ] }),
1184
+ /* @__PURE__ */ jsxs(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.dock, contentContainerStyle: [styles.dockInner, {
1185
+ paddingBottom: Math.max(insets.bottom, 8)
1186
+ }], keyboardShouldPersistTaps: "handled", children: [
1187
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
1188
+ setRailTab(null);
1189
+ setRecordError(null);
1190
+ setRecordOpen((open) => !open);
1191
+ }, style: [styles.dockTab, styles.dockRecord, recordOpen && styles.dockRecordOn], accessibilityRole: "button", accessibilityLabel: "Record", accessibilityState: {
1192
+ selected: recordOpen
1193
+ }, children: [
1194
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "record-circle", size: 22, color: recordOpen || recordOn ? "#F87171" : "#8B8B96" }),
1195
+ /* @__PURE__ */ jsx(Text, { style: [styles.dockLabel, recordOpen && styles.dockRecordLabel], children: "Record" })
1196
+ ] }),
1197
+ /* @__PURE__ */ jsx(View, { style: styles.dockRule }),
1198
+ TABS.map((entry) => {
1199
+ const active = railTab === entry.id;
1200
+ return /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
1201
+ setRecordOpen(false);
1202
+ setRailTab((cur) => cur === entry.id ? null : entry.id);
1203
+ setTab(entry.id);
1204
+ }, style: [styles.dockTab, active && styles.dockTabOn], accessibilityRole: "tab", accessibilityState: {
1205
+ selected: active
1206
+ }, accessibilityLabel: entry.label, children: [
1207
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: entry.icon, size: 20, color: active ? "#F2F2F5" : "#8B8B96" }),
1208
+ /* @__PURE__ */ jsx(Text, { style: [styles.dockLabel, active && styles.dockLabelOn], children: entry.label })
1209
+ ] }, entry.id);
1210
+ })
1211
+ ] }),
1212
+ templatePreview ? /* @__PURE__ */ jsxs(View, { style: styles.templatePreviewOverlay, children: [
1213
+ /* @__PURE__ */ jsxs(View, { style: styles.templatePreviewBar, children: [
1214
+ /* @__PURE__ */ jsx(Text, { style: styles.templatePreviewKicker, children: "Template preview" }),
1215
+ /* @__PURE__ */ jsx(Text, { style: styles.templatePreviewBarTitle, numberOfLines: 1, children: templatePreview.title }),
1216
+ templatePreview.aspect ? /* @__PURE__ */ jsx(Text, { style: styles.templatePreviewAspect, children: templatePreview.aspect }) : null,
1217
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setTemplatePreview(null), hitSlop: 8, accessibilityRole: "button", accessibilityLabel: "Close template preview", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 18, color: "#F2F2F5" }) })
1218
+ ] }),
1219
+ /* @__PURE__ */ jsx(Text, { style: styles.templatePreviewHint, children: "Not part of your video \u2014 Generate adds a fresh clip" }),
1220
+ /* @__PURE__ */ jsx(View, { style: styles.templatePreviewMedia, children: templatePreview.kind === "video" ? /* @__PURE__ */ jsx(TemplateWebPreview, { src: templatePreview.src, poster: templatePreview.poster }) : /* @__PURE__ */ jsx(Image, { source: {
1221
+ uri: templatePreview.poster || templatePreview.src
1222
+ }, style: styles.templatePreviewImage, contentFit: "contain", recyclingKey: templatePreview.src }) })
1223
+ ] }) : null
1224
+ ] }),
1225
+ notice ? /* @__PURE__ */ jsxs(View, { style: styles.notice, children: [
1226
+ /* @__PURE__ */ jsx(Text, { style: styles.noticeText, children: notice }),
1227
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setNotice(null), hitSlop: 8, children: /* @__PURE__ */ jsx(Text, { style: styles.noticeDismiss, children: "OK" }) })
1228
+ ] }) : null,
1229
+ mediaBusy || aiBusy ? /* @__PURE__ */ jsx(View, { style: styles.busyOverlay, pointerEvents: "auto", children: /* @__PURE__ */ jsxs(View, { style: styles.busyCard, children: [
1230
+ /* @__PURE__ */ jsx(ActivityIndicator, { color: "#F7F7FA" }),
1231
+ /* @__PURE__ */ jsx(Text, { style: styles.busyTitle, children: aiBusy ? "Generating scene" : mediaBusy ? "Uploading" : "Working" }),
1232
+ /* @__PURE__ */ jsx(Text, { style: styles.busyDetail, children: aiBusy ? "This can take a minute. Keep the editor open." : uploadStatus || "Preparing your media\u2026" }),
1233
+ mediaBusy ? /* @__PURE__ */ jsx(View, { style: styles.busyTrack, children: /* @__PURE__ */ jsx(View, { style: styles.busyTrackFill }) }) : null
1234
+ ] }) }) : null,
1235
+ /* @__PURE__ */ jsx(KeyboardLiftSpacer, {})
1236
+ ] }) });
1237
+ }
1238
+ function formatSec(sec) {
1239
+ const m = Math.floor(sec / 60);
1240
+ const s = sec - m * 60;
1241
+ return `${m}:${s.toFixed(1).padStart(4, "0")}`;
1242
+ }
1243
+ function DraggableText({
1244
+ text,
1245
+ x,
1246
+ y,
1247
+ active,
1248
+ onSelect,
1249
+ onMove
1250
+ }) {
1251
+ const stage = useRef({
1252
+ w: 1,
1253
+ h: 1
1254
+ });
1255
+ const start = useRef({
1256
+ x,
1257
+ y
1258
+ });
1259
+ const pan = Gesture.Pan().runOnJS(true).onStart(() => {
1260
+ start.current = {
1261
+ x,
1262
+ y
1263
+ };
1264
+ onSelect();
1265
+ }).onUpdate((e) => {
1266
+ onMove(Math.min(1, Math.max(0, start.current.x + e.translationX / stage.current.w)), Math.min(1, Math.max(0, start.current.y + e.translationY / stage.current.h)));
1267
+ });
1268
+ const tap = Gesture.Tap().runOnJS(true).onEnd(onSelect);
1269
+ return /* @__PURE__ */ jsx(View, { style: StyleSheet.absoluteFill, pointerEvents: "box-none", onLayout: (e) => {
1270
+ stage.current = {
1271
+ w: Math.max(1, e.nativeEvent.layout.width),
1272
+ h: Math.max(1, e.nativeEvent.layout.height)
1273
+ };
1274
+ }, children: /* @__PURE__ */ jsx(GestureDetector, { gesture: Gesture.Race(pan, tap), children: /* @__PURE__ */ jsx(View, { style: [styles.stageText, active && styles.stageTextActive, {
1275
+ left: `${x * 100}%`,
1276
+ top: `${y * 100}%`
1277
+ }], children: /* @__PURE__ */ jsx(Text, { style: styles.stageTextLabel, children: text }) }) }) });
1278
+ }
1279
+ function TimelineTrack({
1280
+ timeline,
1281
+ selectedClipId,
1282
+ selectedTextId,
1283
+ selectedSegmentId,
1284
+ segmentMenuOpen,
1285
+ compact,
1286
+ onToggleSegmentMenu,
1287
+ onAddSegment,
1288
+ onSelectSegment,
1289
+ onAddScene,
1290
+ onLayers,
1291
+ onSelectClip,
1292
+ onSelectText,
1293
+ playing,
1294
+ playhead,
1295
+ totalSec,
1296
+ onTogglePlay,
1297
+ onSkipStart,
1298
+ onSkipEnd
1299
+ }) {
1300
+ var _a;
1301
+ const segments = (_a = timeline.segments) != null ? _a : [];
1302
+ const hasAudio = Boolean(timeline.voiceover || timeline.soundtrack);
1303
+ return /* @__PURE__ */ jsxs(View, { style: [styles.timeline, compact && styles.timelineCompact], children: [
1304
+ /* @__PURE__ */ jsxs(View, { style: styles.timelineBar, children: [
1305
+ /* @__PURE__ */ jsx(Pressable, { onPress: onLayers, hitSlop: 6, style: styles.timelineIconBtn, accessibilityRole: "button", accessibilityLabel: "Open layers", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "layers-outline", size: 20, color: "#F2F2F5" }) }),
1306
+ /* @__PURE__ */ jsx(View, { style: styles.timelineRule }),
1307
+ /* @__PURE__ */ jsx(Pressable, { onPress: onAddScene, hitSlop: 6, style: styles.timelineIconBtn, accessibilityRole: "button", accessibilityLabel: "Add blank scene", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 22, color: "#F2F2F5" }) }),
1308
+ /* @__PURE__ */ jsx(Pressable, { onPress: onToggleSegmentMenu, hitSlop: 6, style: [styles.timelineIconBtn, segmentMenuOpen && styles.dockTabOn], accessibilityRole: "button", accessibilityLabel: "Add segment (speed, zoom, crop, trim)", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "arrow-split-horizontal", size: 20, color: "#F2F2F5" }) }),
1309
+ /* @__PURE__ */ jsx(View, { style: styles.headerSpacer }),
1310
+ /* @__PURE__ */ jsx(Pressable, { onPress: onSkipStart, hitSlop: 8, style: styles.transportBtn, accessibilityLabel: "Skip to start", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "skip-previous", size: 24, color: "#F2F2F5" }) }),
1311
+ /* @__PURE__ */ jsx(Pressable, { onPress: onTogglePlay, style: styles.transportPlay, accessibilityLabel: playing ? "Pause" : "Play", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: playing ? "pause" : "play", size: 26, color: "#101013" }) }),
1312
+ /* @__PURE__ */ jsx(Pressable, { onPress: onSkipEnd, hitSlop: 8, style: styles.transportBtn, accessibilityLabel: "Skip to end", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "skip-next", size: 24, color: "#F2F2F5" }) }),
1313
+ /* @__PURE__ */ jsxs(Text, { style: styles.transportTime, children: [
1314
+ formatSec(playhead),
1315
+ /* @__PURE__ */ jsxs(Text, { style: styles.transportTimeDim, children: [
1316
+ " / ",
1317
+ formatSec(totalSec)
1318
+ ] })
1319
+ ] })
1320
+ ] }),
1321
+ segmentMenuOpen ? /* @__PURE__ */ jsxs(View, { style: styles.segmentMenu, children: [
1322
+ SEGMENT_KINDS.map((entry) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => onAddSegment(entry.kind), style: styles.segmentMenuRow, accessibilityRole: "button", accessibilityLabel: entry.label, children: [
1323
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: entry.icon, size: 16, color: "#A9A9B4" }),
1324
+ /* @__PURE__ */ jsxs(View, { style: styles.segmentMenuCopy, children: [
1325
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuLabel, children: entry.label }),
1326
+ /* @__PURE__ */ jsx(Text, { style: styles.segmentMenuHint, children: entry.hint })
1327
+ ] })
1328
+ ] }, entry.kind)),
1329
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Drops a 2s range at the playhead, across scenes. Playback and export honour it." })
1330
+ ] }) : null,
1331
+ /* @__PURE__ */ jsxs(ScrollView, { showsVerticalScrollIndicator: false, children: [
1332
+ /* @__PURE__ */ jsxs(View, { style: styles.laneRow, children: [
1333
+ /* @__PURE__ */ jsxs(View, { style: styles.laneGutter, children: [
1334
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "video", size: 14, color: "#8B8B96" }),
1335
+ /* @__PURE__ */ jsx(Text, { style: styles.laneLabel, children: "Video" })
1336
+ ] }),
1337
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.laneBody, children: /* @__PURE__ */ jsx(View, { style: styles.clipTrack, children: timeline.clips.length === 0 ? /* @__PURE__ */ jsxs(Pressable, { onPress: onAddScene, style: styles.clipTrackEmpty, accessibilityRole: "button", accessibilityLabel: "Add blank scene", children: [
1338
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 16, color: "#8B8B96" }),
1339
+ /* @__PURE__ */ jsx(Text, { style: styles.clipTrackEmptyLabel, children: "Blank scene" })
1340
+ ] }) : timeline.clips.map((clip, index) => {
1341
+ const active = clip.id === selectedClipId;
1342
+ const sec = clipTimelineSec(clip);
1343
+ return /* @__PURE__ */ jsxs(Pressable, { onPress: () => onSelectClip(clip.id), style: [styles.clipBlock, active && styles.clipBlockActive], children: [
1344
+ clip.type === "image" ? /* @__PURE__ */ jsx(Image, { source: {
1345
+ uri: clip.src
1346
+ }, style: StyleSheet.absoluteFill, contentFit: "cover" }) : /* @__PURE__ */ jsx(View, { style: [StyleSheet.absoluteFill, styles.mediaThumbVideo], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "play", size: 14, color: "#9A9AA5" }) }),
1347
+ /* @__PURE__ */ jsxs(View, { style: styles.clipMeta, children: [
1348
+ /* @__PURE__ */ jsx(Text, { style: styles.clipMetaText, children: index + 1 }),
1349
+ /* @__PURE__ */ jsxs(Text, { style: styles.clipMetaText, children: [
1350
+ sec === null ? "video" : `${Math.round(sec * 10) / 10}s`,
1351
+ clip.speed !== 1 ? ` \xB7 ${clip.speed}\xD7` : ""
1352
+ ] })
1353
+ ] })
1354
+ ] }, clip.id);
1355
+ }) }) })
1356
+ ] }),
1357
+ compact ? null : /* @__PURE__ */ jsxs(View, { style: styles.laneRow, children: [
1358
+ /* @__PURE__ */ jsxs(View, { style: styles.laneGutter, children: [
1359
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "image-outline", size: 14, color: "#9A9AA5" }),
1360
+ /* @__PURE__ */ jsx(Text, { style: styles.laneLabel, children: "Overlay" })
1361
+ ] }),
1362
+ /* @__PURE__ */ jsx(View, { style: styles.laneBody })
1363
+ ] }),
1364
+ compact && timeline.texts.length === 0 ? null : /* @__PURE__ */ jsxs(View, { style: styles.laneRow, children: [
1365
+ /* @__PURE__ */ jsxs(View, { style: styles.laneGutter, children: [
1366
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "format-title", size: 14, color: "#8B8B96" }),
1367
+ /* @__PURE__ */ jsx(Text, { style: styles.laneLabel, children: "Text" })
1368
+ ] }),
1369
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.laneBody, children: /* @__PURE__ */ jsx(View, { style: styles.textTrack, children: timeline.texts.map((t) => /* @__PURE__ */ jsxs(Pressable, { onPress: () => onSelectText(t.id), style: [styles.textPill, t.id === selectedTextId && styles.textPillActive], children: [
1370
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "format-text", size: 11, color: "#F7F7FA" }),
1371
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.textPillLabel, children: t.text })
1372
+ ] }, t.id)) }) })
1373
+ ] }),
1374
+ compact && !hasAudio ? null : /* @__PURE__ */ jsxs(View, { style: styles.laneRow, children: [
1375
+ /* @__PURE__ */ jsxs(View, { style: styles.laneGutter, children: [
1376
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "music-note", size: 14, color: "#9A9AA5" }),
1377
+ /* @__PURE__ */ jsx(Text, { style: styles.laneLabel, children: "Audio" })
1378
+ ] }),
1379
+ /* @__PURE__ */ jsxs(View, { style: styles.laneBody, children: [
1380
+ timeline.voiceover ? /* @__PURE__ */ jsxs(View, { style: styles.voTrack, children: [
1381
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "account-voice", size: 11, color: "#DCD6FF" }),
1382
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.voTrackLabel, children: timeline.voiceover.voiceLabel || "Voiceover" })
1383
+ ] }) : null,
1384
+ timeline.soundtrack ? /* @__PURE__ */ jsxs(View, { style: styles.voTrack, children: [
1385
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "music-note", size: 11, color: "#DCD6FF" }),
1386
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.voTrackLabel, children: timeline.soundtrack.title || "Soundtrack" })
1387
+ ] }) : null
1388
+ ] })
1389
+ ] }),
1390
+ compact && segments.length === 0 ? null : /* @__PURE__ */ jsxs(View, { style: styles.laneRow, children: [
1391
+ /* @__PURE__ */ jsxs(View, { style: styles.laneGutter, children: [
1392
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "arrow-split-horizontal", size: 14, color: "#8B8B96" }),
1393
+ /* @__PURE__ */ jsx(Text, { style: styles.laneLabel, children: "Segment" })
1394
+ ] }),
1395
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles.laneBody, children: /* @__PURE__ */ jsx(View, { style: styles.textTrack, children: segments.map((seg) => /* @__PURE__ */ jsx(Pressable, { onPress: () => onSelectSegment(seg.id), style: [styles.textPill, seg.id === selectedSegmentId && styles.textPillActive], children: /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.textPillLabel, children: seg.name }) }, seg.id)) }) })
1396
+ ] })
1397
+ ] })
1398
+ ] });
1399
+ }
1400
+ function TrimPanel({
1401
+ clip,
1402
+ sourceSec,
1403
+ onTrim,
1404
+ onImageDuration,
1405
+ onMove,
1406
+ onRemove,
1407
+ canMoveLeft,
1408
+ canMoveRight
1409
+ }) {
1410
+ var _a, _b;
1411
+ const [trackW, setTrackW] = useState(1);
1412
+ const source = sourceSec && sourceSec > 0 ? sourceSec : null;
1413
+ const end = (_a = clip.trimEndSec) != null ? _a : source;
1414
+ const pxPerSec = source ? trackW / source : 0;
1415
+ const dragStart = useRef(0);
1416
+ const startHandle = Gesture.Pan().runOnJS(true).onStart(() => {
1417
+ dragStart.current = clip.trimStartSec;
1418
+ }).onUpdate((e) => {
1419
+ if (!source) return;
1420
+ onTrim(Math.min(source, dragStart.current + e.translationX / pxPerSec), clip.trimEndSec);
1421
+ });
1422
+ const endHandle = Gesture.Pan().runOnJS(true).onStart(() => {
1423
+ dragStart.current = end != null ? end : 0;
1424
+ }).onUpdate((e) => {
1425
+ if (!source) return;
1426
+ onTrim(clip.trimStartSec, Math.min(source, Math.max(0.1, dragStart.current + e.translationX / pxPerSec)));
1427
+ });
1428
+ return /* @__PURE__ */ jsxs(View, { children: [
1429
+ clip.type === "image" ? /* @__PURE__ */ jsx(View, { style: styles.panelRow, children: /* @__PURE__ */ jsx(Stepper, { label: "Hold for", value: `${(_b = clip.durationSec) != null ? _b : DEFAULT_IMAGE_SEC}s`, onLess: () => {
1430
+ var _a2;
1431
+ return onImageDuration(Math.max(1, ((_a2 = clip.durationSec) != null ? _a2 : DEFAULT_IMAGE_SEC) - 1));
1432
+ }, onMore: () => {
1433
+ var _a2;
1434
+ return onImageDuration(Math.min(30, ((_a2 = clip.durationSec) != null ? _a2 : DEFAULT_IMAGE_SEC) + 1));
1435
+ } }) }) : source === null ? /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Play the clip once so its length is known, then trim." }) : /* @__PURE__ */ jsxs(View, { style: styles.trimTrack, onLayout: (e) => setTrackW(Math.max(1, e.nativeEvent.layout.width)), children: [
1436
+ /* @__PURE__ */ jsx(View, { style: [styles.trimWindow, {
1437
+ left: clip.trimStartSec * pxPerSec,
1438
+ width: Math.max(8, ((end != null ? end : source) - clip.trimStartSec) * pxPerSec)
1439
+ }] }),
1440
+ /* @__PURE__ */ jsx(GestureDetector, { gesture: startHandle, children: /* @__PURE__ */ jsx(View, { style: [styles.trimHandle, {
1441
+ left: clip.trimStartSec * pxPerSec - 10
1442
+ }], hitSlop: 12, children: /* @__PURE__ */ jsx(View, { style: styles.trimHandleBar }) }) }),
1443
+ /* @__PURE__ */ jsx(GestureDetector, { gesture: endHandle, children: /* @__PURE__ */ jsx(View, { style: [styles.trimHandle, {
1444
+ left: (end != null ? end : source) * pxPerSec - 10
1445
+ }], hitSlop: 12, children: /* @__PURE__ */ jsx(View, { style: styles.trimHandleBar }) }) }),
1446
+ /* @__PURE__ */ jsxs(Text, { style: styles.trimReadout, children: [
1447
+ clip.trimStartSec.toFixed(1),
1448
+ "s \u2013 ",
1449
+ (end != null ? end : source).toFixed(1),
1450
+ "s of ",
1451
+ source.toFixed(1),
1452
+ "s"
1453
+ ] })
1454
+ ] }),
1455
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1456
+ /* @__PURE__ */ jsx(IconChip, { icon: "arrow-left", disabled: !canMoveLeft, onPress: () => onMove(-1), label: "Move left" }),
1457
+ /* @__PURE__ */ jsx(IconChip, { icon: "arrow-right", disabled: !canMoveRight, onPress: () => onMove(1), label: "Move right" }),
1458
+ /* @__PURE__ */ jsxs(Pressable, { onPress: onRemove, style: styles.chip, accessibilityRole: "button", children: [
1459
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "trash-can-outline", size: 14, color: "#FF6B6B" }),
1460
+ /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipDanger], children: "Remove" })
1461
+ ] })
1462
+ ] })
1463
+ ] });
1464
+ }
1465
+ function IconChip({
1466
+ icon,
1467
+ label,
1468
+ disabled,
1469
+ onPress
1470
+ }) {
1471
+ return /* @__PURE__ */ jsx(Pressable, { onPress, disabled, style: [styles.chip, disabled && styles.chipDisabled], accessibilityRole: "button", accessibilityLabel: label, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: icon, size: 14, color: "#F7F7FA" }) });
1472
+ }
1473
+ function Stepper({
1474
+ label,
1475
+ value,
1476
+ onLess,
1477
+ onMore
1478
+ }) {
1479
+ return /* @__PURE__ */ jsxs(View, { style: styles.stepper, children: [
1480
+ /* @__PURE__ */ jsx(Text, { style: styles.stepperLabel, children: label }),
1481
+ /* @__PURE__ */ jsx(Pressable, { onPress: onLess, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: `${label} less`, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "minus", size: 15, color: "#F7F7FA" }) }),
1482
+ /* @__PURE__ */ jsx(Text, { style: styles.stepperValue, children: value }),
1483
+ /* @__PURE__ */ jsx(Pressable, { onPress: onMore, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: `${label} more`, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 15, color: "#F7F7FA" }) })
1484
+ ] });
1485
+ }
1486
+ function parseVoices(result) {
1487
+ var _a, _b, _c, _d, _e, _f;
1488
+ const raw = Array.isArray(result.voices) ? result.voices : Array.isArray(result) ? result : [];
1489
+ const out = [];
1490
+ for (const entry of raw) {
1491
+ if (!entry || typeof entry !== "object") continue;
1492
+ const e = entry;
1493
+ const id = (_c = (_b = (_a = e.id) != null ? _a : e.profileId) != null ? _b : e.voice) != null ? _c : e.name;
1494
+ if (!id) continue;
1495
+ const name = String((_e = (_d = e.name) != null ? _d : e.label) != null ? _e : id);
1496
+ const kind = String((_f = e.kind) != null ? _f : "preset");
1497
+ if (kind === "profile" && name.startsWith("preset:")) continue;
1498
+ out.push({
1499
+ id: String(id),
1500
+ label: name,
1501
+ profile: kind === "profile",
1502
+ engine: typeof e.engine === "string" ? e.engine : void 0
1503
+ });
1504
+ }
1505
+ return out;
1506
+ }
1507
+ function VoicePanel({
1508
+ runAction,
1509
+ uploadMedia,
1510
+ audioRecorder,
1511
+ voiceover,
1512
+ selectedClip,
1513
+ onVoiceover,
1514
+ onNotice
1515
+ }) {
1516
+ var _a;
1517
+ const [voices, setVoices] = useState([]);
1518
+ const [voice, setVoice] = useState(null);
1519
+ const [text, setText] = useState((_a = voiceover == null ? void 0 : voiceover.text) != null ? _a : "");
1520
+ const [instruct, setInstruct] = useState("");
1521
+ const [busy, setBusy] = useState(null);
1522
+ const [recording, setRecording] = useState(null);
1523
+ const [cloneName, setCloneName] = useState("");
1524
+ const [cloneSample, setCloneSample] = useState(null);
1525
+ const canRecord = Boolean(audioRecorder && uploadMedia && runAction);
1526
+ const toggleRecord = (purpose) => {
1527
+ if (!audioRecorder || !uploadMedia || !runAction) return;
1528
+ if (recording === purpose) {
1529
+ setRecording(null);
1530
+ setBusy("Processing recording");
1531
+ audioRecorder.stop().then(async (uri) => {
1532
+ var _a2, _b;
1533
+ if (!uri) throw new Error("Nothing was recorded.");
1534
+ const url = await uploadMedia(uri);
1535
+ const result = await runAction("yantra-voicebox", "YANTRA_VOICEBOX_TRANSCRIBE", {
1536
+ audioUrl: url
1537
+ });
1538
+ const transcript = (_b = (_a2 = result.text) != null ? _a2 : result.transcript) != null ? _b : typeof result.output === "string" ? result.output : "";
1539
+ if (purpose === "dictate") {
1540
+ if (!transcript) throw new Error("Could not hear any words in that.");
1541
+ setText(transcript);
1542
+ onNotice("Heard you - pick a voice and Generate to say it as them.");
1543
+ } else {
1544
+ setCloneSample({
1545
+ url,
1546
+ referenceText: transcript
1547
+ });
1548
+ onNotice(transcript ? "Sample ready - check the transcript matches what you said, then create your voice." : "Sample uploaded, but transcription was empty - type what you said, then create.");
1549
+ }
1550
+ }).catch((err) => onNotice(friendlyMediaError(err, "voice transcription"))).finally(() => setBusy(null));
1551
+ return;
1552
+ }
1553
+ if (recording !== null) return;
1554
+ audioRecorder.start().then(() => setRecording(purpose)).catch((err) => onNotice(friendlyMediaError(err, "voice recording")));
1555
+ };
1556
+ const createCloneVoice = () => {
1557
+ if (!runAction || !cloneSample || !cloneName.trim() || !cloneSample.referenceText.trim() || busy) return;
1558
+ setBusy("Creating your voice");
1559
+ runAction("yantra-voicebox", "YANTRA_VOICEBOX_CLONE_VOICE", {
1560
+ name: cloneName.trim(),
1561
+ sampleUrl: cloneSample.url,
1562
+ referenceText: cloneSample.referenceText.trim()
1563
+ }).then(async () => {
1564
+ const result = await runAction("yantra-voicebox", "YANTRA_VOICEBOX_LIST_VOICES", {});
1565
+ const parsed = parseVoices(result);
1566
+ setVoices(parsed);
1567
+ const mine = parsed.find((v) => v.profile && v.label === cloneName.trim());
1568
+ if (mine) setVoice(mine);
1569
+ setCloneSample(null);
1570
+ setCloneName("");
1571
+ onNotice("Your voice is ready - it is selected, Generate speaks as you.");
1572
+ }).catch((err) => onNotice(friendlyMediaError(err, "voice cloning"))).finally(() => setBusy(null));
1573
+ };
1574
+ useEffect(() => {
1575
+ if (!runAction) return;
1576
+ let cancelled = false;
1577
+ runAction("yantra-voicebox", "YANTRA_VOICEBOX_LIST_VOICES", {}).then((result) => {
1578
+ if (cancelled) return;
1579
+ const parsed = parseVoices(result);
1580
+ setVoices(parsed);
1581
+ setVoice((prev) => {
1582
+ var _a2;
1583
+ return (_a2 = prev != null ? prev : parsed[0]) != null ? _a2 : null;
1584
+ });
1585
+ }).catch(() => {
1586
+ if (!cancelled) setVoices([]);
1587
+ });
1588
+ return () => {
1589
+ cancelled = true;
1590
+ };
1591
+ }, [runAction]);
1592
+ if (!runAction) {
1593
+ return /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Voiceover needs the host connector - not wired in this host." });
1594
+ }
1595
+ const transcribeClip = () => {
1596
+ if (!selectedClip || selectedClip.type !== "video" || busy) return;
1597
+ setBusy("Transcribing");
1598
+ runAction("yantra-voicebox", "YANTRA_VOICEBOX_TRANSCRIBE", {
1599
+ audioUrl: selectedClip.src
1600
+ }).then((result) => {
1601
+ var _a2, _b;
1602
+ const t = (_b = (_a2 = result.text) != null ? _a2 : result.transcript) != null ? _b : typeof result.output === "string" ? result.output : void 0;
1603
+ if (!t) throw new Error("No transcript came back.");
1604
+ setText(t);
1605
+ }).catch((err) => onNotice(friendlyMediaError(err, "transcription"))).finally(() => setBusy(null));
1606
+ };
1607
+ const generate = () => {
1608
+ if (!text.trim() || busy) return;
1609
+ setBusy("Generating");
1610
+ runAction("yantra-voicebox", "YANTRA_VOICEBOX_SPEAK", __spreadValues(__spreadValues({
1611
+ text: text.trim()
1612
+ }, voice ? voice.profile ? {
1613
+ profileId: voice.id
1614
+ } : __spreadValues({
1615
+ voice: voice.id
1616
+ }, voice.engine ? {
1617
+ engine: voice.engine
1618
+ } : {}) : {}), instruct.trim() ? {
1619
+ instruct: instruct.trim()
1620
+ } : {})).then((result) => {
1621
+ var _a2;
1622
+ const audioUrl = resultUrl(result, "SPEAK");
1623
+ onVoiceover({
1624
+ audioUrl,
1625
+ mode: (_a2 = voiceover == null ? void 0 : voiceover.mode) != null ? _a2 : "mix",
1626
+ voiceLabel: voice == null ? void 0 : voice.label,
1627
+ text: text.trim()
1628
+ });
1629
+ onNotice("Voiceover ready - it plays under the whole timeline on export.");
1630
+ }).catch((err) => onNotice(friendlyMediaError(err, "voiceover"))).finally(() => setBusy(null));
1631
+ };
1632
+ return /* @__PURE__ */ jsxs(ScrollView, { style: styles.voiceScroll, keyboardShouldPersistTaps: "handled", children: [
1633
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.panelRow, children: voices.length === 0 ? /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "Loading voices\u2026" }) : voices.map((v) => {
1634
+ const active = (voice == null ? void 0 : voice.id) === v.id;
1635
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => setVoice(v), style: [styles.chip, active && styles.chipActive], accessibilityRole: "button", accessibilityState: {
1636
+ selected: active
1637
+ }, children: /* @__PURE__ */ jsxs(Text, { style: [styles.chipLabel, active && styles.chipLabelActive], children: [
1638
+ v.profile ? "\u2605 " : "",
1639
+ v.label
1640
+ ] }) }, `${v.profile ? "p" : "v"}-${v.id}`);
1641
+ }) }),
1642
+ /* @__PURE__ */ jsx(TextInput, { value: instruct, onChangeText: setInstruct, placeholder: "Direction (optional) - calm, warm, excited\u2026", placeholderTextColor: "#5A5A66", style: styles.voiceInstruct, selectionColor: "#8B7CFF" }),
1643
+ /* @__PURE__ */ jsx(TextInput, { value: text, onChangeText: setText, placeholder: "What should the voice say?", placeholderTextColor: "#5A5A66", style: styles.voiceText, selectionColor: "#8B7CFF", multiline: true }),
1644
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1645
+ canRecord ? /* @__PURE__ */ jsxs(Pressable, { onPress: () => toggleRecord("dictate"), style: [styles.chip, recording === "dictate" && styles.chipRecording], accessibilityRole: "button", accessibilityLabel: recording === "dictate" ? "Stop recording" : "Speak instead of typing", children: [
1646
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: recording === "dictate" ? "stop-circle-outline" : "microphone", size: 14, color: recording === "dictate" ? "#FF8484" : "#F7F7FA" }),
1647
+ /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, recording === "dictate" && styles.chipDanger], children: recording === "dictate" ? "Stop" : "Speak" })
1648
+ ] }) : null,
1649
+ (selectedClip == null ? void 0 : selectedClip.type) === "video" ? /* @__PURE__ */ jsx(Pressable, { onPress: transcribeClip, style: styles.chip, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles.chipLabel, children: busy === "Transcribing" ? "Transcribing\u2026" : "From clip" }) }) : null,
1650
+ /* @__PURE__ */ jsx(Pressable, { onPress: generate, disabled: !text.trim() || busy !== null, style: [styles.chip, styles.chipActive, (!text.trim() || busy !== null) && styles.chipDisabled], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: busy === "Generating" ? "Generating\u2026" : voiceover ? "Regenerate" : "Generate voiceover" }) })
1651
+ ] }),
1652
+ canRecord ? /* @__PURE__ */ jsxs(View, { style: styles.cloneBox, children: [
1653
+ /* @__PURE__ */ jsx(Text, { style: styles.cloneTitle, children: "MY VOICE" }),
1654
+ cloneSample === null ? /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1655
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => toggleRecord("clone"), style: [styles.chip, recording === "clone" && styles.chipRecording], accessibilityRole: "button", children: [
1656
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: recording === "clone" ? "stop-circle-outline" : "microphone-plus", size: 14, color: recording === "clone" ? "#FF8484" : "#F7F7FA" }),
1657
+ /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, recording === "clone" && styles.chipDanger], children: recording === "clone" ? "Stop" : "Record a sample" })
1658
+ ] }),
1659
+ /* @__PURE__ */ jsx(Text, { style: styles.cloneHint, children: "Read a sentence or two, naturally." })
1660
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1661
+ /* @__PURE__ */ jsx(TextInput, { value: cloneName, onChangeText: setCloneName, placeholder: "Name this voice - e.g. Me", placeholderTextColor: "#5A5A66", style: styles.voiceInstruct, selectionColor: "#8B7CFF" }),
1662
+ /* @__PURE__ */ jsx(TextInput, { value: cloneSample.referenceText, onChangeText: (referenceText) => setCloneSample(__spreadProps(__spreadValues({}, cloneSample), {
1663
+ referenceText
1664
+ })), placeholder: "What you said in the sample", placeholderTextColor: "#5A5A66", style: styles.voiceText, selectionColor: "#8B7CFF", multiline: true }),
1665
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1666
+ /* @__PURE__ */ jsx(Pressable, { onPress: createCloneVoice, disabled: !cloneName.trim() || !cloneSample.referenceText.trim() || busy !== null, style: [styles.chip, styles.chipActive, (!cloneName.trim() || !cloneSample.referenceText.trim() || busy !== null) && styles.chipDisabled], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipLabelActive], children: busy === "Creating your voice" ? "Creating\u2026" : "Create my voice" }) }),
1667
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => setCloneSample(null), style: styles.chip, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles.chipLabel, children: "Discard" }) })
1668
+ ] })
1669
+ ] })
1670
+ ] }) : null,
1671
+ voiceover ? /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1672
+ ["mix", "replace"].map((mode) => {
1673
+ const active = voiceover.mode === mode;
1674
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => onVoiceover(__spreadProps(__spreadValues({}, voiceover), {
1675
+ mode
1676
+ })), style: [styles.chip, active && styles.chipActive], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, active && styles.chipLabelActive], children: mode === "mix" ? "Mix under audio" : "Replace audio" }) }, mode);
1677
+ }),
1678
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => onVoiceover(null), style: styles.chip, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipDanger], children: "Remove" }) })
1679
+ ] }) : null
1680
+ ] });
1681
+ }
1682
+ function SoundtrackPanel({
1683
+ runAction,
1684
+ soundtrack,
1685
+ totalSec,
1686
+ onSoundtrack,
1687
+ onNotice
1688
+ }) {
1689
+ const [prompt, setPrompt] = useState("");
1690
+ const [busy, setBusy] = useState(false);
1691
+ const generate = useCallback(async () => {
1692
+ const styleText = prompt.trim();
1693
+ if (!styleText || !runAction || busy) return;
1694
+ setBusy(true);
1695
+ try {
1696
+ const durationSec = Math.min(120, Math.max(10, Math.ceil(totalSec || 15)));
1697
+ const result = await runAction("yantra-audio", "YANTRA_AUDIO_RUN_PROMPT", {
1698
+ prompt: styleText,
1699
+ model: "fal-ai/elevenlabs/music",
1700
+ durationSec,
1701
+ format: "mp3"
1702
+ });
1703
+ onSoundtrack({
1704
+ audioUrl: resultUrl(result, "RUN_PROMPT"),
1705
+ mode: "mix",
1706
+ title: styleText
1707
+ });
1708
+ } catch (err) {
1709
+ onNotice(friendlyMediaError(err, "soundtrack"));
1710
+ } finally {
1711
+ setBusy(false);
1712
+ }
1713
+ }, [prompt, runAction, busy, totalSec, onSoundtrack, onNotice]);
1714
+ if (!runAction) return null;
1715
+ return /* @__PURE__ */ jsx(View, { style: styles.soundtrackSection, children: soundtrack ? /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1716
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "music-note", size: 14, color: "#8B7CFF" }),
1717
+ /* @__PURE__ */ jsx(Text, { style: styles.soundtrackTitle, numberOfLines: 1, children: soundtrack.title || "Soundtrack" }),
1718
+ ["mix", "replace"].map((mode) => {
1719
+ const active = soundtrack.mode === mode;
1720
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => onSoundtrack(__spreadProps(__spreadValues({}, soundtrack), {
1721
+ mode
1722
+ })), style: [styles.chip, active && styles.chipActive], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, active && styles.chipLabelActive], children: mode === "mix" ? "Mix under audio" : "Replace audio" }) }, mode);
1723
+ }),
1724
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => onSoundtrack(null), style: styles.chip, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, styles.chipDanger], children: "Remove" }) })
1725
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1726
+ /* @__PURE__ */ jsxs(View, { style: styles.panelRow, children: [
1727
+ /* @__PURE__ */ jsx(TextInput, { value: prompt, onChangeText: setPrompt, style: [styles.textInput, styles.soundtrackInput], placeholder: "Soundtrack style - e.g. energetic Punjabi hip hop, heavy bassline", placeholderTextColor: "#5A5A66", selectionColor: "#8B7CFF", returnKeyType: "done", editable: !busy }),
1728
+ /* @__PURE__ */ jsx(Pressable, { onPress: () => void generate(), disabled: busy || !prompt.trim(), style: [styles.chip, prompt.trim() && !busy ? styles.chipActive : null], accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: [styles.chipLabel, prompt.trim() && !busy ? styles.chipLabelActive : null], children: busy ? "Composing\u2026" : "Generate" }) })
1729
+ ] }),
1730
+ /* @__PURE__ */ jsx(Text, { style: styles.panelHint, children: "An original track is composed for the whole cut - describe genre, mood, and energy." })
1731
+ ] }) });
1732
+ }
1733
+ const styles = StyleSheet.create({
1734
+ root: {
1735
+ flex: 1,
1736
+ backgroundColor: "#101013"
1737
+ },
1738
+ header: {
1739
+ flexDirection: "row",
1740
+ alignItems: "center",
1741
+ gap: 12,
1742
+ height: 52,
1743
+ paddingHorizontal: 14,
1744
+ borderBottomWidth: StyleSheet.hairlineWidth,
1745
+ borderBottomColor: "#26262c",
1746
+ backgroundColor: "#17171b"
1747
+ },
1748
+ headerCopy: {
1749
+ flex: 1,
1750
+ minWidth: 0,
1751
+ gap: 2
1752
+ },
1753
+ headerProject: {
1754
+ color: "#F2F2F5",
1755
+ fontSize: 16,
1756
+ fontWeight: "600"
1757
+ },
1758
+ headerSaved: {
1759
+ color: "#C8C8D0",
1760
+ fontSize: 12,
1761
+ fontWeight: "600"
1762
+ },
1763
+ headerSavedDim: {
1764
+ color: "#8B8B96",
1765
+ fontWeight: "500"
1766
+ },
1767
+ headerGhostBtn: {
1768
+ paddingHorizontal: 8,
1769
+ paddingVertical: 8,
1770
+ minHeight: 44,
1771
+ justifyContent: "center"
1772
+ },
1773
+ headerGhost: {
1774
+ color: "#E8E8EE",
1775
+ fontSize: 14,
1776
+ fontWeight: "600"
1777
+ },
1778
+ headerSpacer: {
1779
+ flex: 1,
1780
+ minWidth: 8
1781
+ },
1782
+ exportBtn: {
1783
+ paddingHorizontal: 12,
1784
+ paddingVertical: 7,
1785
+ borderRadius: 8,
1786
+ backgroundColor: "#E8E8EE"
1787
+ },
1788
+ exportBtnLabel: {
1789
+ color: "#101013",
1790
+ fontSize: 13,
1791
+ fontWeight: "700"
1792
+ },
1793
+ projectsPane: {
1794
+ gap: 10
1795
+ },
1796
+ projectActions: {
1797
+ flexDirection: "row",
1798
+ gap: 8
1799
+ },
1800
+ solidBtn: {
1801
+ flexDirection: "row",
1802
+ alignItems: "center",
1803
+ justifyContent: "center",
1804
+ gap: 6,
1805
+ minHeight: 44,
1806
+ paddingHorizontal: 14,
1807
+ borderRadius: 10,
1808
+ backgroundColor: "#F2F2F5"
1809
+ },
1810
+ solidBtnLabel: {
1811
+ color: "#101013",
1812
+ fontSize: 14,
1813
+ fontWeight: "700"
1814
+ },
1815
+ projectRow: {
1816
+ flexDirection: "row",
1817
+ alignItems: "center",
1818
+ gap: 8,
1819
+ paddingHorizontal: 10,
1820
+ paddingVertical: 10,
1821
+ borderRadius: 10,
1822
+ borderWidth: StyleSheet.hairlineWidth,
1823
+ borderColor: "#32323a",
1824
+ backgroundColor: "#1a1a20"
1825
+ },
1826
+ projectRowOn: {
1827
+ borderColor: "#5B6CFF",
1828
+ backgroundColor: "#1c2440"
1829
+ },
1830
+ projectRowCopy: {
1831
+ flex: 1,
1832
+ minWidth: 0,
1833
+ gap: 2
1834
+ },
1835
+ projectRowTitle: {
1836
+ color: "#F2F2F5",
1837
+ fontSize: 14,
1838
+ fontWeight: "600"
1839
+ },
1840
+ projectRowMeta: {
1841
+ color: "#8B8B96",
1842
+ fontSize: 11
1843
+ },
1844
+ renameInput: {
1845
+ flex: 1,
1846
+ color: "#F2F2F5",
1847
+ fontSize: 14,
1848
+ paddingVertical: 4,
1849
+ borderBottomWidth: StyleSheet.hairlineWidth,
1850
+ borderBottomColor: "#5B6CFF"
1851
+ },
1852
+ stageEmptyCopy: {
1853
+ flex: 1,
1854
+ alignItems: "center",
1855
+ justifyContent: "center",
1856
+ gap: 10,
1857
+ paddingHorizontal: 28
1858
+ },
1859
+ stageEmptyActions: {
1860
+ width: "100%",
1861
+ maxWidth: 280,
1862
+ gap: 8,
1863
+ marginTop: 4
1864
+ },
1865
+ ghostBtn: {
1866
+ flexDirection: "row",
1867
+ alignItems: "center",
1868
+ justifyContent: "center",
1869
+ gap: 6,
1870
+ minHeight: 44,
1871
+ paddingHorizontal: 14,
1872
+ borderRadius: 10,
1873
+ borderWidth: StyleSheet.hairlineWidth,
1874
+ borderColor: "#3A3A44",
1875
+ backgroundColor: "#1A1A20"
1876
+ },
1877
+ ghostBtnLabel: {
1878
+ color: "#F2F2F5",
1879
+ fontSize: 14,
1880
+ fontWeight: "700"
1881
+ },
1882
+ disabled: {
1883
+ opacity: 0.35
1884
+ },
1885
+ workspace: {
1886
+ flex: 1,
1887
+ minHeight: 0,
1888
+ position: "relative"
1889
+ },
1890
+ sheet: {
1891
+ position: "absolute",
1892
+ left: 0,
1893
+ right: 0,
1894
+ bottom: 76,
1895
+ maxHeight: 360,
1896
+ zIndex: 40,
1897
+ backgroundColor: "#17171b",
1898
+ borderTopLeftRadius: 18,
1899
+ borderTopRightRadius: 18,
1900
+ borderTopWidth: StyleSheet.hairlineWidth,
1901
+ borderTopColor: "#2c2c34",
1902
+ overflow: "hidden",
1903
+ shadowColor: "#000",
1904
+ shadowOpacity: 0.35,
1905
+ shadowRadius: 16,
1906
+ shadowOffset: {
1907
+ width: 0,
1908
+ height: -4
1909
+ },
1910
+ elevation: 12
1911
+ },
1912
+ sheetTall: {
1913
+ maxHeight: 480,
1914
+ height: 480
1915
+ },
1916
+ templateSheetBody: {
1917
+ flex: 1,
1918
+ minHeight: 0
1919
+ },
1920
+ sheetHead: {
1921
+ flexDirection: "row",
1922
+ alignItems: "center",
1923
+ gap: 8,
1924
+ paddingHorizontal: 14,
1925
+ height: 44,
1926
+ borderBottomWidth: StyleSheet.hairlineWidth,
1927
+ borderBottomColor: "#26262c"
1928
+ },
1929
+ sheetTitle: {
1930
+ color: "#F2F2F5",
1931
+ fontSize: 15,
1932
+ fontWeight: "600",
1933
+ flex: 1
1934
+ },
1935
+ sheetNewBtn: {
1936
+ flexDirection: "row",
1937
+ alignItems: "center",
1938
+ gap: 4,
1939
+ paddingHorizontal: 10,
1940
+ height: 30,
1941
+ borderRadius: 8,
1942
+ backgroundColor: "#F2F2F5"
1943
+ },
1944
+ sheetNewBtnLabel: {
1945
+ color: "#101013",
1946
+ fontSize: 12,
1947
+ fontWeight: "700"
1948
+ },
1949
+ dock: {
1950
+ flexGrow: 0,
1951
+ flexShrink: 0,
1952
+ maxHeight: 76,
1953
+ borderTopWidth: StyleSheet.hairlineWidth,
1954
+ borderTopColor: "#26262c",
1955
+ backgroundColor: "#141418"
1956
+ },
1957
+ dockInner: {
1958
+ flexDirection: "row",
1959
+ alignItems: "center",
1960
+ paddingHorizontal: 8,
1961
+ gap: 6,
1962
+ paddingTop: 8
1963
+ },
1964
+ dockTab: {
1965
+ minWidth: 68,
1966
+ alignItems: "center",
1967
+ gap: 4,
1968
+ paddingVertical: 8,
1969
+ paddingHorizontal: 6,
1970
+ borderRadius: 12
1971
+ },
1972
+ dockTabOn: {
1973
+ backgroundColor: "#243a5e"
1974
+ },
1975
+ recordPane: {
1976
+ gap: 8
1977
+ },
1978
+ recordRow: {
1979
+ flexDirection: "row",
1980
+ alignItems: "center",
1981
+ gap: 12,
1982
+ minHeight: 52,
1983
+ paddingHorizontal: 10,
1984
+ borderRadius: 12,
1985
+ backgroundColor: "#1A1A20",
1986
+ borderWidth: StyleSheet.hairlineWidth,
1987
+ borderColor: "#32323A"
1988
+ },
1989
+ recordError: {
1990
+ color: "#FECACA",
1991
+ fontSize: 13,
1992
+ lineHeight: 18,
1993
+ padding: 10,
1994
+ borderRadius: 10,
1995
+ backgroundColor: "rgba(248, 113, 113, 0.12)"
1996
+ },
1997
+ dockRecord: {
1998
+ minWidth: 72
1999
+ },
2000
+ dockRecordOn: {
2001
+ backgroundColor: "rgba(248, 113, 113, 0.16)"
2002
+ },
2003
+ dockRecordLabel: {
2004
+ color: "#FECACA"
2005
+ },
2006
+ dockRule: {
2007
+ width: StyleSheet.hairlineWidth,
2008
+ height: 28,
2009
+ backgroundColor: "#32323A",
2010
+ marginHorizontal: 4
2011
+ },
2012
+ dockLabel: {
2013
+ color: "#8B8B96",
2014
+ fontSize: 10,
2015
+ fontWeight: "600"
2016
+ },
2017
+ dockLabelOn: {
2018
+ color: "#F2F2F5"
2019
+ },
2020
+ captionRow: {
2021
+ flexDirection: "row",
2022
+ alignItems: "center",
2023
+ gap: 8,
2024
+ paddingVertical: 10,
2025
+ borderBottomWidth: StyleSheet.hairlineWidth,
2026
+ borderBottomColor: "#26262c"
2027
+ },
2028
+ captionRowText: {
2029
+ flex: 1,
2030
+ color: "#F2F2F5",
2031
+ fontSize: 14
2032
+ },
2033
+ captionRowMeta: {
2034
+ color: "#8B8B96",
2035
+ fontSize: 11,
2036
+ fontVariant: ["tabular-nums"]
2037
+ },
2038
+ sidePaneScroll: {
2039
+ maxHeight: 268
2040
+ },
2041
+ sidePaneInner: {
2042
+ paddingBottom: 20
2043
+ },
2044
+ stageCol: {
2045
+ flex: 1,
2046
+ minHeight: 0,
2047
+ backgroundColor: "#101013"
2048
+ },
2049
+ stageWell: {
2050
+ flex: 1,
2051
+ backgroundColor: "#08080a",
2052
+ padding: 10,
2053
+ minHeight: 0,
2054
+ position: "relative"
2055
+ },
2056
+ stage: {
2057
+ flex: 1,
2058
+ overflow: "hidden",
2059
+ backgroundColor: "#000000",
2060
+ borderRadius: 2
2061
+ },
2062
+ stageEmpty: {
2063
+ flex: 1,
2064
+ position: "relative"
2065
+ },
2066
+ stageEmptyTitle: {
2067
+ color: "#E8E8EE",
2068
+ fontSize: 15,
2069
+ fontWeight: "600"
2070
+ },
2071
+ stageEmptyDetail: {
2072
+ color: "#7A7A88",
2073
+ fontSize: 12.5,
2074
+ textAlign: "center",
2075
+ lineHeight: 18
2076
+ },
2077
+ stageText: {
2078
+ position: "absolute",
2079
+ transform: [{
2080
+ translateX: -60
2081
+ }, {
2082
+ translateY: -14
2083
+ }],
2084
+ maxWidth: 160,
2085
+ paddingHorizontal: 10,
2086
+ paddingVertical: 5,
2087
+ borderRadius: 8,
2088
+ backgroundColor: "rgba(10, 10, 12, 0.55)",
2089
+ borderWidth: 1,
2090
+ borderColor: "transparent"
2091
+ },
2092
+ stageTextActive: {
2093
+ borderColor: "#8B7CFF"
2094
+ },
2095
+ stageTextLabel: {
2096
+ color: "#F7F7FA",
2097
+ fontSize: 15,
2098
+ fontWeight: "600"
2099
+ },
2100
+ transport: {
2101
+ flexDirection: "row",
2102
+ alignItems: "center",
2103
+ justifyContent: "center",
2104
+ gap: 12,
2105
+ paddingVertical: 8
2106
+ },
2107
+ transportDisabled: {
2108
+ opacity: 0.3
2109
+ },
2110
+ transportTime: {
2111
+ color: "#F7F7FA",
2112
+ fontSize: 12.5,
2113
+ fontVariant: ["tabular-nums"]
2114
+ },
2115
+ transportTimeDim: {
2116
+ color: "#7A7A88"
2117
+ },
2118
+ timeline: {
2119
+ height: 200,
2120
+ flexGrow: 0,
2121
+ flexShrink: 0,
2122
+ backgroundColor: "#17171b",
2123
+ borderTopWidth: StyleSheet.hairlineWidth,
2124
+ borderTopColor: "#26262c"
2125
+ },
2126
+ timelineCompact: {
2127
+ height: 128
2128
+ },
2129
+ timelineBar: {
2130
+ flexDirection: "row",
2131
+ alignItems: "center",
2132
+ height: 52,
2133
+ paddingHorizontal: 6,
2134
+ borderBottomWidth: StyleSheet.hairlineWidth,
2135
+ borderBottomColor: "#26262c"
2136
+ },
2137
+ timelineIconBtn: {
2138
+ width: 40,
2139
+ height: 40,
2140
+ alignItems: "center",
2141
+ justifyContent: "center"
2142
+ },
2143
+ transportBtn: {
2144
+ width: 40,
2145
+ height: 40,
2146
+ alignItems: "center",
2147
+ justifyContent: "center"
2148
+ },
2149
+ transportPlay: {
2150
+ width: 44,
2151
+ height: 44,
2152
+ borderRadius: 22,
2153
+ backgroundColor: "#F2F2F5",
2154
+ alignItems: "center",
2155
+ justifyContent: "center",
2156
+ marginHorizontal: 4
2157
+ },
2158
+ timelineRule: {
2159
+ width: StyleSheet.hairlineWidth,
2160
+ height: 16,
2161
+ backgroundColor: "#26262c",
2162
+ marginHorizontal: 4
2163
+ },
2164
+ segmentMenu: {
2165
+ paddingHorizontal: 10,
2166
+ paddingBottom: 8,
2167
+ borderBottomWidth: StyleSheet.hairlineWidth,
2168
+ borderBottomColor: "#26262c",
2169
+ gap: 2
2170
+ },
2171
+ segmentMenuRow: {
2172
+ flexDirection: "row",
2173
+ alignItems: "center",
2174
+ gap: 8,
2175
+ paddingVertical: 6
2176
+ },
2177
+ segmentMenuCopy: {
2178
+ flex: 1,
2179
+ minWidth: 0
2180
+ },
2181
+ segmentMenuLabel: {
2182
+ color: "#F2F2F5",
2183
+ fontSize: 13,
2184
+ fontWeight: "600"
2185
+ },
2186
+ segmentMenuHint: {
2187
+ color: "#8B8B96",
2188
+ fontSize: 11
2189
+ },
2190
+ timelineBarActions: {
2191
+ flexDirection: "row",
2192
+ alignItems: "center",
2193
+ gap: 4
2194
+ },
2195
+ laneRow: {
2196
+ flexDirection: "row",
2197
+ height: 56,
2198
+ borderBottomWidth: StyleSheet.hairlineWidth,
2199
+ borderBottomColor: "#26262c"
2200
+ },
2201
+ laneGutter: {
2202
+ width: 108,
2203
+ flexDirection: "row",
2204
+ alignItems: "center",
2205
+ gap: 6,
2206
+ paddingHorizontal: 8,
2207
+ borderRightWidth: StyleSheet.hairlineWidth,
2208
+ borderRightColor: "#26262c",
2209
+ backgroundColor: "#17171b"
2210
+ },
2211
+ laneBody: {
2212
+ flex: 1,
2213
+ minWidth: 0
2214
+ },
2215
+ laneLabelRow: {
2216
+ paddingBottom: 4
2217
+ },
2218
+ laneLabel: {
2219
+ color: "#9A9AA5",
2220
+ fontSize: 10,
2221
+ fontWeight: "700",
2222
+ letterSpacing: 0.6,
2223
+ textTransform: "uppercase"
2224
+ },
2225
+ textTrack: {
2226
+ flexDirection: "row",
2227
+ gap: 6,
2228
+ marginBottom: 6
2229
+ },
2230
+ textPill: {
2231
+ flexDirection: "row",
2232
+ alignItems: "center",
2233
+ gap: 5,
2234
+ paddingHorizontal: 9,
2235
+ paddingVertical: 4,
2236
+ borderRadius: 7,
2237
+ backgroundColor: "#2A2440",
2238
+ borderWidth: 1,
2239
+ borderColor: "transparent",
2240
+ maxWidth: 150
2241
+ },
2242
+ textPillActive: {
2243
+ borderColor: "#8B7CFF"
2244
+ },
2245
+ textPillLabel: {
2246
+ color: "#DCD6FF",
2247
+ fontSize: 11.5
2248
+ },
2249
+ clipTrack: {
2250
+ flexDirection: "row",
2251
+ gap: 6,
2252
+ minHeight: 56
2253
+ },
2254
+ clipTrackEmpty: {
2255
+ flexDirection: "row",
2256
+ alignItems: "center",
2257
+ gap: 8,
2258
+ margin: 8,
2259
+ paddingHorizontal: 12,
2260
+ height: 40,
2261
+ borderRadius: 8,
2262
+ borderWidth: StyleSheet.hairlineWidth,
2263
+ borderColor: "#3A3A44",
2264
+ borderStyle: "dashed",
2265
+ backgroundColor: "#1A1A20"
2266
+ },
2267
+ clipTrackEmptyLabel: {
2268
+ color: "#8B8B96",
2269
+ fontSize: 13,
2270
+ fontWeight: "600"
2271
+ },
2272
+ clipBlock: {
2273
+ width: 96,
2274
+ height: 56,
2275
+ borderRadius: 9,
2276
+ overflow: "hidden",
2277
+ backgroundColor: "#16161A",
2278
+ borderWidth: 1.5,
2279
+ borderColor: "transparent"
2280
+ },
2281
+ clipBlockActive: {
2282
+ borderColor: "#8B7CFF"
2283
+ },
2284
+ clipMeta: {
2285
+ position: "absolute",
2286
+ left: 0,
2287
+ right: 0,
2288
+ bottom: 0,
2289
+ flexDirection: "row",
2290
+ justifyContent: "space-between",
2291
+ paddingHorizontal: 6,
2292
+ paddingVertical: 2,
2293
+ backgroundColor: "rgba(10, 10, 12, 0.6)"
2294
+ },
2295
+ clipMetaText: {
2296
+ color: "#E8E8EE",
2297
+ fontSize: 9.5,
2298
+ fontVariant: ["tabular-nums"]
2299
+ },
2300
+ panel: {
2301
+ flex: 1,
2302
+ minHeight: 0,
2303
+ paddingHorizontal: 10,
2304
+ paddingVertical: 10
2305
+ },
2306
+ mediaPane: {
2307
+ gap: 12
2308
+ },
2309
+ pickRow: {
2310
+ flexDirection: "row",
2311
+ gap: 8
2312
+ },
2313
+ pickBtn: {
2314
+ flex: 1,
2315
+ alignItems: "center",
2316
+ gap: 6,
2317
+ paddingVertical: 12,
2318
+ borderRadius: 12,
2319
+ backgroundColor: "#222228",
2320
+ borderWidth: StyleSheet.hairlineWidth,
2321
+ borderColor: "#32323a"
2322
+ },
2323
+ pickBtnLabel: {
2324
+ color: "#E8E8EE",
2325
+ fontSize: 12,
2326
+ fontWeight: "600"
2327
+ },
2328
+ dropzone: {
2329
+ alignItems: "center",
2330
+ gap: 4,
2331
+ paddingVertical: 22,
2332
+ paddingHorizontal: 10,
2333
+ borderRadius: 12,
2334
+ borderWidth: 1,
2335
+ borderStyle: "dashed",
2336
+ borderColor: "rgba(255,255,255,0.18)",
2337
+ backgroundColor: "#16161A"
2338
+ },
2339
+ dropzoneTitle: {
2340
+ color: "#F7F7FA",
2341
+ fontSize: 13,
2342
+ fontWeight: "600"
2343
+ },
2344
+ dropzoneHint: {
2345
+ color: "#7A7A88",
2346
+ fontSize: 11,
2347
+ textAlign: "center"
2348
+ },
2349
+ mediaGrid: {
2350
+ flexDirection: "row",
2351
+ flexWrap: "wrap",
2352
+ gap: 8,
2353
+ paddingBottom: 16
2354
+ },
2355
+ panelRow: {
2356
+ flexDirection: "row",
2357
+ alignItems: "center",
2358
+ gap: 8,
2359
+ paddingVertical: 4
2360
+ },
2361
+ panelEmpty: {
2362
+ color: "#7A7A88",
2363
+ fontSize: 13
2364
+ },
2365
+ panelHint: {
2366
+ color: "#7A7A88",
2367
+ fontSize: 11.5,
2368
+ marginTop: 6
2369
+ },
2370
+ panelBar: {
2371
+ flexDirection: "row",
2372
+ alignItems: "center",
2373
+ justifyContent: "space-between",
2374
+ marginBottom: 8
2375
+ },
2376
+ panelBarTitle: {
2377
+ color: "#C8C8D0",
2378
+ fontSize: 11,
2379
+ fontWeight: "700",
2380
+ letterSpacing: 0.6,
2381
+ textTransform: "uppercase"
2382
+ },
2383
+ panelBarBtn: {
2384
+ flexDirection: "row",
2385
+ alignItems: "center",
2386
+ gap: 4,
2387
+ paddingHorizontal: 8,
2388
+ paddingVertical: 5
2389
+ },
2390
+ panelBarBtnLabel: {
2391
+ color: "#F7F7FA",
2392
+ fontSize: 12,
2393
+ fontWeight: "600"
2394
+ },
2395
+ emptyPanel: {
2396
+ alignItems: "center",
2397
+ justifyContent: "flex-start",
2398
+ gap: 8,
2399
+ paddingVertical: 16,
2400
+ paddingHorizontal: 12
2401
+ },
2402
+ templatesPane: {
2403
+ gap: 10,
2404
+ paddingBottom: 12
2405
+ },
2406
+ generateField: {
2407
+ flexDirection: "row",
2408
+ alignItems: "flex-start",
2409
+ minHeight: 88,
2410
+ paddingLeft: 12,
2411
+ paddingRight: 12,
2412
+ paddingTop: 12,
2413
+ paddingBottom: 10,
2414
+ gap: 10,
2415
+ borderRadius: 12,
2416
+ backgroundColor: "#141418",
2417
+ borderWidth: 1,
2418
+ borderColor: "#2E2E38"
2419
+ },
2420
+ generateIcon: {
2421
+ marginTop: 2
2422
+ },
2423
+ generateInput: {
2424
+ flex: 1,
2425
+ color: "#F2F2F5",
2426
+ fontSize: 16,
2427
+ lineHeight: 22,
2428
+ minHeight: 64,
2429
+ padding: 0
2430
+ },
2431
+ generateBtn: {
2432
+ minHeight: 44,
2433
+ borderRadius: 12,
2434
+ backgroundColor: "#8B7CFF",
2435
+ alignItems: "center",
2436
+ justifyContent: "center"
2437
+ },
2438
+ generateBtnLabel: {
2439
+ color: "#0A0A0C",
2440
+ fontSize: 15,
2441
+ fontWeight: "700"
2442
+ },
2443
+ searchField: {
2444
+ flexDirection: "row",
2445
+ alignItems: "center",
2446
+ minHeight: 44,
2447
+ marginTop: 4,
2448
+ paddingLeft: 12,
2449
+ paddingRight: 8,
2450
+ gap: 8,
2451
+ borderRadius: 12,
2452
+ backgroundColor: "#141418",
2453
+ borderWidth: 1,
2454
+ borderColor: "#2E2E38"
2455
+ },
2456
+ searchInput: {
2457
+ flex: 1,
2458
+ color: "#F2F2F5",
2459
+ fontSize: 16,
2460
+ paddingVertical: 10
2461
+ },
2462
+ searchClear: {
2463
+ width: 36,
2464
+ height: 36,
2465
+ alignItems: "center",
2466
+ justifyContent: "center"
2467
+ },
2468
+ templateList: {
2469
+ flex: 1
2470
+ },
2471
+ templateListInner: {
2472
+ paddingHorizontal: 12,
2473
+ paddingBottom: 16
2474
+ },
2475
+ templateRow: {
2476
+ flexDirection: "row",
2477
+ alignItems: "flex-start",
2478
+ gap: 8,
2479
+ marginBottom: 10
2480
+ },
2481
+ templateGrid: {
2482
+ flexDirection: "row",
2483
+ flexWrap: "wrap",
2484
+ gap: 8
2485
+ },
2486
+ templateCard: {
2487
+ flex: 1,
2488
+ gap: 6,
2489
+ minWidth: 0
2490
+ },
2491
+ templateCover: {
2492
+ width: "100%",
2493
+ aspectRatio: 16 / 9,
2494
+ borderRadius: 8,
2495
+ backgroundColor: "#121216"
2496
+ },
2497
+ templateTitle: {
2498
+ color: "#E8E8EE",
2499
+ fontSize: 12,
2500
+ fontWeight: "600",
2501
+ minHeight: 32
2502
+ },
2503
+ templateActions: {
2504
+ flexDirection: "row",
2505
+ alignItems: "stretch",
2506
+ gap: 6
2507
+ },
2508
+ templateGenerate: {
2509
+ flex: 1,
2510
+ minHeight: 32,
2511
+ flexDirection: "row",
2512
+ alignItems: "center",
2513
+ justifyContent: "center",
2514
+ gap: 4,
2515
+ borderRadius: 8,
2516
+ backgroundColor: "#2A2A32",
2517
+ borderWidth: 1,
2518
+ borderColor: "#3A3A44",
2519
+ paddingHorizontal: 4
2520
+ },
2521
+ templateGenerateLabel: {
2522
+ color: "#F2F2F5",
2523
+ fontSize: 11,
2524
+ fontWeight: "600"
2525
+ },
2526
+ templatePreviewBtn: {
2527
+ flex: 1,
2528
+ minHeight: 32,
2529
+ flexDirection: "row",
2530
+ alignItems: "center",
2531
+ justifyContent: "center",
2532
+ gap: 4,
2533
+ borderRadius: 8,
2534
+ backgroundColor: "#141418",
2535
+ borderWidth: 1,
2536
+ borderColor: "#2E2E38",
2537
+ paddingHorizontal: 4
2538
+ },
2539
+ templatePreviewLabel: {
2540
+ color: "#D8D8E0",
2541
+ fontSize: 11,
2542
+ fontWeight: "600"
2543
+ },
2544
+ templatePreviewOverlay: {
2545
+ position: "absolute",
2546
+ top: 0,
2547
+ left: 0,
2548
+ right: 0,
2549
+ bottom: 76,
2550
+ zIndex: 60,
2551
+ backgroundColor: "rgba(8,8,10,0.94)",
2552
+ paddingHorizontal: 12,
2553
+ paddingTop: 8,
2554
+ paddingBottom: 12,
2555
+ gap: 6
2556
+ },
2557
+ templatePreviewBar: {
2558
+ flexDirection: "row",
2559
+ alignItems: "center",
2560
+ gap: 8
2561
+ },
2562
+ templatePreviewKicker: {
2563
+ color: "#F2F2F5",
2564
+ fontSize: 10,
2565
+ fontWeight: "700",
2566
+ letterSpacing: 0.3,
2567
+ backgroundColor: "rgba(255,255,255,0.15)",
2568
+ overflow: "hidden",
2569
+ paddingHorizontal: 8,
2570
+ paddingVertical: 3,
2571
+ borderRadius: 99
2572
+ },
2573
+ templatePreviewBarTitle: {
2574
+ flex: 1,
2575
+ color: "rgba(255,255,255,0.85)",
2576
+ fontSize: 13
2577
+ },
2578
+ templatePreviewAspect: {
2579
+ color: "rgba(255,255,255,0.7)",
2580
+ fontSize: 11,
2581
+ backgroundColor: "rgba(255,255,255,0.1)",
2582
+ overflow: "hidden",
2583
+ paddingHorizontal: 6,
2584
+ paddingVertical: 2,
2585
+ borderRadius: 4
2586
+ },
2587
+ templatePreviewHint: {
2588
+ color: "rgba(255,255,255,0.5)",
2589
+ fontSize: 11
2590
+ },
2591
+ templatePreviewMedia: {
2592
+ flex: 1,
2593
+ minHeight: 220,
2594
+ overflow: "hidden",
2595
+ backgroundColor: "#000",
2596
+ borderRadius: 4
2597
+ },
2598
+ templatePreviewMediaFill: {
2599
+ flex: 1,
2600
+ minHeight: 220
2601
+ },
2602
+ templateWebView: {
2603
+ flex: 1,
2604
+ minHeight: 220,
2605
+ backgroundColor: "#000"
2606
+ },
2607
+ templatePreviewImage: {
2608
+ width: "100%",
2609
+ height: "100%",
2610
+ minHeight: 220
2611
+ },
2612
+ templateFooter: {
2613
+ height: 8
2614
+ },
2615
+ templateLoadBar: {
2616
+ width: "100%",
2617
+ paddingTop: 10,
2618
+ paddingBottom: 16,
2619
+ backgroundColor: "#17171b"
2620
+ },
2621
+ loadMoreBtn: {
2622
+ width: "100%",
2623
+ minHeight: 48,
2624
+ flexDirection: "row",
2625
+ alignItems: "center",
2626
+ justifyContent: "center",
2627
+ gap: 8,
2628
+ borderRadius: 12,
2629
+ backgroundColor: "#E8E8EE"
2630
+ },
2631
+ loadMoreBtnPressed: {
2632
+ opacity: 0.88
2633
+ },
2634
+ loadMoreBtnLabel: {
2635
+ color: "#101013",
2636
+ fontSize: 16,
2637
+ fontWeight: "700"
2638
+ },
2639
+ templateFooterHint: {
2640
+ color: "#6A6A74",
2641
+ fontSize: 11,
2642
+ textAlign: "center",
2643
+ paddingVertical: 8
2644
+ },
2645
+ clipInspector: {
2646
+ borderTopWidth: StyleSheet.hairlineWidth,
2647
+ borderTopColor: "#26262c",
2648
+ backgroundColor: "#141418",
2649
+ paddingHorizontal: 12,
2650
+ paddingVertical: 8,
2651
+ gap: 6
2652
+ },
2653
+ clipInspectorTitle: {
2654
+ color: "#F2F2F5",
2655
+ fontSize: 13,
2656
+ fontWeight: "600"
2657
+ },
2658
+ busyOverlay: __spreadProps(__spreadValues({}, StyleSheet.absoluteFillObject), {
2659
+ zIndex: 80,
2660
+ backgroundColor: "rgba(8,8,10,0.62)",
2661
+ alignItems: "center",
2662
+ justifyContent: "center",
2663
+ paddingHorizontal: 28
2664
+ }),
2665
+ busyCard: {
2666
+ width: "100%",
2667
+ maxWidth: 320,
2668
+ borderRadius: 16,
2669
+ backgroundColor: "#1c1c22",
2670
+ paddingHorizontal: 20,
2671
+ paddingVertical: 22,
2672
+ alignItems: "center",
2673
+ gap: 10
2674
+ },
2675
+ busyTitle: {
2676
+ color: "#F7F7FA",
2677
+ fontSize: 16,
2678
+ fontWeight: "600"
2679
+ },
2680
+ busyDetail: {
2681
+ color: "#A9A9B4",
2682
+ fontSize: 13,
2683
+ textAlign: "center",
2684
+ lineHeight: 18
2685
+ },
2686
+ busyTrack: {
2687
+ marginTop: 6,
2688
+ width: "100%",
2689
+ height: 4,
2690
+ borderRadius: 99,
2691
+ backgroundColor: "#2c2c34",
2692
+ overflow: "hidden"
2693
+ },
2694
+ busyTrackFill: {
2695
+ width: "62%",
2696
+ height: "100%",
2697
+ borderRadius: 99,
2698
+ backgroundColor: "#7C8CFF"
2699
+ },
2700
+ sceneSwatch: {
2701
+ width: 36,
2702
+ height: 36,
2703
+ borderRadius: 8,
2704
+ borderWidth: 1,
2705
+ borderColor: "rgba(255,255,255,0.12)"
2706
+ },
2707
+ logoPreview: {
2708
+ height: 48,
2709
+ width: "100%",
2710
+ marginBottom: 8
2711
+ },
2712
+ logoOverlay: {
2713
+ position: "absolute",
2714
+ right: 10,
2715
+ bottom: 10,
2716
+ width: 72,
2717
+ height: 28
2718
+ },
2719
+ stageToolbar: {
2720
+ position: "absolute",
2721
+ left: 10,
2722
+ right: 10,
2723
+ bottom: 10,
2724
+ flexDirection: "row",
2725
+ gap: 6,
2726
+ justifyContent: "center"
2727
+ },
2728
+ stagePill: {
2729
+ paddingHorizontal: 10,
2730
+ paddingVertical: 6,
2731
+ borderRadius: 999,
2732
+ backgroundColor: "rgba(10,10,12,0.72)"
2733
+ },
2734
+ stagePillOn: {
2735
+ backgroundColor: "#8B7CFF"
2736
+ },
2737
+ stagePillLabel: {
2738
+ color: "#F7F7FA",
2739
+ fontSize: 11,
2740
+ fontWeight: "600"
2741
+ },
2742
+ stageToolRow: {
2743
+ paddingHorizontal: 12,
2744
+ paddingVertical: 6,
2745
+ gap: 6,
2746
+ flexDirection: "row"
2747
+ },
2748
+ textPreset: {
2749
+ minWidth: 108,
2750
+ paddingHorizontal: 12,
2751
+ paddingVertical: 10,
2752
+ borderRadius: 10,
2753
+ backgroundColor: "#16161A",
2754
+ borderWidth: 1,
2755
+ borderColor: "rgba(255,255,255,0.08)"
2756
+ },
2757
+ textPresetSample: {
2758
+ color: "#F7F7FA",
2759
+ fontSize: 15,
2760
+ fontWeight: "700"
2761
+ },
2762
+ textPresetLabel: {
2763
+ color: "#7A7A88",
2764
+ fontSize: 11,
2765
+ marginTop: 4
2766
+ },
2767
+ voiceScroll: {
2768
+ maxHeight: 240
2769
+ },
2770
+ voiceInstruct: {
2771
+ color: "#F7F7FA",
2772
+ fontSize: 13,
2773
+ paddingHorizontal: 12,
2774
+ paddingVertical: 8,
2775
+ borderRadius: 9,
2776
+ backgroundColor: "#16161A",
2777
+ marginTop: 6
2778
+ },
2779
+ voiceText: {
2780
+ minHeight: 64,
2781
+ color: "#F7F7FA",
2782
+ fontSize: 13.5,
2783
+ lineHeight: 19,
2784
+ padding: 12,
2785
+ borderRadius: 9,
2786
+ backgroundColor: "#16161A",
2787
+ marginTop: 8,
2788
+ textAlignVertical: "top"
2789
+ },
2790
+ chipRecording: {
2791
+ backgroundColor: "rgba(255, 132, 132, 0.16)"
2792
+ },
2793
+ cloneBox: {
2794
+ marginTop: 10,
2795
+ paddingTop: 10,
2796
+ borderTopWidth: StyleSheet.hairlineWidth,
2797
+ borderTopColor: "rgba(255,255,255,0.08)",
2798
+ gap: 4
2799
+ },
2800
+ cloneTitle: {
2801
+ color: "#8B7CFF",
2802
+ fontSize: 10.5,
2803
+ fontWeight: "700",
2804
+ letterSpacing: 0.8,
2805
+ marginBottom: 2
2806
+ },
2807
+ cloneHint: {
2808
+ color: "#7A7A88",
2809
+ fontSize: 11.5,
2810
+ flexShrink: 1
2811
+ },
2812
+ voTrack: {
2813
+ flexDirection: "row",
2814
+ alignItems: "center",
2815
+ gap: 6,
2816
+ paddingVertical: 4,
2817
+ paddingHorizontal: 2,
2818
+ marginBottom: 4
2819
+ },
2820
+ voTrackLabel: {
2821
+ color: "#DCD6FF",
2822
+ fontSize: 11
2823
+ },
2824
+ mediaTile: {
2825
+ width: 84,
2826
+ height: 56
2827
+ },
2828
+ devicePick: {
2829
+ borderRadius: 10,
2830
+ borderWidth: 1.5,
2831
+ borderColor: "#2A2440",
2832
+ borderStyle: "dashed",
2833
+ alignItems: "center",
2834
+ justifyContent: "center",
2835
+ gap: 3
2836
+ },
2837
+ devicePickLabel: {
2838
+ color: "#8B7CFF",
2839
+ fontSize: 10,
2840
+ fontWeight: "600"
2841
+ },
2842
+ mediaThumb: {
2843
+ width: 84,
2844
+ height: 56,
2845
+ borderRadius: 8,
2846
+ backgroundColor: "#16161A"
2847
+ },
2848
+ mediaThumbVideo: {
2849
+ alignItems: "center",
2850
+ justifyContent: "center",
2851
+ backgroundColor: "#16161A"
2852
+ },
2853
+ mediaAdd: {
2854
+ position: "absolute",
2855
+ right: 3,
2856
+ top: 3,
2857
+ width: 18,
2858
+ height: 18,
2859
+ borderRadius: 9,
2860
+ backgroundColor: "#8B7CFF",
2861
+ alignItems: "center",
2862
+ justifyContent: "center"
2863
+ },
2864
+ filterTile: {
2865
+ alignItems: "center",
2866
+ gap: 5,
2867
+ width: 62
2868
+ },
2869
+ filterThumb: {
2870
+ width: 56,
2871
+ height: 56,
2872
+ borderRadius: 10,
2873
+ overflow: "hidden",
2874
+ backgroundColor: "#16161A",
2875
+ borderWidth: 1.5,
2876
+ borderColor: "transparent"
2877
+ },
2878
+ filterThumbActive: {
2879
+ borderColor: "#8B7CFF"
2880
+ },
2881
+ filterNoneGlyph: {
2882
+ position: "absolute",
2883
+ alignSelf: "center",
2884
+ top: 19
2885
+ },
2886
+ filterLabel: {
2887
+ color: "#9A9AA5",
2888
+ fontSize: 10.5
2889
+ },
2890
+ filterLabelActive: {
2891
+ color: "#F7F7FA",
2892
+ fontWeight: "600"
2893
+ },
2894
+ chip: {
2895
+ flexDirection: "row",
2896
+ alignItems: "center",
2897
+ gap: 5,
2898
+ paddingHorizontal: 12,
2899
+ paddingVertical: 8,
2900
+ borderRadius: 9,
2901
+ backgroundColor: "#1F1F24"
2902
+ },
2903
+ chipWide: {
2904
+ alignSelf: "flex-start"
2905
+ },
2906
+ chipActive: {
2907
+ backgroundColor: "#8B7CFF"
2908
+ },
2909
+ chipDisabled: {
2910
+ opacity: 0.35
2911
+ },
2912
+ chipLabel: {
2913
+ color: "#F7F7FA",
2914
+ fontSize: 12.5,
2915
+ fontWeight: "500"
2916
+ },
2917
+ chipLabelActive: {
2918
+ color: "#0A0A0C"
2919
+ },
2920
+ chipDanger: {
2921
+ color: "#FF6B6B"
2922
+ },
2923
+ textInput: {
2924
+ color: "#F7F7FA",
2925
+ fontSize: 14,
2926
+ paddingHorizontal: 12,
2927
+ paddingVertical: 9,
2928
+ borderRadius: 9,
2929
+ backgroundColor: "#16161A"
2930
+ },
2931
+ soundtrackSection: {
2932
+ marginTop: 10
2933
+ },
2934
+ soundtrackInput: {
2935
+ flex: 1,
2936
+ minWidth: 0
2937
+ },
2938
+ soundtrackTitle: {
2939
+ flexShrink: 1,
2940
+ fontSize: 12,
2941
+ fontWeight: "600",
2942
+ color: "#F7F7FA"
2943
+ },
2944
+ stepper: {
2945
+ flexDirection: "row",
2946
+ alignItems: "center",
2947
+ gap: 9,
2948
+ paddingHorizontal: 12,
2949
+ paddingVertical: 8,
2950
+ borderRadius: 9,
2951
+ backgroundColor: "#1F1F24"
2952
+ },
2953
+ stepperLabel: {
2954
+ color: "#9A9AA5",
2955
+ fontSize: 11.5
2956
+ },
2957
+ stepperValue: {
2958
+ color: "#F7F7FA",
2959
+ fontSize: 12.5,
2960
+ fontVariant: ["tabular-nums"],
2961
+ minWidth: 34,
2962
+ textAlign: "center"
2963
+ },
2964
+ trimTrack: {
2965
+ height: 40,
2966
+ borderRadius: 8,
2967
+ backgroundColor: "#16161A",
2968
+ justifyContent: "center",
2969
+ marginBottom: 4
2970
+ },
2971
+ trimWindow: {
2972
+ position: "absolute",
2973
+ top: 0,
2974
+ bottom: 0,
2975
+ borderRadius: 8,
2976
+ backgroundColor: "rgba(139, 124, 255, 0.28)",
2977
+ borderWidth: 1.5,
2978
+ borderColor: "#8B7CFF"
2979
+ },
2980
+ trimHandle: {
2981
+ position: "absolute",
2982
+ top: 0,
2983
+ bottom: 0,
2984
+ width: 20,
2985
+ alignItems: "center",
2986
+ justifyContent: "center"
2987
+ },
2988
+ trimHandleBar: {
2989
+ width: 4,
2990
+ height: 22,
2991
+ borderRadius: 2,
2992
+ backgroundColor: "#F7F7FA"
2993
+ },
2994
+ trimReadout: {
2995
+ color: "#9A9AA5",
2996
+ fontSize: 10.5,
2997
+ textAlign: "center",
2998
+ fontVariant: ["tabular-nums"]
2999
+ },
3000
+ toolbarScroll: {
3001
+ flexGrow: 0,
3002
+ borderTopWidth: StyleSheet.hairlineWidth,
3003
+ borderTopColor: "rgba(255,255,255,0.08)"
3004
+ },
3005
+ toolbar: {
3006
+ flexDirection: "row",
3007
+ alignItems: "center",
3008
+ gap: 4,
3009
+ paddingHorizontal: 10,
3010
+ paddingVertical: 8,
3011
+ paddingBottom: 10
3012
+ },
3013
+ toolbarTab: {
3014
+ alignItems: "center",
3015
+ gap: 3,
3016
+ minWidth: 56,
3017
+ paddingHorizontal: 6
3018
+ },
3019
+ toolbarLabel: {
3020
+ color: "#C8C8D0",
3021
+ fontSize: 10
3022
+ },
3023
+ toolbarLabelActive: {
3024
+ color: "#8B7CFF",
3025
+ fontWeight: "600"
3026
+ },
3027
+ notice: {
3028
+ position: "absolute",
3029
+ left: 20,
3030
+ right: 20,
3031
+ bottom: 84,
3032
+ flexDirection: "row",
3033
+ alignItems: "center",
3034
+ gap: 12,
3035
+ paddingHorizontal: 14,
3036
+ paddingVertical: 11,
3037
+ borderRadius: 12,
3038
+ backgroundColor: "rgba(248, 250, 252, 0.96)"
3039
+ },
3040
+ noticeText: {
3041
+ flex: 1,
3042
+ color: "#0f172a",
3043
+ fontSize: 13
3044
+ },
3045
+ noticeDismiss: {
3046
+ color: "#6C5CE7",
3047
+ fontSize: 13,
3048
+ fontWeight: "600"
3049
+ }
3050
+ });export{VideoEditorExperience,VideoEditorExperience as default};//# sourceMappingURL=VideoEditorExperience.js.map