@athenaintel/react 0.23.3 → 0.24.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 (288) hide show
  1. package/README.md +6 -0
  2. package/dist/assets/AssetPanel.cjs +1 -1
  3. package/dist/assets/AssetPanel.cjs.map +1 -1
  4. package/dist/assets/AssetPanel.js +1 -1
  5. package/dist/assets/AssetPanel.js.map +1 -1
  6. package/dist/assets/AthenaAssetEmbed.cjs +1 -1
  7. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  8. package/dist/assets/AthenaAssetEmbed.js +1 -1
  9. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  10. package/dist/chat/AthenaChat.cjs +15 -23
  11. package/dist/chat/AthenaChat.cjs.map +1 -1
  12. package/dist/chat/AthenaChat.d.ts +9 -4
  13. package/dist/chat/AthenaChat.js +15 -23
  14. package/dist/chat/AthenaChat.js.map +1 -1
  15. package/dist/chat/StatewireApprovalCard.cjs +3 -18
  16. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  17. package/dist/chat/StatewireApprovalCard.js +3 -18
  18. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  19. package/dist/chat/StatewireClientToolBridge.cjs +2 -16
  20. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  21. package/dist/chat/StatewireClientToolBridge.js +2 -16
  22. package/dist/chat/StatewireClientToolBridge.js.map +1 -1
  23. package/dist/chat/StatewireQueuedMessages.cjs +5 -16
  24. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  25. package/dist/chat/StatewireQueuedMessages.js +5 -16
  26. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  27. package/dist/chat/WaitingOnYouBanner.cjs +3 -18
  28. package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
  29. package/dist/chat/WaitingOnYouBanner.js +3 -18
  30. package/dist/chat/WaitingOnYouBanner.js.map +1 -1
  31. package/dist/chat/run-activity.cjs +0 -16
  32. package/dist/chat/run-activity.cjs.map +1 -1
  33. package/dist/chat/run-activity.js +0 -16
  34. package/dist/chat/run-activity.js.map +1 -1
  35. package/dist/chat/statewire-client-tools.cjs +1 -17
  36. package/dist/chat/statewire-client-tools.cjs.map +1 -1
  37. package/dist/chat/statewire-client-tools.js +1 -17
  38. package/dist/chat/statewire-client-tools.js.map +1 -1
  39. package/dist/chat/super-grouping/activity-timeline.cjs +0 -16
  40. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  41. package/dist/chat/super-grouping/activity-timeline.js +0 -16
  42. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  43. package/dist/chat/tiptap-text.cjs +1 -17
  44. package/dist/chat/tiptap-text.cjs.map +1 -1
  45. package/dist/chat/tiptap-text.js +1 -17
  46. package/dist/chat/tiptap-text.js.map +1 -1
  47. package/dist/chat/use-athena-run-live.cjs +0 -15
  48. package/dist/chat/use-athena-run-live.cjs.map +1 -1
  49. package/dist/chat/use-athena-run-live.js +0 -15
  50. package/dist/chat/use-athena-run-live.js.map +1 -1
  51. package/dist/chat/use-statewire-approval-request.cjs +4 -16
  52. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  53. package/dist/chat/use-statewire-approval-request.d.ts +2 -0
  54. package/dist/chat/use-statewire-approval-request.js +4 -16
  55. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  56. package/dist/chat-ui/composer/tiptap-composer.cjs +1 -16
  57. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  58. package/dist/chat-ui/composer/tiptap-composer.js +1 -16
  59. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  60. package/dist/chat-ui/index.cjs +0 -16
  61. package/dist/chat-ui/index.cjs.map +1 -1
  62. package/dist/chat-ui/index.js +0 -16
  63. package/dist/chat-ui/index.js.map +1 -1
  64. package/dist/chat-ui/mentions/mention-chip.cjs +1 -16
  65. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  66. package/dist/chat-ui/mentions/mention-chip.js +1 -16
  67. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  68. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +4 -6
  69. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
  70. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +4 -6
  71. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
  72. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +2 -9
  73. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  74. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +2 -9
  75. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  76. package/dist/chat-ui/messages/message-components.cjs +5 -19
  77. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  78. package/dist/chat-ui/messages/message-components.js +5 -19
  79. package/dist/chat-ui/messages/message-components.js.map +1 -1
  80. package/dist/chat-ui/messages/runtime-message.cjs +1 -16
  81. package/dist/chat-ui/messages/runtime-message.cjs.map +1 -1
  82. package/dist/chat-ui/messages/runtime-message.js +1 -16
  83. package/dist/chat-ui/messages/runtime-message.js.map +1 -1
  84. package/dist/chat-ui/messages/statewire-continue-run.cjs +3 -15
  85. package/dist/chat-ui/messages/statewire-continue-run.cjs.map +1 -1
  86. package/dist/chat-ui/messages/statewire-continue-run.js +3 -15
  87. package/dist/chat-ui/messages/statewire-continue-run.js.map +1 -1
  88. package/dist/chat-ui/messages/user-edit-composer.cjs +0 -16
  89. package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
  90. package/dist/chat-ui/messages/user-edit-composer.js +0 -16
  91. package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
  92. package/dist/chat-ui/messages/wake-marker.cjs +1 -16
  93. package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
  94. package/dist/chat-ui/messages/wake-marker.js +1 -16
  95. package/dist/chat-ui/messages/wake-marker.js.map +1 -1
  96. package/dist/chat-ui/statewire.cjs +0 -16
  97. package/dist/chat-ui/statewire.cjs.map +1 -1
  98. package/dist/chat-ui/statewire.js +0 -16
  99. package/dist/chat-ui/statewire.js.map +1 -1
  100. package/dist/chat-ui/thread/statewire-history-edge.cjs +2 -17
  101. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  102. package/dist/chat-ui/thread/statewire-history-edge.js +2 -17
  103. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  104. package/dist/dictation/DictationStrip.cjs +2 -1
  105. package/dist/dictation/DictationStrip.cjs.map +1 -1
  106. package/dist/dictation/DictationStrip.d.ts +2 -0
  107. package/dist/dictation/DictationStrip.js +2 -1
  108. package/dist/dictation/DictationStrip.js.map +1 -1
  109. package/dist/dictation/dictation-engine.cjs.map +1 -1
  110. package/dist/dictation/dictation-engine.d.ts +8 -0
  111. package/dist/dictation/dictation-engine.js.map +1 -1
  112. package/dist/dictation/recorded-dictation-engine.cjs +153 -0
  113. package/dist/dictation/recorded-dictation-engine.cjs.map +1 -0
  114. package/dist/dictation/recorded-dictation-engine.d.ts +66 -0
  115. package/dist/dictation/recorded-dictation-engine.js +153 -0
  116. package/dist/dictation/recorded-dictation-engine.js.map +1 -0
  117. package/dist/dictation/use-athena-dictation-engine.cjs +64 -0
  118. package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -0
  119. package/dist/dictation/use-athena-dictation-engine.d.ts +25 -0
  120. package/dist/dictation/use-athena-dictation-engine.js +64 -0
  121. package/dist/dictation/use-athena-dictation-engine.js.map +1 -0
  122. package/dist/dictation/use-dictation.cjs +17 -6
  123. package/dist/dictation/use-dictation.cjs.map +1 -1
  124. package/dist/dictation/use-dictation.d.ts +20 -4
  125. package/dist/dictation/use-dictation.js +17 -6
  126. package/dist/dictation/use-dictation.js.map +1 -1
  127. package/dist/index.cjs +28 -39
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.ts +4 -1
  130. package/dist/index.js +10 -21
  131. package/dist/index.js.map +1 -1
  132. package/dist/packages/agent-runtime/src/edit-command.cjs.map +1 -1
  133. package/dist/packages/agent-runtime/src/edit-command.js.map +1 -1
  134. package/dist/packages/agent-runtime/src/errors.cjs +18 -0
  135. package/dist/packages/agent-runtime/src/errors.cjs.map +1 -1
  136. package/dist/packages/agent-runtime/src/errors.js +19 -1
  137. package/dist/packages/agent-runtime/src/errors.js.map +1 -1
  138. package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +1 -0
  139. package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  140. package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +1 -0
  141. package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  142. package/dist/packages/agent-runtime/src/interrupts.cjs +61 -12
  143. package/dist/packages/agent-runtime/src/interrupts.cjs.map +1 -1
  144. package/dist/packages/agent-runtime/src/interrupts.js +61 -12
  145. package/dist/packages/agent-runtime/src/interrupts.js.map +1 -1
  146. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs +49 -0
  147. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  148. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js +49 -0
  149. package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  150. package/dist/packages/agent-runtime/src/thread-status.js +1 -1
  151. package/dist/packages/agent-runtime/src/tool-metadata.cjs +1 -37
  152. package/dist/packages/agent-runtime/src/tool-metadata.cjs.map +1 -1
  153. package/dist/packages/agent-runtime/src/tool-metadata.js +1 -37
  154. package/dist/packages/agent-runtime/src/tool-metadata.js.map +1 -1
  155. package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs +0 -1
  156. package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
  157. package/dist/packages/agent-runtime/src/use-deep-agent-config.js +0 -1
  158. package/dist/packages/agent-runtime/src/use-deep-agent-config.js.map +1 -1
  159. package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  160. package/dist/packages/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  161. package/dist/packages/react/package.json.cjs +1 -1
  162. package/dist/packages/react/package.json.js +1 -1
  163. package/dist/provider/AthenaProvider.cjs +3 -17
  164. package/dist/provider/AthenaProvider.cjs.map +1 -1
  165. package/dist/provider/AthenaProvider.js +3 -17
  166. package/dist/provider/AthenaProvider.js.map +1 -1
  167. package/dist/runtime/statewire-lifecycle.cjs +0 -16
  168. package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
  169. package/dist/runtime/statewire-lifecycle.js +0 -16
  170. package/dist/runtime/statewire-lifecycle.js.map +1 -1
  171. package/dist/runtime/useAthenaStatewireRuntime.cjs +3 -17
  172. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  173. package/dist/runtime/useAthenaStatewireRuntime.js +3 -17
  174. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  175. package/dist/threads/statewire-thread-list.cjs +4 -17
  176. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  177. package/dist/threads/statewire-thread-list.js +4 -17
  178. package/dist/threads/statewire-thread-list.js.map +1 -1
  179. package/dist/threads/use-rest-conversation-history.cjs +2 -16
  180. package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
  181. package/dist/threads/use-rest-conversation-history.js +2 -16
  182. package/dist/threads/use-rest-conversation-history.js.map +1 -1
  183. package/dist/threads/use-statewire-conversation-history.cjs +2 -16
  184. package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
  185. package/dist/threads/use-statewire-conversation-history.js +2 -16
  186. package/dist/threads/use-statewire-conversation-history.js.map +1 -1
  187. package/dist/toolkits/index.cjs +0 -7
  188. package/dist/toolkits/index.cjs.map +1 -1
  189. package/dist/toolkits/index.d.ts +0 -2
  190. package/dist/toolkits/index.js +0 -7
  191. package/dist/toolkits/index.js.map +1 -1
  192. package/dist/tools/index.cjs +4 -20
  193. package/dist/tools/index.cjs.map +1 -1
  194. package/dist/tools/index.js +1 -17
  195. package/dist/tools/index.js.map +1 -1
  196. package/dist/tools/misc-tool-uis.cjs +2 -17
  197. package/dist/tools/misc-tool-uis.cjs.map +1 -1
  198. package/dist/tools/misc-tool-uis.js +2 -17
  199. package/dist/tools/misc-tool-uis.js.map +1 -1
  200. package/dist/tools/primitives.cjs +1 -16
  201. package/dist/tools/primitives.cjs.map +1 -1
  202. package/dist/tools/primitives.js +1 -16
  203. package/dist/tools/primitives.js.map +1 -1
  204. package/dist/tools/tool-fallback.cjs +2 -17
  205. package/dist/tools/tool-fallback.cjs.map +1 -1
  206. package/dist/tools/tool-fallback.js +2 -17
  207. package/dist/tools/tool-fallback.js.map +1 -1
  208. package/dist/tools/voice-update-tool-ui.cjs +1 -17
  209. package/dist/tools/voice-update-tool-ui.cjs.map +1 -1
  210. package/dist/tools/voice-update-tool-ui.js +1 -17
  211. package/dist/tools/voice-update-tool-ui.js.map +1 -1
  212. package/package.json +1 -1
  213. package/dist/node_modules/qrcode-generator/dist/qrcode.cjs +0 -32
  214. package/dist/node_modules/qrcode-generator/dist/qrcode.cjs.map +0 -1
  215. package/dist/node_modules/qrcode-generator/dist/qrcode.js +0 -31
  216. package/dist/node_modules/qrcode-generator/dist/qrcode.js.map +0 -1
  217. package/dist/node_modules/zod/v4/classic/errors.cjs +0 -44
  218. package/dist/node_modules/zod/v4/classic/errors.cjs.map +0 -1
  219. package/dist/node_modules/zod/v4/classic/errors.js +0 -44
  220. package/dist/node_modules/zod/v4/classic/errors.js.map +0 -1
  221. package/dist/node_modules/zod/v4/classic/iso.cjs +0 -43
  222. package/dist/node_modules/zod/v4/classic/iso.cjs.map +0 -1
  223. package/dist/node_modules/zod/v4/classic/iso.js +0 -43
  224. package/dist/node_modules/zod/v4/classic/iso.js.map +0 -1
  225. package/dist/node_modules/zod/v4/classic/parse.cjs +0 -29
  226. package/dist/node_modules/zod/v4/classic/parse.cjs.map +0 -1
  227. package/dist/node_modules/zod/v4/classic/parse.js +0 -29
  228. package/dist/node_modules/zod/v4/classic/parse.js.map +0 -1
  229. package/dist/node_modules/zod/v4/classic/schemas.cjs +0 -871
  230. package/dist/node_modules/zod/v4/classic/schemas.cjs.map +0 -1
  231. package/dist/node_modules/zod/v4/classic/schemas.js +0 -871
  232. package/dist/node_modules/zod/v4/classic/schemas.js.map +0 -1
  233. package/dist/node_modules/zod/v4/core/api.cjs +0 -570
  234. package/dist/node_modules/zod/v4/core/api.cjs.map +0 -1
  235. package/dist/node_modules/zod/v4/core/api.js +0 -570
  236. package/dist/node_modules/zod/v4/core/api.js.map +0 -1
  237. package/dist/node_modules/zod/v4/core/checks.cjs +0 -411
  238. package/dist/node_modules/zod/v4/core/checks.cjs.map +0 -1
  239. package/dist/node_modules/zod/v4/core/checks.js +0 -411
  240. package/dist/node_modules/zod/v4/core/checks.js.map +0 -1
  241. package/dist/node_modules/zod/v4/core/core.cjs +0 -77
  242. package/dist/node_modules/zod/v4/core/core.cjs.map +0 -1
  243. package/dist/node_modules/zod/v4/core/core.js +0 -77
  244. package/dist/node_modules/zod/v4/core/core.js.map +0 -1
  245. package/dist/node_modules/zod/v4/core/doc.cjs +0 -38
  246. package/dist/node_modules/zod/v4/core/doc.cjs.map +0 -1
  247. package/dist/node_modules/zod/v4/core/doc.js +0 -38
  248. package/dist/node_modules/zod/v4/core/doc.js.map +0 -1
  249. package/dist/node_modules/zod/v4/core/errors.cjs +0 -76
  250. package/dist/node_modules/zod/v4/core/errors.cjs.map +0 -1
  251. package/dist/node_modules/zod/v4/core/errors.js +0 -76
  252. package/dist/node_modules/zod/v4/core/errors.js.map +0 -1
  253. package/dist/node_modules/zod/v4/core/json-schema-processors.cjs +0 -312
  254. package/dist/node_modules/zod/v4/core/json-schema-processors.cjs.map +0 -1
  255. package/dist/node_modules/zod/v4/core/json-schema-processors.js +0 -312
  256. package/dist/node_modules/zod/v4/core/json-schema-processors.js.map +0 -1
  257. package/dist/node_modules/zod/v4/core/parse.cjs +0 -96
  258. package/dist/node_modules/zod/v4/core/parse.cjs.map +0 -1
  259. package/dist/node_modules/zod/v4/core/parse.js +0 -96
  260. package/dist/node_modules/zod/v4/core/parse.js.map +0 -1
  261. package/dist/node_modules/zod/v4/core/regexes.cjs +0 -86
  262. package/dist/node_modules/zod/v4/core/regexes.cjs.map +0 -1
  263. package/dist/node_modules/zod/v4/core/regexes.js +0 -86
  264. package/dist/node_modules/zod/v4/core/regexes.js.map +0 -1
  265. package/dist/node_modules/zod/v4/core/registries.cjs +0 -52
  266. package/dist/node_modules/zod/v4/core/registries.cjs.map +0 -1
  267. package/dist/node_modules/zod/v4/core/registries.js +0 -52
  268. package/dist/node_modules/zod/v4/core/registries.js.map +0 -1
  269. package/dist/node_modules/zod/v4/core/schemas.cjs +0 -1412
  270. package/dist/node_modules/zod/v4/core/schemas.cjs.map +0 -1
  271. package/dist/node_modules/zod/v4/core/schemas.js +0 -1413
  272. package/dist/node_modules/zod/v4/core/schemas.js.map +0 -1
  273. package/dist/node_modules/zod/v4/core/to-json-schema.cjs +0 -370
  274. package/dist/node_modules/zod/v4/core/to-json-schema.cjs.map +0 -1
  275. package/dist/node_modules/zod/v4/core/to-json-schema.js +0 -370
  276. package/dist/node_modules/zod/v4/core/to-json-schema.js.map +0 -1
  277. package/dist/node_modules/zod/v4/core/util.cjs +0 -444
  278. package/dist/node_modules/zod/v4/core/util.cjs.map +0 -1
  279. package/dist/node_modules/zod/v4/core/util.js +0 -444
  280. package/dist/node_modules/zod/v4/core/util.js.map +0 -1
  281. package/dist/node_modules/zod/v4/core/versions.cjs +0 -9
  282. package/dist/node_modules/zod/v4/core/versions.cjs.map +0 -1
  283. package/dist/node_modules/zod/v4/core/versions.js +0 -9
  284. package/dist/node_modules/zod/v4/core/versions.js.map +0 -1
  285. package/dist/packages/agent-runtime/src/thread-handoff.cjs +0 -85
  286. package/dist/packages/agent-runtime/src/thread-handoff.cjs.map +0 -1
  287. package/dist/packages/agent-runtime/src/thread-handoff.js +0 -85
  288. package/dist/packages/agent-runtime/src/thread-handoff.js.map +0 -1
package/README.md CHANGED
@@ -459,6 +459,12 @@ Both use the same bearer / API key as session creation. The full recipe
459
459
  template skill `voice-session-guide.md`. `createAthenaVoiceSession` is also
460
460
  exported if you hold the bridge state yourself.
461
461
 
462
+ ## What's new in 0.24.0
463
+
464
+ **Dictation is transcribed by Athena.** The composer mic now records with `MediaRecorder` and, on Stop or Send, posts the clip to agora's `POST /api/transcription/upload`, which runs Deepgram Nova-3 and returns the text; the strip shows "Transcribing…" until the words land. Accuracy is Deepgram's, every language Deepgram supports works (the session `lang` is forwarded), and the mic is available in Firefox. There are no live interim captions. A recording stops on its own after 5 minutes and is transcribed as if Stop had been pressed (`createRecordedDictationEngine({ maxDurationMs })` to change it); agora caps a clip at 10 MB and rate-limits uploads per user (20 a minute by default). Pass `dictation={{ engine: createWebSpeechDictationEngine() }}` to keep the browser's live Web Speech engine. Needs an agora that serves `/api/transcription/upload` (staging from 2026-09-24; production with the next release train).
465
+
466
+ **Breaking: `useDictation().stop()` resolves to `{ text, error }`** (`DictationStopResult`) instead of a string, so a custom composer can tell a failed transcription from silence and keep the draft instead of sending it; `AthenaChat` does exactly that. `DictationEngine` gains optional `flushTimeoutMs` (how long `stop()` waits for the flush; 1.5 s live, 90 s recorded) and `stoppingLabel`; the controller exposes `engine`; `DictationStrip` takes `stoppingLabel`. New exports: `createRecordedDictationEngine`, `useAthenaDictationEngine`, `DictationTranscriber`, `DictationTranscribeContext`, `RecordedDictationEngineOptions`, `DictationStopResult`.
467
+
462
468
  ## What's new in 0.23.3
463
469
 
464
470
  **Dictation in the composer.** `<AthenaChat>` now has a microphone left of Send. Click it and the editor row becomes a live waveform; Stop puts the spoken words into the draft for review, Send sends them (queued while a run is live). The default engine is the browser's Web Speech API (Chrome, Edge, Safari) — no backend, no extra dependency; the mic hides itself where the engine is missing (Firefox). Pass `dictation={false}` to remove it, or `dictation={{ lang, engine }}` to set the language or plug in another speech engine (`DictationEngine` interface, `useDictation()` hook, `DictationStrip` component are exported for custom composers).
@@ -99,7 +99,7 @@ const AssetIframe = react.memo(
99
99
  width: "100%",
100
100
  height: "100%",
101
101
  frameBorder: "0",
102
- allow: "fullscreen",
102
+ allow: "clipboard-write; fullscreen",
103
103
  title: tab.name ?? `Asset ${tab.id}`,
104
104
  className: "h-full w-full",
105
105
  onLoad: postNavigationMessage
@@ -1 +1 @@
1
- {"version":3,"file":"AssetPanel.cjs","sources":["../../src/assets/AssetPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FC, memo, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport {\n X,\n Loader2,\n AlertCircle,\n Maximize2,\n Minimize2,\n FileText,\n FileSpreadsheet,\n Presentation,\n File,\n BookOpen,\n LayoutGrid,\n Layers,\n} from \"lucide-react\";\nimport { appendCitationReferenceParams, useAssetEmbed } from \"./use-asset-embed\";\nimport {\n useAssetPanelStore,\n type AssetTab,\n type AssetType,\n} from \"./asset-panel-store\";\nimport {\n buildAssetIframeSrc,\n buildPresentationNavigationMessage,\n} from \"./asset-panel-url\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\n\nconst ASSET_TYPE_CONFIG: Record<\n AssetType,\n { icon: typeof File; label: string }\n> = {\n presentation: { icon: Presentation, label: \"Presentation\" },\n spreadsheet: { icon: FileSpreadsheet, label: \"Spreadsheet\" },\n document: { icon: FileText, label: \"Document\" },\n notebook: { icon: BookOpen, label: \"Notebook\" },\n unknown: { icon: File, label: \"Asset\" },\n};\n\n/** Memoized iframe for a single asset — only re-renders when iframe inputs change. */\nconst AssetIframe = memo<{ tab: AssetTab }>(\n ({ tab }) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const { backendUrl, appUrl, apiKey, token } = useAthenaConfig();\n const { embedUrl, isLoading, error } = useAssetEmbed(tab.id, {\n backendUrl,\n appUrl,\n apiKey,\n token,\n });\n const initialSlideRef = useRef<{\n assetId: string;\n slideNumber?: number;\n }>({\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n });\n if (initialSlideRef.current.assetId !== tab.id) {\n initialSlideRef.current = {\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n };\n }\n const initialSlideNumber = initialSlideRef.current.slideNumber;\n // The citation target rides the embed URL: the embed page parses the\n // anchor params and navigates (sheet range scroll/flash, PDF page). A\n // repeat click with a DIFFERENT target updates the tab's reference ->\n // new src -> the iframe reloads at the new range. Same target twice is a\n // no-op (already there).\n //\n // Deliberately does NOT set `athena_sdk_bridge=1` (buildSdkAssetEmbedUrl\n // is for AthenaAssetEmbed): that flag makes the embed page wait\n // indefinitely for a host config handshake that only AthenaAssetEmbed\n // implements — the panel's bare iframe never replies, so the embed would\n // hang on its loading bar forever.\n const iframeSrc = useMemo(() => {\n if (!embedUrl) return null;\n const base = buildAssetIframeSrc({\n embedUrl,\n assetType: tab.type,\n slideNumber: initialSlideNumber,\n });\n try {\n const url = new URL(base, window.location.href);\n appendCitationReferenceParams({ params: url.searchParams, reference: tab.reference });\n return url.toString();\n } catch {\n return base;\n }\n }, [embedUrl, initialSlideNumber, tab.type, tab.reference]);\n const navigationMessage = useMemo(\n () =>\n buildPresentationNavigationMessage({\n assetId: tab.id,\n assetType: tab.type,\n slideNumber: tab.slideNumber,\n }),\n [tab.id, tab.slideNumber, tab.type],\n );\n const navigationTargetOrigin = useMemo(() => {\n if (!iframeSrc) return null;\n\n try {\n return new URL(iframeSrc, window.location.href).origin;\n } catch {\n return null;\n }\n }, [iframeSrc]);\n const postNavigationMessage = useCallback(() => {\n if (!navigationMessage || !navigationTargetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n navigationMessage,\n navigationTargetOrigin,\n );\n }, [navigationMessage, navigationTargetOrigin]);\n\n useEffect(() => {\n postNavigationMessage();\n }, [postNavigationMessage]);\n\n if (isLoading) {\n return (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"text-center\">\n <Loader2 className=\"mx-auto size-6 animate-spin text-muted-foreground\" />\n <p className=\"mt-2 text-xs text-muted-foreground\">Loading...</p>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <div className=\"max-w-sm text-center\">\n <AlertCircle className=\"mx-auto size-5 text-red-400\" />\n <p className=\"mt-1.5 text-xs font-medium text-foreground\">\n Failed to load\n </p>\n <p className=\"mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground\">\n {error}\n </p>\n </div>\n </div>\n );\n }\n\n if (!iframeSrc) return null;\n\n return (\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n frameBorder=\"0\"\n allow=\"fullscreen\"\n title={tab.name ?? `Asset ${tab.id}`}\n className=\"h-full w-full\"\n onLoad={postNavigationMessage}\n />\n );\n },\n (prev, next) =>\n prev.tab.id === next.tab.id &&\n prev.tab.name === next.tab.name &&\n prev.tab.type === next.tab.type &&\n prev.tab.slideNumber === next.tab.slideNumber,\n);\n\nAssetIframe.displayName = \"AssetIframe\";\n\nexport interface AssetPanelProps {\n /** Register this panel as an asset-panel host when used outside AthenaLayout. */\n manageAssetPanelHostRegistration?: boolean;\n}\n\n/**\n * Content area — renders all iframes in the same tree.\n * Tab mode: only active tab visible via CSS. Tiled mode: CSS grid. Iframes never unmount on switch.\n */\nconst PanelContent: FC<{ manageAssetPanelHostRegistration: boolean }> = ({\n manageAssetPanelHostRegistration,\n}) => {\n const {\n tabs,\n activeTabId,\n viewMode,\n closeTab,\n registerAssetPanelHost,\n unregisterAssetPanelHost,\n } =\n useAssetPanelStore();\n const isTiled = viewMode === \"tiled\" && tabs.length >= 2;\n\n useEffect(() => {\n if (!manageAssetPanelHostRegistration) {\n return;\n }\n\n registerAssetPanelHost();\n return () => {\n unregisterAssetPanelHost();\n };\n }, [manageAssetPanelHostRegistration, registerAssetPanelHost, unregisterAssetPanelHost]);\n\n const gridClass = useMemo(() => {\n const n = tabs.length;\n if (n <= 1) return \"\";\n if (n === 2) return \"grid grid-cols-2 grid-rows-1\";\n if (n <= 4) return \"grid grid-cols-2 grid-rows-2\";\n if (n <= 6) return \"grid grid-cols-3 grid-rows-2\";\n return \"grid grid-cols-3 grid-rows-3\";\n }, [tabs.length]);\n\n return (\n <div\n className={`flex-1 overflow-hidden ${isTiled ? `${gridClass} gap-px bg-border/60` : \"\"}`}\n >\n {tabs.map((tab) => {\n const isActive = tab.id === activeTabId;\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n\n if (isTiled) {\n return (\n <div\n key={tab.id}\n className=\"flex min-h-0 min-w-0 flex-col bg-background\"\n >\n <div className=\"flex shrink-0 items-center gap-1.5 border-b px-2 py-1\">\n <TypeIcon className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate text-[11px] font-medium text-foreground\">\n {tab.name ?? config.label}\n </span>\n <button\n onClick={() => closeTab(tab.id)}\n className=\"shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-hidden\">\n <AssetIframe tab={tab} />\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={tab.id}\n className={isActive ? \"h-full w-full\" : \"hidden\"}\n >\n <AssetIframe tab={tab} />\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Tab bar for tab mode — scrollable row of tabs. */\nconst TabBar: FC = () => {\n const { tabs, activeTabId, setActiveTab, closeTab, viewMode } =\n useAssetPanelStore();\n\n if (tabs.length <= 1 || viewMode === \"tiled\") return null;\n\n return (\n <div className=\"flex shrink-0 items-center gap-0 overflow-x-auto border-b bg-muted/30\">\n {tabs.map((tab) => {\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n const isActive = tab.id === activeTabId;\n\n return (\n <div\n key={tab.id}\n className={`group flex max-w-[180px] shrink-0 cursor-pointer items-center gap-1.5 border-r border-border/40 px-3 py-1.5 text-xs ${\n isActive\n ? \"border-b-2 border-b-primary bg-background text-foreground\"\n : \"text-muted-foreground hover:bg-background/50 hover:text-foreground\"\n }`}\n onClick={() => setActiveTab(tab.id)}\n >\n <TypeIcon className=\"size-3 shrink-0\" />\n <span className=\"truncate\">{tab.name ?? config.label}</span>\n <button\n onClick={(e) => {\n e.stopPropagation();\n closeTab(tab.id);\n }}\n className=\"ml-auto shrink-0 rounded p-0.5 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Header with active tab info + panel controls. */\nconst PanelHeader: FC<{ fullscreen?: boolean }> = ({ fullscreen }) => {\n const {\n closePanel,\n toggleFullscreen,\n tabs,\n activeTabId,\n viewMode,\n setViewMode,\n } = useAssetPanelStore();\n const activeTab = tabs.find((t) => t.id === activeTabId);\n const config = ASSET_TYPE_CONFIG[activeTab?.type ?? \"unknown\"];\n const TypeIcon = config.icon;\n const isTiled = viewMode === \"tiled\";\n\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b px-4 py-2.5\">\n {!isTiled && (\n <TypeIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <p className=\"flex-1 truncate text-sm font-semibold text-foreground\">\n {isTiled\n ? `${tabs.length} Assets`\n : activeTab?.name ?? config.label}\n </p>\n\n {tabs.length >= 2 && (\n <button\n onClick={() => setViewMode(isTiled ? \"tabs\" : \"tiled\")}\n className={`flex size-7 items-center justify-center rounded-lg transition-colors ${\n isTiled\n ? \"bg-primary/10 text-primary\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\"\n }`}\n title={isTiled ? \"Switch to tabs\" : \"Tile all assets\"}\n >\n {isTiled ? (\n <Layers className=\"size-3.5\" />\n ) : (\n <LayoutGrid className=\"size-3.5\" />\n )}\n </button>\n )}\n\n <button\n onClick={toggleFullscreen}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title={fullscreen ? \"Exit fullscreen\" : \"Fullscreen\"}\n >\n {fullscreen ? (\n <Minimize2 className=\"size-3.5\" />\n ) : (\n <Maximize2 className=\"size-3.5\" />\n )}\n </button>\n <button\n onClick={closePanel}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title=\"Close all\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n );\n};\n\nexport const AssetPanel: FC<AssetPanelProps> = ({\n manageAssetPanelHostRegistration = true,\n}) => {\n const isFullscreen = useAssetPanelStore((s) => s.isFullscreen);\n\n const content = (\n <>\n <PanelHeader fullscreen={isFullscreen} />\n <TabBar />\n <PanelContent manageAssetPanelHostRegistration={manageAssetPanelHostRegistration} />\n </>\n );\n\n if (isFullscreen) {\n return (\n <div className=\"fixed inset-0 z-50 flex flex-col bg-background\">\n {content}\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full flex-col bg-background\">{content}</div>\n );\n};\n"],"names":["Presentation","FileSpreadsheet","FileText","BookOpen","File","memo","useRef","useAthenaConfig","useAssetEmbed","useMemo","buildAssetIframeSrc","appendCitationReferenceParams","buildPresentationNavigationMessage","useCallback","useEffect","jsxs","jsx","Loader2","AlertCircle","useAssetPanelStore","X","Layers","LayoutGrid","Minimize2","Maximize2","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"AssetPanel.cjs","sources":["../../src/assets/AssetPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FC, memo, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport {\n X,\n Loader2,\n AlertCircle,\n Maximize2,\n Minimize2,\n FileText,\n FileSpreadsheet,\n Presentation,\n File,\n BookOpen,\n LayoutGrid,\n Layers,\n} from \"lucide-react\";\nimport { appendCitationReferenceParams, useAssetEmbed } from \"./use-asset-embed\";\nimport {\n useAssetPanelStore,\n type AssetTab,\n type AssetType,\n} from \"./asset-panel-store\";\nimport {\n buildAssetIframeSrc,\n buildPresentationNavigationMessage,\n} from \"./asset-panel-url\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\n\nconst ASSET_TYPE_CONFIG: Record<\n AssetType,\n { icon: typeof File; label: string }\n> = {\n presentation: { icon: Presentation, label: \"Presentation\" },\n spreadsheet: { icon: FileSpreadsheet, label: \"Spreadsheet\" },\n document: { icon: FileText, label: \"Document\" },\n notebook: { icon: BookOpen, label: \"Notebook\" },\n unknown: { icon: File, label: \"Asset\" },\n};\n\n/** Memoized iframe for a single asset — only re-renders when iframe inputs change. */\nconst AssetIframe = memo<{ tab: AssetTab }>(\n ({ tab }) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const { backendUrl, appUrl, apiKey, token } = useAthenaConfig();\n const { embedUrl, isLoading, error } = useAssetEmbed(tab.id, {\n backendUrl,\n appUrl,\n apiKey,\n token,\n });\n const initialSlideRef = useRef<{\n assetId: string;\n slideNumber?: number;\n }>({\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n });\n if (initialSlideRef.current.assetId !== tab.id) {\n initialSlideRef.current = {\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n };\n }\n const initialSlideNumber = initialSlideRef.current.slideNumber;\n // The citation target rides the embed URL: the embed page parses the\n // anchor params and navigates (sheet range scroll/flash, PDF page). A\n // repeat click with a DIFFERENT target updates the tab's reference ->\n // new src -> the iframe reloads at the new range. Same target twice is a\n // no-op (already there).\n //\n // Deliberately does NOT set `athena_sdk_bridge=1` (buildSdkAssetEmbedUrl\n // is for AthenaAssetEmbed): that flag makes the embed page wait\n // indefinitely for a host config handshake that only AthenaAssetEmbed\n // implements — the panel's bare iframe never replies, so the embed would\n // hang on its loading bar forever.\n const iframeSrc = useMemo(() => {\n if (!embedUrl) return null;\n const base = buildAssetIframeSrc({\n embedUrl,\n assetType: tab.type,\n slideNumber: initialSlideNumber,\n });\n try {\n const url = new URL(base, window.location.href);\n appendCitationReferenceParams({ params: url.searchParams, reference: tab.reference });\n return url.toString();\n } catch {\n return base;\n }\n }, [embedUrl, initialSlideNumber, tab.type, tab.reference]);\n const navigationMessage = useMemo(\n () =>\n buildPresentationNavigationMessage({\n assetId: tab.id,\n assetType: tab.type,\n slideNumber: tab.slideNumber,\n }),\n [tab.id, tab.slideNumber, tab.type],\n );\n const navigationTargetOrigin = useMemo(() => {\n if (!iframeSrc) return null;\n\n try {\n return new URL(iframeSrc, window.location.href).origin;\n } catch {\n return null;\n }\n }, [iframeSrc]);\n const postNavigationMessage = useCallback(() => {\n if (!navigationMessage || !navigationTargetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n navigationMessage,\n navigationTargetOrigin,\n );\n }, [navigationMessage, navigationTargetOrigin]);\n\n useEffect(() => {\n postNavigationMessage();\n }, [postNavigationMessage]);\n\n if (isLoading) {\n return (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"text-center\">\n <Loader2 className=\"mx-auto size-6 animate-spin text-muted-foreground\" />\n <p className=\"mt-2 text-xs text-muted-foreground\">Loading...</p>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <div className=\"max-w-sm text-center\">\n <AlertCircle className=\"mx-auto size-5 text-red-400\" />\n <p className=\"mt-1.5 text-xs font-medium text-foreground\">\n Failed to load\n </p>\n <p className=\"mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground\">\n {error}\n </p>\n </div>\n </div>\n );\n }\n\n if (!iframeSrc) return null;\n\n return (\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n frameBorder=\"0\"\n allow=\"clipboard-write; fullscreen\"\n title={tab.name ?? `Asset ${tab.id}`}\n className=\"h-full w-full\"\n onLoad={postNavigationMessage}\n />\n );\n },\n (prev, next) =>\n prev.tab.id === next.tab.id &&\n prev.tab.name === next.tab.name &&\n prev.tab.type === next.tab.type &&\n prev.tab.slideNumber === next.tab.slideNumber,\n);\n\nAssetIframe.displayName = \"AssetIframe\";\n\nexport interface AssetPanelProps {\n /** Register this panel as an asset-panel host when used outside AthenaLayout. */\n manageAssetPanelHostRegistration?: boolean;\n}\n\n/**\n * Content area — renders all iframes in the same tree.\n * Tab mode: only active tab visible via CSS. Tiled mode: CSS grid. Iframes never unmount on switch.\n */\nconst PanelContent: FC<{ manageAssetPanelHostRegistration: boolean }> = ({\n manageAssetPanelHostRegistration,\n}) => {\n const {\n tabs,\n activeTabId,\n viewMode,\n closeTab,\n registerAssetPanelHost,\n unregisterAssetPanelHost,\n } =\n useAssetPanelStore();\n const isTiled = viewMode === \"tiled\" && tabs.length >= 2;\n\n useEffect(() => {\n if (!manageAssetPanelHostRegistration) {\n return;\n }\n\n registerAssetPanelHost();\n return () => {\n unregisterAssetPanelHost();\n };\n }, [manageAssetPanelHostRegistration, registerAssetPanelHost, unregisterAssetPanelHost]);\n\n const gridClass = useMemo(() => {\n const n = tabs.length;\n if (n <= 1) return \"\";\n if (n === 2) return \"grid grid-cols-2 grid-rows-1\";\n if (n <= 4) return \"grid grid-cols-2 grid-rows-2\";\n if (n <= 6) return \"grid grid-cols-3 grid-rows-2\";\n return \"grid grid-cols-3 grid-rows-3\";\n }, [tabs.length]);\n\n return (\n <div\n className={`flex-1 overflow-hidden ${isTiled ? `${gridClass} gap-px bg-border/60` : \"\"}`}\n >\n {tabs.map((tab) => {\n const isActive = tab.id === activeTabId;\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n\n if (isTiled) {\n return (\n <div\n key={tab.id}\n className=\"flex min-h-0 min-w-0 flex-col bg-background\"\n >\n <div className=\"flex shrink-0 items-center gap-1.5 border-b px-2 py-1\">\n <TypeIcon className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate text-[11px] font-medium text-foreground\">\n {tab.name ?? config.label}\n </span>\n <button\n onClick={() => closeTab(tab.id)}\n className=\"shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-hidden\">\n <AssetIframe tab={tab} />\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={tab.id}\n className={isActive ? \"h-full w-full\" : \"hidden\"}\n >\n <AssetIframe tab={tab} />\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Tab bar for tab mode — scrollable row of tabs. */\nconst TabBar: FC = () => {\n const { tabs, activeTabId, setActiveTab, closeTab, viewMode } =\n useAssetPanelStore();\n\n if (tabs.length <= 1 || viewMode === \"tiled\") return null;\n\n return (\n <div className=\"flex shrink-0 items-center gap-0 overflow-x-auto border-b bg-muted/30\">\n {tabs.map((tab) => {\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n const isActive = tab.id === activeTabId;\n\n return (\n <div\n key={tab.id}\n className={`group flex max-w-[180px] shrink-0 cursor-pointer items-center gap-1.5 border-r border-border/40 px-3 py-1.5 text-xs ${\n isActive\n ? \"border-b-2 border-b-primary bg-background text-foreground\"\n : \"text-muted-foreground hover:bg-background/50 hover:text-foreground\"\n }`}\n onClick={() => setActiveTab(tab.id)}\n >\n <TypeIcon className=\"size-3 shrink-0\" />\n <span className=\"truncate\">{tab.name ?? config.label}</span>\n <button\n onClick={(e) => {\n e.stopPropagation();\n closeTab(tab.id);\n }}\n className=\"ml-auto shrink-0 rounded p-0.5 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Header with active tab info + panel controls. */\nconst PanelHeader: FC<{ fullscreen?: boolean }> = ({ fullscreen }) => {\n const {\n closePanel,\n toggleFullscreen,\n tabs,\n activeTabId,\n viewMode,\n setViewMode,\n } = useAssetPanelStore();\n const activeTab = tabs.find((t) => t.id === activeTabId);\n const config = ASSET_TYPE_CONFIG[activeTab?.type ?? \"unknown\"];\n const TypeIcon = config.icon;\n const isTiled = viewMode === \"tiled\";\n\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b px-4 py-2.5\">\n {!isTiled && (\n <TypeIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <p className=\"flex-1 truncate text-sm font-semibold text-foreground\">\n {isTiled\n ? `${tabs.length} Assets`\n : activeTab?.name ?? config.label}\n </p>\n\n {tabs.length >= 2 && (\n <button\n onClick={() => setViewMode(isTiled ? \"tabs\" : \"tiled\")}\n className={`flex size-7 items-center justify-center rounded-lg transition-colors ${\n isTiled\n ? \"bg-primary/10 text-primary\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\"\n }`}\n title={isTiled ? \"Switch to tabs\" : \"Tile all assets\"}\n >\n {isTiled ? (\n <Layers className=\"size-3.5\" />\n ) : (\n <LayoutGrid className=\"size-3.5\" />\n )}\n </button>\n )}\n\n <button\n onClick={toggleFullscreen}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title={fullscreen ? \"Exit fullscreen\" : \"Fullscreen\"}\n >\n {fullscreen ? (\n <Minimize2 className=\"size-3.5\" />\n ) : (\n <Maximize2 className=\"size-3.5\" />\n )}\n </button>\n <button\n onClick={closePanel}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title=\"Close all\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n );\n};\n\nexport const AssetPanel: FC<AssetPanelProps> = ({\n manageAssetPanelHostRegistration = true,\n}) => {\n const isFullscreen = useAssetPanelStore((s) => s.isFullscreen);\n\n const content = (\n <>\n <PanelHeader fullscreen={isFullscreen} />\n <TabBar />\n <PanelContent manageAssetPanelHostRegistration={manageAssetPanelHostRegistration} />\n </>\n );\n\n if (isFullscreen) {\n return (\n <div className=\"fixed inset-0 z-50 flex flex-col bg-background\">\n {content}\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full flex-col bg-background\">{content}</div>\n );\n};\n"],"names":["Presentation","FileSpreadsheet","FileText","BookOpen","File","memo","useRef","useAthenaConfig","useAssetEmbed","useMemo","buildAssetIframeSrc","appendCitationReferenceParams","buildPresentationNavigationMessage","useCallback","useEffect","jsxs","jsx","Loader2","AlertCircle","useAssetPanelStore","X","Layers","LayoutGrid","Minimize2","Maximize2","Fragment"],"mappings":"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"}
@@ -97,7 +97,7 @@ const AssetIframe = memo(
97
97
  width: "100%",
98
98
  height: "100%",
99
99
  frameBorder: "0",
100
- allow: "fullscreen",
100
+ allow: "clipboard-write; fullscreen",
101
101
  title: tab.name ?? `Asset ${tab.id}`,
102
102
  className: "h-full w-full",
103
103
  onLoad: postNavigationMessage
@@ -1 +1 @@
1
- {"version":3,"file":"AssetPanel.js","sources":["../../src/assets/AssetPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FC, memo, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport {\n X,\n Loader2,\n AlertCircle,\n Maximize2,\n Minimize2,\n FileText,\n FileSpreadsheet,\n Presentation,\n File,\n BookOpen,\n LayoutGrid,\n Layers,\n} from \"lucide-react\";\nimport { appendCitationReferenceParams, useAssetEmbed } from \"./use-asset-embed\";\nimport {\n useAssetPanelStore,\n type AssetTab,\n type AssetType,\n} from \"./asset-panel-store\";\nimport {\n buildAssetIframeSrc,\n buildPresentationNavigationMessage,\n} from \"./asset-panel-url\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\n\nconst ASSET_TYPE_CONFIG: Record<\n AssetType,\n { icon: typeof File; label: string }\n> = {\n presentation: { icon: Presentation, label: \"Presentation\" },\n spreadsheet: { icon: FileSpreadsheet, label: \"Spreadsheet\" },\n document: { icon: FileText, label: \"Document\" },\n notebook: { icon: BookOpen, label: \"Notebook\" },\n unknown: { icon: File, label: \"Asset\" },\n};\n\n/** Memoized iframe for a single asset — only re-renders when iframe inputs change. */\nconst AssetIframe = memo<{ tab: AssetTab }>(\n ({ tab }) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const { backendUrl, appUrl, apiKey, token } = useAthenaConfig();\n const { embedUrl, isLoading, error } = useAssetEmbed(tab.id, {\n backendUrl,\n appUrl,\n apiKey,\n token,\n });\n const initialSlideRef = useRef<{\n assetId: string;\n slideNumber?: number;\n }>({\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n });\n if (initialSlideRef.current.assetId !== tab.id) {\n initialSlideRef.current = {\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n };\n }\n const initialSlideNumber = initialSlideRef.current.slideNumber;\n // The citation target rides the embed URL: the embed page parses the\n // anchor params and navigates (sheet range scroll/flash, PDF page). A\n // repeat click with a DIFFERENT target updates the tab's reference ->\n // new src -> the iframe reloads at the new range. Same target twice is a\n // no-op (already there).\n //\n // Deliberately does NOT set `athena_sdk_bridge=1` (buildSdkAssetEmbedUrl\n // is for AthenaAssetEmbed): that flag makes the embed page wait\n // indefinitely for a host config handshake that only AthenaAssetEmbed\n // implements — the panel's bare iframe never replies, so the embed would\n // hang on its loading bar forever.\n const iframeSrc = useMemo(() => {\n if (!embedUrl) return null;\n const base = buildAssetIframeSrc({\n embedUrl,\n assetType: tab.type,\n slideNumber: initialSlideNumber,\n });\n try {\n const url = new URL(base, window.location.href);\n appendCitationReferenceParams({ params: url.searchParams, reference: tab.reference });\n return url.toString();\n } catch {\n return base;\n }\n }, [embedUrl, initialSlideNumber, tab.type, tab.reference]);\n const navigationMessage = useMemo(\n () =>\n buildPresentationNavigationMessage({\n assetId: tab.id,\n assetType: tab.type,\n slideNumber: tab.slideNumber,\n }),\n [tab.id, tab.slideNumber, tab.type],\n );\n const navigationTargetOrigin = useMemo(() => {\n if (!iframeSrc) return null;\n\n try {\n return new URL(iframeSrc, window.location.href).origin;\n } catch {\n return null;\n }\n }, [iframeSrc]);\n const postNavigationMessage = useCallback(() => {\n if (!navigationMessage || !navigationTargetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n navigationMessage,\n navigationTargetOrigin,\n );\n }, [navigationMessage, navigationTargetOrigin]);\n\n useEffect(() => {\n postNavigationMessage();\n }, [postNavigationMessage]);\n\n if (isLoading) {\n return (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"text-center\">\n <Loader2 className=\"mx-auto size-6 animate-spin text-muted-foreground\" />\n <p className=\"mt-2 text-xs text-muted-foreground\">Loading...</p>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <div className=\"max-w-sm text-center\">\n <AlertCircle className=\"mx-auto size-5 text-red-400\" />\n <p className=\"mt-1.5 text-xs font-medium text-foreground\">\n Failed to load\n </p>\n <p className=\"mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground\">\n {error}\n </p>\n </div>\n </div>\n );\n }\n\n if (!iframeSrc) return null;\n\n return (\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n frameBorder=\"0\"\n allow=\"fullscreen\"\n title={tab.name ?? `Asset ${tab.id}`}\n className=\"h-full w-full\"\n onLoad={postNavigationMessage}\n />\n );\n },\n (prev, next) =>\n prev.tab.id === next.tab.id &&\n prev.tab.name === next.tab.name &&\n prev.tab.type === next.tab.type &&\n prev.tab.slideNumber === next.tab.slideNumber,\n);\n\nAssetIframe.displayName = \"AssetIframe\";\n\nexport interface AssetPanelProps {\n /** Register this panel as an asset-panel host when used outside AthenaLayout. */\n manageAssetPanelHostRegistration?: boolean;\n}\n\n/**\n * Content area — renders all iframes in the same tree.\n * Tab mode: only active tab visible via CSS. Tiled mode: CSS grid. Iframes never unmount on switch.\n */\nconst PanelContent: FC<{ manageAssetPanelHostRegistration: boolean }> = ({\n manageAssetPanelHostRegistration,\n}) => {\n const {\n tabs,\n activeTabId,\n viewMode,\n closeTab,\n registerAssetPanelHost,\n unregisterAssetPanelHost,\n } =\n useAssetPanelStore();\n const isTiled = viewMode === \"tiled\" && tabs.length >= 2;\n\n useEffect(() => {\n if (!manageAssetPanelHostRegistration) {\n return;\n }\n\n registerAssetPanelHost();\n return () => {\n unregisterAssetPanelHost();\n };\n }, [manageAssetPanelHostRegistration, registerAssetPanelHost, unregisterAssetPanelHost]);\n\n const gridClass = useMemo(() => {\n const n = tabs.length;\n if (n <= 1) return \"\";\n if (n === 2) return \"grid grid-cols-2 grid-rows-1\";\n if (n <= 4) return \"grid grid-cols-2 grid-rows-2\";\n if (n <= 6) return \"grid grid-cols-3 grid-rows-2\";\n return \"grid grid-cols-3 grid-rows-3\";\n }, [tabs.length]);\n\n return (\n <div\n className={`flex-1 overflow-hidden ${isTiled ? `${gridClass} gap-px bg-border/60` : \"\"}`}\n >\n {tabs.map((tab) => {\n const isActive = tab.id === activeTabId;\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n\n if (isTiled) {\n return (\n <div\n key={tab.id}\n className=\"flex min-h-0 min-w-0 flex-col bg-background\"\n >\n <div className=\"flex shrink-0 items-center gap-1.5 border-b px-2 py-1\">\n <TypeIcon className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate text-[11px] font-medium text-foreground\">\n {tab.name ?? config.label}\n </span>\n <button\n onClick={() => closeTab(tab.id)}\n className=\"shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-hidden\">\n <AssetIframe tab={tab} />\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={tab.id}\n className={isActive ? \"h-full w-full\" : \"hidden\"}\n >\n <AssetIframe tab={tab} />\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Tab bar for tab mode — scrollable row of tabs. */\nconst TabBar: FC = () => {\n const { tabs, activeTabId, setActiveTab, closeTab, viewMode } =\n useAssetPanelStore();\n\n if (tabs.length <= 1 || viewMode === \"tiled\") return null;\n\n return (\n <div className=\"flex shrink-0 items-center gap-0 overflow-x-auto border-b bg-muted/30\">\n {tabs.map((tab) => {\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n const isActive = tab.id === activeTabId;\n\n return (\n <div\n key={tab.id}\n className={`group flex max-w-[180px] shrink-0 cursor-pointer items-center gap-1.5 border-r border-border/40 px-3 py-1.5 text-xs ${\n isActive\n ? \"border-b-2 border-b-primary bg-background text-foreground\"\n : \"text-muted-foreground hover:bg-background/50 hover:text-foreground\"\n }`}\n onClick={() => setActiveTab(tab.id)}\n >\n <TypeIcon className=\"size-3 shrink-0\" />\n <span className=\"truncate\">{tab.name ?? config.label}</span>\n <button\n onClick={(e) => {\n e.stopPropagation();\n closeTab(tab.id);\n }}\n className=\"ml-auto shrink-0 rounded p-0.5 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Header with active tab info + panel controls. */\nconst PanelHeader: FC<{ fullscreen?: boolean }> = ({ fullscreen }) => {\n const {\n closePanel,\n toggleFullscreen,\n tabs,\n activeTabId,\n viewMode,\n setViewMode,\n } = useAssetPanelStore();\n const activeTab = tabs.find((t) => t.id === activeTabId);\n const config = ASSET_TYPE_CONFIG[activeTab?.type ?? \"unknown\"];\n const TypeIcon = config.icon;\n const isTiled = viewMode === \"tiled\";\n\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b px-4 py-2.5\">\n {!isTiled && (\n <TypeIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <p className=\"flex-1 truncate text-sm font-semibold text-foreground\">\n {isTiled\n ? `${tabs.length} Assets`\n : activeTab?.name ?? config.label}\n </p>\n\n {tabs.length >= 2 && (\n <button\n onClick={() => setViewMode(isTiled ? \"tabs\" : \"tiled\")}\n className={`flex size-7 items-center justify-center rounded-lg transition-colors ${\n isTiled\n ? \"bg-primary/10 text-primary\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\"\n }`}\n title={isTiled ? \"Switch to tabs\" : \"Tile all assets\"}\n >\n {isTiled ? (\n <Layers className=\"size-3.5\" />\n ) : (\n <LayoutGrid className=\"size-3.5\" />\n )}\n </button>\n )}\n\n <button\n onClick={toggleFullscreen}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title={fullscreen ? \"Exit fullscreen\" : \"Fullscreen\"}\n >\n {fullscreen ? (\n <Minimize2 className=\"size-3.5\" />\n ) : (\n <Maximize2 className=\"size-3.5\" />\n )}\n </button>\n <button\n onClick={closePanel}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title=\"Close all\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n );\n};\n\nexport const AssetPanel: FC<AssetPanelProps> = ({\n manageAssetPanelHostRegistration = true,\n}) => {\n const isFullscreen = useAssetPanelStore((s) => s.isFullscreen);\n\n const content = (\n <>\n <PanelHeader fullscreen={isFullscreen} />\n <TabBar />\n <PanelContent manageAssetPanelHostRegistration={manageAssetPanelHostRegistration} />\n </>\n );\n\n if (isFullscreen) {\n return (\n <div className=\"fixed inset-0 z-50 flex flex-col bg-background\">\n {content}\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full flex-col bg-background\">{content}</div>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AssetPanel.js","sources":["../../src/assets/AssetPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FC, memo, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport {\n X,\n Loader2,\n AlertCircle,\n Maximize2,\n Minimize2,\n FileText,\n FileSpreadsheet,\n Presentation,\n File,\n BookOpen,\n LayoutGrid,\n Layers,\n} from \"lucide-react\";\nimport { appendCitationReferenceParams, useAssetEmbed } from \"./use-asset-embed\";\nimport {\n useAssetPanelStore,\n type AssetTab,\n type AssetType,\n} from \"./asset-panel-store\";\nimport {\n buildAssetIframeSrc,\n buildPresentationNavigationMessage,\n} from \"./asset-panel-url\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\n\nconst ASSET_TYPE_CONFIG: Record<\n AssetType,\n { icon: typeof File; label: string }\n> = {\n presentation: { icon: Presentation, label: \"Presentation\" },\n spreadsheet: { icon: FileSpreadsheet, label: \"Spreadsheet\" },\n document: { icon: FileText, label: \"Document\" },\n notebook: { icon: BookOpen, label: \"Notebook\" },\n unknown: { icon: File, label: \"Asset\" },\n};\n\n/** Memoized iframe for a single asset — only re-renders when iframe inputs change. */\nconst AssetIframe = memo<{ tab: AssetTab }>(\n ({ tab }) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const { backendUrl, appUrl, apiKey, token } = useAthenaConfig();\n const { embedUrl, isLoading, error } = useAssetEmbed(tab.id, {\n backendUrl,\n appUrl,\n apiKey,\n token,\n });\n const initialSlideRef = useRef<{\n assetId: string;\n slideNumber?: number;\n }>({\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n });\n if (initialSlideRef.current.assetId !== tab.id) {\n initialSlideRef.current = {\n assetId: tab.id,\n slideNumber: tab.slideNumber,\n };\n }\n const initialSlideNumber = initialSlideRef.current.slideNumber;\n // The citation target rides the embed URL: the embed page parses the\n // anchor params and navigates (sheet range scroll/flash, PDF page). A\n // repeat click with a DIFFERENT target updates the tab's reference ->\n // new src -> the iframe reloads at the new range. Same target twice is a\n // no-op (already there).\n //\n // Deliberately does NOT set `athena_sdk_bridge=1` (buildSdkAssetEmbedUrl\n // is for AthenaAssetEmbed): that flag makes the embed page wait\n // indefinitely for a host config handshake that only AthenaAssetEmbed\n // implements — the panel's bare iframe never replies, so the embed would\n // hang on its loading bar forever.\n const iframeSrc = useMemo(() => {\n if (!embedUrl) return null;\n const base = buildAssetIframeSrc({\n embedUrl,\n assetType: tab.type,\n slideNumber: initialSlideNumber,\n });\n try {\n const url = new URL(base, window.location.href);\n appendCitationReferenceParams({ params: url.searchParams, reference: tab.reference });\n return url.toString();\n } catch {\n return base;\n }\n }, [embedUrl, initialSlideNumber, tab.type, tab.reference]);\n const navigationMessage = useMemo(\n () =>\n buildPresentationNavigationMessage({\n assetId: tab.id,\n assetType: tab.type,\n slideNumber: tab.slideNumber,\n }),\n [tab.id, tab.slideNumber, tab.type],\n );\n const navigationTargetOrigin = useMemo(() => {\n if (!iframeSrc) return null;\n\n try {\n return new URL(iframeSrc, window.location.href).origin;\n } catch {\n return null;\n }\n }, [iframeSrc]);\n const postNavigationMessage = useCallback(() => {\n if (!navigationMessage || !navigationTargetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n navigationMessage,\n navigationTargetOrigin,\n );\n }, [navigationMessage, navigationTargetOrigin]);\n\n useEffect(() => {\n postNavigationMessage();\n }, [postNavigationMessage]);\n\n if (isLoading) {\n return (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"text-center\">\n <Loader2 className=\"mx-auto size-6 animate-spin text-muted-foreground\" />\n <p className=\"mt-2 text-xs text-muted-foreground\">Loading...</p>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center p-4\">\n <div className=\"max-w-sm text-center\">\n <AlertCircle className=\"mx-auto size-5 text-red-400\" />\n <p className=\"mt-1.5 text-xs font-medium text-foreground\">\n Failed to load\n </p>\n <p className=\"mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground\">\n {error}\n </p>\n </div>\n </div>\n );\n }\n\n if (!iframeSrc) return null;\n\n return (\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n width=\"100%\"\n height=\"100%\"\n frameBorder=\"0\"\n allow=\"clipboard-write; fullscreen\"\n title={tab.name ?? `Asset ${tab.id}`}\n className=\"h-full w-full\"\n onLoad={postNavigationMessage}\n />\n );\n },\n (prev, next) =>\n prev.tab.id === next.tab.id &&\n prev.tab.name === next.tab.name &&\n prev.tab.type === next.tab.type &&\n prev.tab.slideNumber === next.tab.slideNumber,\n);\n\nAssetIframe.displayName = \"AssetIframe\";\n\nexport interface AssetPanelProps {\n /** Register this panel as an asset-panel host when used outside AthenaLayout. */\n manageAssetPanelHostRegistration?: boolean;\n}\n\n/**\n * Content area — renders all iframes in the same tree.\n * Tab mode: only active tab visible via CSS. Tiled mode: CSS grid. Iframes never unmount on switch.\n */\nconst PanelContent: FC<{ manageAssetPanelHostRegistration: boolean }> = ({\n manageAssetPanelHostRegistration,\n}) => {\n const {\n tabs,\n activeTabId,\n viewMode,\n closeTab,\n registerAssetPanelHost,\n unregisterAssetPanelHost,\n } =\n useAssetPanelStore();\n const isTiled = viewMode === \"tiled\" && tabs.length >= 2;\n\n useEffect(() => {\n if (!manageAssetPanelHostRegistration) {\n return;\n }\n\n registerAssetPanelHost();\n return () => {\n unregisterAssetPanelHost();\n };\n }, [manageAssetPanelHostRegistration, registerAssetPanelHost, unregisterAssetPanelHost]);\n\n const gridClass = useMemo(() => {\n const n = tabs.length;\n if (n <= 1) return \"\";\n if (n === 2) return \"grid grid-cols-2 grid-rows-1\";\n if (n <= 4) return \"grid grid-cols-2 grid-rows-2\";\n if (n <= 6) return \"grid grid-cols-3 grid-rows-2\";\n return \"grid grid-cols-3 grid-rows-3\";\n }, [tabs.length]);\n\n return (\n <div\n className={`flex-1 overflow-hidden ${isTiled ? `${gridClass} gap-px bg-border/60` : \"\"}`}\n >\n {tabs.map((tab) => {\n const isActive = tab.id === activeTabId;\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n\n if (isTiled) {\n return (\n <div\n key={tab.id}\n className=\"flex min-h-0 min-w-0 flex-col bg-background\"\n >\n <div className=\"flex shrink-0 items-center gap-1.5 border-b px-2 py-1\">\n <TypeIcon className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate text-[11px] font-medium text-foreground\">\n {tab.name ?? config.label}\n </span>\n <button\n onClick={() => closeTab(tab.id)}\n className=\"shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-hidden\">\n <AssetIframe tab={tab} />\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={tab.id}\n className={isActive ? \"h-full w-full\" : \"hidden\"}\n >\n <AssetIframe tab={tab} />\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Tab bar for tab mode — scrollable row of tabs. */\nconst TabBar: FC = () => {\n const { tabs, activeTabId, setActiveTab, closeTab, viewMode } =\n useAssetPanelStore();\n\n if (tabs.length <= 1 || viewMode === \"tiled\") return null;\n\n return (\n <div className=\"flex shrink-0 items-center gap-0 overflow-x-auto border-b bg-muted/30\">\n {tabs.map((tab) => {\n const config = ASSET_TYPE_CONFIG[tab.type];\n const TypeIcon = config.icon;\n const isActive = tab.id === activeTabId;\n\n return (\n <div\n key={tab.id}\n className={`group flex max-w-[180px] shrink-0 cursor-pointer items-center gap-1.5 border-r border-border/40 px-3 py-1.5 text-xs ${\n isActive\n ? \"border-b-2 border-b-primary bg-background text-foreground\"\n : \"text-muted-foreground hover:bg-background/50 hover:text-foreground\"\n }`}\n onClick={() => setActiveTab(tab.id)}\n >\n <TypeIcon className=\"size-3 shrink-0\" />\n <span className=\"truncate\">{tab.name ?? config.label}</span>\n <button\n onClick={(e) => {\n e.stopPropagation();\n closeTab(tab.id);\n }}\n className=\"ml-auto shrink-0 rounded p-0.5 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100\"\n >\n <X className=\"size-2.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n};\n\n/** Header with active tab info + panel controls. */\nconst PanelHeader: FC<{ fullscreen?: boolean }> = ({ fullscreen }) => {\n const {\n closePanel,\n toggleFullscreen,\n tabs,\n activeTabId,\n viewMode,\n setViewMode,\n } = useAssetPanelStore();\n const activeTab = tabs.find((t) => t.id === activeTabId);\n const config = ASSET_TYPE_CONFIG[activeTab?.type ?? \"unknown\"];\n const TypeIcon = config.icon;\n const isTiled = viewMode === \"tiled\";\n\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b px-4 py-2.5\">\n {!isTiled && (\n <TypeIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <p className=\"flex-1 truncate text-sm font-semibold text-foreground\">\n {isTiled\n ? `${tabs.length} Assets`\n : activeTab?.name ?? config.label}\n </p>\n\n {tabs.length >= 2 && (\n <button\n onClick={() => setViewMode(isTiled ? \"tabs\" : \"tiled\")}\n className={`flex size-7 items-center justify-center rounded-lg transition-colors ${\n isTiled\n ? \"bg-primary/10 text-primary\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\"\n }`}\n title={isTiled ? \"Switch to tabs\" : \"Tile all assets\"}\n >\n {isTiled ? (\n <Layers className=\"size-3.5\" />\n ) : (\n <LayoutGrid className=\"size-3.5\" />\n )}\n </button>\n )}\n\n <button\n onClick={toggleFullscreen}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title={fullscreen ? \"Exit fullscreen\" : \"Fullscreen\"}\n >\n {fullscreen ? (\n <Minimize2 className=\"size-3.5\" />\n ) : (\n <Maximize2 className=\"size-3.5\" />\n )}\n </button>\n <button\n onClick={closePanel}\n className=\"flex size-7 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n title=\"Close all\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n );\n};\n\nexport const AssetPanel: FC<AssetPanelProps> = ({\n manageAssetPanelHostRegistration = true,\n}) => {\n const isFullscreen = useAssetPanelStore((s) => s.isFullscreen);\n\n const content = (\n <>\n <PanelHeader fullscreen={isFullscreen} />\n <TabBar />\n <PanelContent manageAssetPanelHostRegistration={manageAssetPanelHostRegistration} />\n </>\n );\n\n if (isFullscreen) {\n return (\n <div className=\"fixed inset-0 z-50 flex flex-col bg-background\">\n {content}\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full flex-col bg-background\">{content}</div>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA6BA,MAAM,oBAGF;AAAA,EACF,cAAc,EAAE,MAAM,cAAc,OAAO,eAAA;AAAA,EAC3C,aAAa,EAAE,MAAM,iBAAiB,OAAO,cAAA;AAAA,EAC7C,UAAU,EAAE,MAAM,UAAU,OAAO,WAAA;AAAA,EACnC,UAAU,EAAE,MAAM,UAAU,OAAO,WAAA;AAAA,EACnC,SAAS,EAAE,MAAM,MAAM,OAAO,QAAA;AAChC;AAGA,MAAM,cAAc;AAAA,EAClB,CAAC,EAAE,IAAA,MAAU;AACX,UAAM,YAAY,OAAiC,IAAI;AACvD,UAAM,EAAE,YAAY,QAAQ,QAAQ,MAAA,IAAU,gBAAA;AAC9C,UAAM,EAAE,UAAU,WAAW,UAAU,cAAc,IAAI,IAAI;AAAA,MAC3D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;AACD,UAAM,kBAAkB,OAGrB;AAAA,MACD,SAAS,IAAI;AAAA,MACb,aAAa,IAAI;AAAA,IAAA,CAClB;AACD,QAAI,gBAAgB,QAAQ,YAAY,IAAI,IAAI;AAC9C,sBAAgB,UAAU;AAAA,QACxB,SAAS,IAAI;AAAA,QACb,aAAa,IAAI;AAAA,MAAA;AAAA,IAErB;AACA,UAAM,qBAAqB,gBAAgB,QAAQ;AAYnD,UAAM,YAAY,QAAQ,MAAM;AAC9B,UAAI,CAAC,SAAU,QAAO;AACtB,YAAM,OAAO,oBAAoB;AAAA,QAC/B;AAAA,QACA,WAAW,IAAI;AAAA,QACf,aAAa;AAAA,MAAA,CACd;AACD,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,MAAM,OAAO,SAAS,IAAI;AAC9C,sCAA8B,EAAE,QAAQ,IAAI,cAAc,WAAW,IAAI,WAAW;AACpF,eAAO,IAAI,SAAA;AAAA,MACb,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG,CAAC,UAAU,oBAAoB,IAAI,MAAM,IAAI,SAAS,CAAC;AAC1D,UAAM,oBAAoB;AAAA,MACxB,MACE,mCAAmC;AAAA,QACjC,SAAS,IAAI;AAAA,QACb,WAAW,IAAI;AAAA,QACf,aAAa,IAAI;AAAA,MAAA,CAClB;AAAA,MACH,CAAC,IAAI,IAAI,IAAI,aAAa,IAAI,IAAI;AAAA,IAAA;AAEpC,UAAM,yBAAyB,QAAQ,MAAM;AAC3C,UAAI,CAAC,UAAW,QAAO;AAEvB,UAAI;AACF,eAAO,IAAI,IAAI,WAAW,OAAO,SAAS,IAAI,EAAE;AAAA,MAClD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG,CAAC,SAAS,CAAC;AACd,UAAM,wBAAwB,YAAY,MAAM;;AAC9C,UAAI,CAAC,qBAAqB,CAAC,uBAAwB;AACnD,4BAAU,YAAV,mBAAmB,kBAAnB,mBAAkC;AAAA,QAChC;AAAA,QACA;AAAA;AAAA,IAEJ,GAAG,CAAC,mBAAmB,sBAAsB,CAAC;AAE9C,cAAU,MAAM;AACd,4BAAA;AAAA,IACF,GAAG,CAAC,qBAAqB,CAAC;AAE1B,QAAI,WAAW;AACb,iCACG,OAAA,EAAI,WAAU,2CACb,UAAA,qBAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,QAAA,oBAAC,SAAA,EAAQ,WAAU,oDAAA,CAAoD;AAAA,QACvE,oBAAC,KAAA,EAAE,WAAU,sCAAqC,UAAA,aAAA,CAAU;AAAA,MAAA,EAAA,CAC9D,EAAA,CACF;AAAA,IAEJ;AAEA,QAAI,OAAO;AACT,iCACG,OAAA,EAAI,WAAU,+CACb,UAAA,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,QAAA,oBAAC,aAAA,EAAY,WAAU,8BAAA,CAA8B;AAAA,QACrD,oBAAC,KAAA,EAAE,WAAU,8CAA6C,UAAA,kBAE1D;AAAA,QACA,oBAAC,KAAA,EAAE,WAAU,qEACV,UAAA,MAAA,CACH;AAAA,MAAA,EAAA,CACF,EAAA,CACF;AAAA,IAEJ;AAEA,QAAI,CAAC,UAAW,QAAO;AAEvB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK;AAAA,QACL,OAAM;AAAA,QACN,QAAO;AAAA,QACP,aAAY;AAAA,QACZ,OAAM;AAAA,QACN,OAAO,IAAI,QAAQ,SAAS,IAAI,EAAE;AAAA,QAClC,WAAU;AAAA,QACV,QAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAGd;AAAA,EACA,CAAC,MAAM,SACL,KAAK,IAAI,OAAO,KAAK,IAAI,MACzB,KAAK,IAAI,SAAS,KAAK,IAAI,QAC3B,KAAK,IAAI,SAAS,KAAK,IAAI,QAC3B,KAAK,IAAI,gBAAgB,KAAK,IAAI;AACtC;AAEA,YAAY,cAAc;AAW1B,MAAM,eAAkE,CAAC;AAAA,EACvE;AACF,MAAM;AACJ,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IAEA,mBAAA;AACF,QAAM,UAAU,aAAa,WAAW,KAAK,UAAU;AAEvD,YAAU,MAAM;AACd,QAAI,CAAC,kCAAkC;AACrC;AAAA,IACF;AAEA,2BAAA;AACA,WAAO,MAAM;AACX,+BAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kCAAkC,wBAAwB,wBAAwB,CAAC;AAEvF,QAAM,YAAY,QAAQ,MAAM;AAC9B,UAAM,IAAI,KAAK;AACf,QAAI,KAAK,EAAG,QAAO;AACnB,QAAI,MAAM,EAAG,QAAO;AACpB,QAAI,KAAK,EAAG,QAAO;AACnB,QAAI,KAAK,EAAG,QAAO;AACnB,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,MAAM,CAAC;AAEhB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,0BAA0B,UAAU,GAAG,SAAS,yBAAyB,EAAE;AAAA,MAErF,UAAA,KAAK,IAAI,CAAC,QAAQ;AACjB,cAAM,WAAW,IAAI,OAAO;AAC5B,cAAM,SAAS,kBAAkB,IAAI,IAAI;AACzC,cAAM,WAAW,OAAO;AAExB,YAAI,SAAS;AACX,iBACE;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,WAAU;AAAA,cAEV,UAAA;AAAA,gBAAA,qBAAC,OAAA,EAAI,WAAU,yDACb,UAAA;AAAA,kBAAA,oBAAC,UAAA,EAAS,WAAU,wCAAA,CAAwC;AAAA,sCAC3D,QAAA,EAAK,WAAU,2DACb,UAAA,IAAI,QAAQ,OAAO,OACtB;AAAA,kBACA;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,sBAC9B,WAAU;AAAA,sBAEV,UAAA,oBAAC,GAAA,EAAE,WAAU,WAAA,CAAW;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBAC1B,GACF;AAAA,oCACC,OAAA,EAAI,WAAU,0BACb,UAAA,oBAAC,aAAA,EAAY,KAAU,EAAA,CACzB;AAAA,cAAA;AAAA,YAAA;AAAA,YAjBK,IAAI;AAAA,UAAA;AAAA,QAoBf;AAEA,eACE;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAW,WAAW,kBAAkB;AAAA,YAExC,UAAA,oBAAC,eAAY,IAAA,CAAU;AAAA,UAAA;AAAA,UAHlB,IAAI;AAAA,QAAA;AAAA,MAMf,CAAC;AAAA,IAAA;AAAA,EAAA;AAGP;AAGA,MAAM,SAAa,MAAM;AACvB,QAAM,EAAE,MAAM,aAAa,cAAc,UAAU,SAAA,IACjD,mBAAA;AAEF,MAAI,KAAK,UAAU,KAAK,aAAa,QAAS,QAAO;AAErD,6BACG,OAAA,EAAI,WAAU,yEACZ,UAAA,KAAK,IAAI,CAAC,QAAQ;AACjB,UAAM,SAAS,kBAAkB,IAAI,IAAI;AACzC,UAAM,WAAW,OAAO;AACxB,UAAM,WAAW,IAAI,OAAO;AAE5B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,WAAW,uHACT,WACI,8DACA,oEACN;AAAA,QACA,SAAS,MAAM,aAAa,IAAI,EAAE;AAAA,QAElC,UAAA;AAAA,UAAA,oBAAC,UAAA,EAAS,WAAU,kBAAA,CAAkB;AAAA,8BACrC,QAAA,EAAK,WAAU,YAAY,UAAA,IAAI,QAAQ,OAAO,OAAM;AAAA,UACrD;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SAAS,CAAC,MAAM;AACd,kBAAE,gBAAA;AACF,yBAAS,IAAI,EAAE;AAAA,cACjB;AAAA,cACA,WAAU;AAAA,cAEV,UAAA,oBAAC,GAAA,EAAE,WAAU,WAAA,CAAW;AAAA,YAAA;AAAA,UAAA;AAAA,QAC1B;AAAA,MAAA;AAAA,MAlBK,IAAI;AAAA,IAAA;AAAA,EAqBf,CAAC,EAAA,CACH;AAEJ;AAGA,MAAM,cAA4C,CAAC,EAAE,iBAAiB;AACpE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE,mBAAA;AACJ,QAAM,YAAY,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,WAAW;AACvD,QAAM,SAAS,mBAAkB,uCAAW,SAAQ,SAAS;AAC7D,QAAM,WAAW,OAAO;AACxB,QAAM,UAAU,aAAa;AAE7B,SACE,qBAAC,OAAA,EAAI,WAAU,yDACZ,UAAA;AAAA,IAAA,CAAC,WACA,oBAAC,UAAA,EAAS,WAAU,wCAAA,CAAwC;AAAA,IAE9D,oBAAC,KAAA,EAAE,WAAU,yDACV,UAAA,UACG,GAAG,KAAK,MAAM,aACd,uCAAW,SAAQ,OAAO,OAChC;AAAA,IAEC,KAAK,UAAU,KACd;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS,MAAM,YAAY,UAAU,SAAS,OAAO;AAAA,QACrD,WAAW,wEACT,UACI,+BACA,6DACN;AAAA,QACA,OAAO,UAAU,mBAAmB;AAAA,QAEnC,UAAA,8BACE,QAAA,EAAO,WAAU,YAAW,IAE7B,oBAAC,YAAA,EAAW,WAAU,WAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,IAKvC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAU;AAAA,QACV,OAAO,aAAa,oBAAoB;AAAA,QAEvC,UAAA,iCACE,WAAA,EAAU,WAAU,YAAW,IAEhC,oBAAC,WAAA,EAAU,WAAU,WAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,IAGpC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAU;AAAA,QACV,OAAM;AAAA,QAEN,UAAA,oBAAC,GAAA,EAAE,WAAU,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EACxB,GACF;AAEJ;AAEO,MAAM,aAAkC,CAAC;AAAA,EAC9C,mCAAmC;AACrC,MAAM;AACJ,QAAM,eAAe,mBAAmB,CAAC,MAAM,EAAE,YAAY;AAE7D,QAAM,UACJ,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA,oBAAC,aAAA,EAAY,YAAY,aAAA,CAAc;AAAA,wBACtC,QAAA,EAAO;AAAA,IACR,oBAAC,gBAAa,iCAAA,CAAoE;AAAA,EAAA,GACpF;AAGF,MAAI,cAAc;AAChB,WACE,oBAAC,OAAA,EAAI,WAAU,kDACZ,UAAA,SACH;AAAA,EAEJ;AAEA,SACE,oBAAC,OAAA,EAAI,WAAU,sCAAsC,UAAA,SAAQ;AAEjE;"}
@@ -30,7 +30,7 @@ const AthenaAssetEmbed = ({
30
30
  className,
31
31
  style,
32
32
  title,
33
- allow = "fullscreen",
33
+ allow = "clipboard-write; fullscreen",
34
34
  ...iframeProps
35
35
  }) => {
36
36
  const iframeRef = react.useRef(null);
@@ -1 +1 @@
1
- {"version":3,"file":"AthenaAssetEmbed.cjs","sources":["../../src/assets/AthenaAssetEmbed.tsx"],"sourcesContent":["\"use client\";\n\nimport { AlertCircle, Loader2 } from \"lucide-react\";\nimport { type CSSProperties, type FC, type IframeHTMLAttributes, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\nimport {\n ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n type AthenaAssetCitationActionEvent,\n type AthenaAssetCitationBehavior,\n type AthenaAssetCitationClickEvent,\n type AthenaAssetCitationReference,\n isAthenaAssetCitationActionEvent,\n isAthenaAssetCitationClickEvent,\n isAthenaAssetEmbedReadyEvent,\n resolveAthenaAssetCitationActionBehavior,\n resolveAthenaAssetCitationBehavior,\n} from \"./asset-embed-messages\";\nimport {\n buildSdkAssetEmbedUrl,\n DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n DEFAULT_ASSET_EMBED_READ_ONLY,\n useAssetEmbed,\n} from \"./use-asset-embed\";\n\nexport interface AthenaAssetEmbedProps extends Omit<\n IframeHTMLAttributes<HTMLIFrameElement>,\n \"src\" | \"onError\" | \"onLoad\"\n> {\n assetId: string;\n /** Optional citation target to open inside the embedded asset, such as a PDF page. */\n reference?: AthenaAssetCitationReference;\n /** Defaults to the native full asset experience. */\n displayMode?: \"minimal\" | \"full\";\n /** Defaults to false so authorized users can edit the embedded asset. */\n readOnly?: boolean;\n expiresInSeconds?: number;\n citationBehavior?: AthenaAssetCitationBehavior;\n onCitationClick?: (event: AthenaAssetCitationClickEvent) => void;\n /** Controls the citation popover's actions, including the (+) Open in Spaces button. */\n citationActionBehavior?: AthenaAssetCitationBehavior;\n onCitationAction?: (event: AthenaAssetCitationActionEvent) => void;\n onLoad?: () => void;\n onError?: (error: Error) => void;\n loadingFallback?: React.ReactNode;\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: 0,\n};\nconst AUTH_SYNC_INTERVAL_MS = 60_000;\n\nexport const AthenaAssetEmbed: FC<AthenaAssetEmbedProps> = ({\n assetId,\n reference,\n displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,\n expiresInSeconds,\n citationBehavior,\n onCitationClick,\n citationActionBehavior,\n onCitationAction,\n onLoad,\n onError,\n loadingFallback,\n errorFallback,\n className,\n style,\n title,\n allow = \"fullscreen\",\n ...iframeProps\n}) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const athenaConfig = useAthenaConfig();\n const { backendUrl, appUrl, apiKey } = athenaConfig;\n const { embedUrl, isLoading, error } = useAssetEmbed(assetId, {\n backendUrl,\n appUrl,\n apiKey,\n token: athenaConfig.token,\n readOnly,\n expiresInSeconds,\n displayMode,\n });\n const targetOrigin = useMemo(() => {\n if (!embedUrl) return null;\n try {\n return new URL(embedUrl, window.location.href).origin;\n } catch {\n return null;\n }\n }, [embedUrl]);\n const iframeSrc = useMemo(\n () => (embedUrl ? buildSdkAssetEmbedUrl(embedUrl, reference) : null),\n [embedUrl, reference],\n );\n const effectiveCitationBehavior = resolveAthenaAssetCitationBehavior({\n citationBehavior,\n hasCitationClickHandler: !!onCitationClick,\n });\n const effectiveCitationActionBehavior = resolveAthenaAssetCitationActionBehavior({\n citationActionBehavior,\n hasCitationActionHandler: !!onCitationAction,\n });\n\n const sendConfig = useCallback(() => {\n if (!targetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n version: 1,\n ...(athenaConfig.token ? { token: athenaConfig.token } : {}),\n citationBehavior: effectiveCitationBehavior,\n citationActionBehavior: effectiveCitationActionBehavior,\n },\n targetOrigin,\n );\n }, [athenaConfig, effectiveCitationActionBehavior, effectiveCitationBehavior, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl || !targetOrigin) return;\n const handleMessage = (event: MessageEvent<unknown>) => {\n if (event.origin !== targetOrigin || event.source !== iframeRef.current?.contentWindow) return;\n if (isAthenaAssetEmbedReadyEvent(event.data)) {\n sendConfig();\n return;\n }\n if (isAthenaAssetCitationClickEvent(event.data)) {\n onCitationClick?.(event.data);\n return;\n }\n if (isAthenaAssetCitationActionEvent(event.data)) {\n onCitationAction?.(event.data);\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [embedUrl, onCitationAction, onCitationClick, sendConfig, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl) return;\n sendConfig();\n const interval = window.setInterval(sendConfig, AUTH_SYNC_INTERVAL_MS);\n return () => window.clearInterval(interval);\n }, [embedUrl, sendConfig]);\n\n useEffect(() => {\n if (error) onError?.(new Error(error));\n }, [error, onError]);\n\n if (isLoading) {\n return (\n loadingFallback ?? (\n <output className=\"athena-sdk-chrome flex h-full w-full items-center justify-center\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n <span className=\"sr-only\">Loading asset</span>\n </output>\n )\n );\n }\n\n if (error) {\n const embedError = new Error(error);\n if (typeof errorFallback === \"function\") return errorFallback(embedError);\n return (\n errorFallback ?? (\n <div\n className=\"athena-sdk-chrome flex h-full w-full items-center justify-center gap-2 p-4 text-sm text-muted-foreground\"\n role=\"alert\"\n >\n <AlertCircle className=\"size-4 text-destructive\" />\n <span>{error}</span>\n </div>\n )\n );\n }\n\n if (!embedUrl) return null;\n\n return (\n <iframe\n {...iframeProps}\n ref={iframeRef}\n src={iframeSrc ?? undefined}\n title={title ?? `Athena asset ${assetId}`}\n allow={allow}\n className={cn(\"block h-full w-full\", className)}\n style={{ ...DEFAULT_STYLE, ...style }}\n onLoad={() => {\n sendConfig();\n onLoad?.();\n }}\n />\n );\n};\n"],"names":["DEFAULT_ASSET_EMBED_DISPLAY_MODE","DEFAULT_ASSET_EMBED_READ_ONLY","useRef","useAthenaConfig","useAssetEmbed","useMemo","buildSdkAssetEmbedUrl","resolveAthenaAssetCitationBehavior","resolveAthenaAssetCitationActionBehavior","useCallback","ATHENA_ASSET_EMBED_CONFIG_MESSAGE","useEffect","isAthenaAssetEmbedReadyEvent","isAthenaAssetCitationClickEvent","isAthenaAssetCitationActionEvent","jsxs","jsx","Loader2","AlertCircle","cn"],"mappings":"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"}
1
+ {"version":3,"file":"AthenaAssetEmbed.cjs","sources":["../../src/assets/AthenaAssetEmbed.tsx"],"sourcesContent":["\"use client\";\n\nimport { AlertCircle, Loader2 } from \"lucide-react\";\nimport { type CSSProperties, type FC, type IframeHTMLAttributes, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\nimport {\n ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n type AthenaAssetCitationActionEvent,\n type AthenaAssetCitationBehavior,\n type AthenaAssetCitationClickEvent,\n type AthenaAssetCitationReference,\n isAthenaAssetCitationActionEvent,\n isAthenaAssetCitationClickEvent,\n isAthenaAssetEmbedReadyEvent,\n resolveAthenaAssetCitationActionBehavior,\n resolveAthenaAssetCitationBehavior,\n} from \"./asset-embed-messages\";\nimport {\n buildSdkAssetEmbedUrl,\n DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n DEFAULT_ASSET_EMBED_READ_ONLY,\n useAssetEmbed,\n} from \"./use-asset-embed\";\n\nexport interface AthenaAssetEmbedProps extends Omit<\n IframeHTMLAttributes<HTMLIFrameElement>,\n \"src\" | \"onError\" | \"onLoad\"\n> {\n assetId: string;\n /** Optional citation target to open inside the embedded asset, such as a PDF page. */\n reference?: AthenaAssetCitationReference;\n /** Defaults to the native full asset experience. */\n displayMode?: \"minimal\" | \"full\";\n /** Defaults to false so authorized users can edit the embedded asset. */\n readOnly?: boolean;\n expiresInSeconds?: number;\n citationBehavior?: AthenaAssetCitationBehavior;\n onCitationClick?: (event: AthenaAssetCitationClickEvent) => void;\n /** Controls the citation popover's actions, including the (+) Open in Spaces button. */\n citationActionBehavior?: AthenaAssetCitationBehavior;\n onCitationAction?: (event: AthenaAssetCitationActionEvent) => void;\n onLoad?: () => void;\n onError?: (error: Error) => void;\n loadingFallback?: React.ReactNode;\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: 0,\n};\nconst AUTH_SYNC_INTERVAL_MS = 60_000;\n\nexport const AthenaAssetEmbed: FC<AthenaAssetEmbedProps> = ({\n assetId,\n reference,\n displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,\n expiresInSeconds,\n citationBehavior,\n onCitationClick,\n citationActionBehavior,\n onCitationAction,\n onLoad,\n onError,\n loadingFallback,\n errorFallback,\n className,\n style,\n title,\n allow = \"clipboard-write; fullscreen\",\n ...iframeProps\n}) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const athenaConfig = useAthenaConfig();\n const { backendUrl, appUrl, apiKey } = athenaConfig;\n const { embedUrl, isLoading, error } = useAssetEmbed(assetId, {\n backendUrl,\n appUrl,\n apiKey,\n token: athenaConfig.token,\n readOnly,\n expiresInSeconds,\n displayMode,\n });\n const targetOrigin = useMemo(() => {\n if (!embedUrl) return null;\n try {\n return new URL(embedUrl, window.location.href).origin;\n } catch {\n return null;\n }\n }, [embedUrl]);\n const iframeSrc = useMemo(\n () => (embedUrl ? buildSdkAssetEmbedUrl(embedUrl, reference) : null),\n [embedUrl, reference],\n );\n const effectiveCitationBehavior = resolveAthenaAssetCitationBehavior({\n citationBehavior,\n hasCitationClickHandler: !!onCitationClick,\n });\n const effectiveCitationActionBehavior = resolveAthenaAssetCitationActionBehavior({\n citationActionBehavior,\n hasCitationActionHandler: !!onCitationAction,\n });\n\n const sendConfig = useCallback(() => {\n if (!targetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n version: 1,\n ...(athenaConfig.token ? { token: athenaConfig.token } : {}),\n citationBehavior: effectiveCitationBehavior,\n citationActionBehavior: effectiveCitationActionBehavior,\n },\n targetOrigin,\n );\n }, [athenaConfig, effectiveCitationActionBehavior, effectiveCitationBehavior, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl || !targetOrigin) return;\n const handleMessage = (event: MessageEvent<unknown>) => {\n if (event.origin !== targetOrigin || event.source !== iframeRef.current?.contentWindow) return;\n if (isAthenaAssetEmbedReadyEvent(event.data)) {\n sendConfig();\n return;\n }\n if (isAthenaAssetCitationClickEvent(event.data)) {\n onCitationClick?.(event.data);\n return;\n }\n if (isAthenaAssetCitationActionEvent(event.data)) {\n onCitationAction?.(event.data);\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [embedUrl, onCitationAction, onCitationClick, sendConfig, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl) return;\n sendConfig();\n const interval = window.setInterval(sendConfig, AUTH_SYNC_INTERVAL_MS);\n return () => window.clearInterval(interval);\n }, [embedUrl, sendConfig]);\n\n useEffect(() => {\n if (error) onError?.(new Error(error));\n }, [error, onError]);\n\n if (isLoading) {\n return (\n loadingFallback ?? (\n <output className=\"athena-sdk-chrome flex h-full w-full items-center justify-center\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n <span className=\"sr-only\">Loading asset</span>\n </output>\n )\n );\n }\n\n if (error) {\n const embedError = new Error(error);\n if (typeof errorFallback === \"function\") return errorFallback(embedError);\n return (\n errorFallback ?? (\n <div\n className=\"athena-sdk-chrome flex h-full w-full items-center justify-center gap-2 p-4 text-sm text-muted-foreground\"\n role=\"alert\"\n >\n <AlertCircle className=\"size-4 text-destructive\" />\n <span>{error}</span>\n </div>\n )\n );\n }\n\n if (!embedUrl) return null;\n\n return (\n <iframe\n {...iframeProps}\n ref={iframeRef}\n src={iframeSrc ?? undefined}\n title={title ?? `Athena asset ${assetId}`}\n allow={allow}\n className={cn(\"block h-full w-full\", className)}\n style={{ ...DEFAULT_STYLE, ...style }}\n onLoad={() => {\n sendConfig();\n onLoad?.();\n }}\n />\n );\n};\n"],"names":["DEFAULT_ASSET_EMBED_DISPLAY_MODE","DEFAULT_ASSET_EMBED_READ_ONLY","useRef","useAthenaConfig","useAssetEmbed","useMemo","buildSdkAssetEmbedUrl","resolveAthenaAssetCitationBehavior","resolveAthenaAssetCitationActionBehavior","useCallback","ATHENA_ASSET_EMBED_CONFIG_MESSAGE","useEffect","isAthenaAssetEmbedReadyEvent","isAthenaAssetCitationClickEvent","isAthenaAssetCitationActionEvent","jsxs","jsx","Loader2","AlertCircle","cn"],"mappings":"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"}
@@ -28,7 +28,7 @@ const AthenaAssetEmbed = ({
28
28
  className,
29
29
  style,
30
30
  title,
31
- allow = "fullscreen",
31
+ allow = "clipboard-write; fullscreen",
32
32
  ...iframeProps
33
33
  }) => {
34
34
  const iframeRef = useRef(null);
@@ -1 +1 @@
1
- {"version":3,"file":"AthenaAssetEmbed.js","sources":["../../src/assets/AthenaAssetEmbed.tsx"],"sourcesContent":["\"use client\";\n\nimport { AlertCircle, Loader2 } from \"lucide-react\";\nimport { type CSSProperties, type FC, type IframeHTMLAttributes, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\nimport {\n ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n type AthenaAssetCitationActionEvent,\n type AthenaAssetCitationBehavior,\n type AthenaAssetCitationClickEvent,\n type AthenaAssetCitationReference,\n isAthenaAssetCitationActionEvent,\n isAthenaAssetCitationClickEvent,\n isAthenaAssetEmbedReadyEvent,\n resolveAthenaAssetCitationActionBehavior,\n resolveAthenaAssetCitationBehavior,\n} from \"./asset-embed-messages\";\nimport {\n buildSdkAssetEmbedUrl,\n DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n DEFAULT_ASSET_EMBED_READ_ONLY,\n useAssetEmbed,\n} from \"./use-asset-embed\";\n\nexport interface AthenaAssetEmbedProps extends Omit<\n IframeHTMLAttributes<HTMLIFrameElement>,\n \"src\" | \"onError\" | \"onLoad\"\n> {\n assetId: string;\n /** Optional citation target to open inside the embedded asset, such as a PDF page. */\n reference?: AthenaAssetCitationReference;\n /** Defaults to the native full asset experience. */\n displayMode?: \"minimal\" | \"full\";\n /** Defaults to false so authorized users can edit the embedded asset. */\n readOnly?: boolean;\n expiresInSeconds?: number;\n citationBehavior?: AthenaAssetCitationBehavior;\n onCitationClick?: (event: AthenaAssetCitationClickEvent) => void;\n /** Controls the citation popover's actions, including the (+) Open in Spaces button. */\n citationActionBehavior?: AthenaAssetCitationBehavior;\n onCitationAction?: (event: AthenaAssetCitationActionEvent) => void;\n onLoad?: () => void;\n onError?: (error: Error) => void;\n loadingFallback?: React.ReactNode;\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: 0,\n};\nconst AUTH_SYNC_INTERVAL_MS = 60_000;\n\nexport const AthenaAssetEmbed: FC<AthenaAssetEmbedProps> = ({\n assetId,\n reference,\n displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,\n expiresInSeconds,\n citationBehavior,\n onCitationClick,\n citationActionBehavior,\n onCitationAction,\n onLoad,\n onError,\n loadingFallback,\n errorFallback,\n className,\n style,\n title,\n allow = \"fullscreen\",\n ...iframeProps\n}) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const athenaConfig = useAthenaConfig();\n const { backendUrl, appUrl, apiKey } = athenaConfig;\n const { embedUrl, isLoading, error } = useAssetEmbed(assetId, {\n backendUrl,\n appUrl,\n apiKey,\n token: athenaConfig.token,\n readOnly,\n expiresInSeconds,\n displayMode,\n });\n const targetOrigin = useMemo(() => {\n if (!embedUrl) return null;\n try {\n return new URL(embedUrl, window.location.href).origin;\n } catch {\n return null;\n }\n }, [embedUrl]);\n const iframeSrc = useMemo(\n () => (embedUrl ? buildSdkAssetEmbedUrl(embedUrl, reference) : null),\n [embedUrl, reference],\n );\n const effectiveCitationBehavior = resolveAthenaAssetCitationBehavior({\n citationBehavior,\n hasCitationClickHandler: !!onCitationClick,\n });\n const effectiveCitationActionBehavior = resolveAthenaAssetCitationActionBehavior({\n citationActionBehavior,\n hasCitationActionHandler: !!onCitationAction,\n });\n\n const sendConfig = useCallback(() => {\n if (!targetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n version: 1,\n ...(athenaConfig.token ? { token: athenaConfig.token } : {}),\n citationBehavior: effectiveCitationBehavior,\n citationActionBehavior: effectiveCitationActionBehavior,\n },\n targetOrigin,\n );\n }, [athenaConfig, effectiveCitationActionBehavior, effectiveCitationBehavior, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl || !targetOrigin) return;\n const handleMessage = (event: MessageEvent<unknown>) => {\n if (event.origin !== targetOrigin || event.source !== iframeRef.current?.contentWindow) return;\n if (isAthenaAssetEmbedReadyEvent(event.data)) {\n sendConfig();\n return;\n }\n if (isAthenaAssetCitationClickEvent(event.data)) {\n onCitationClick?.(event.data);\n return;\n }\n if (isAthenaAssetCitationActionEvent(event.data)) {\n onCitationAction?.(event.data);\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [embedUrl, onCitationAction, onCitationClick, sendConfig, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl) return;\n sendConfig();\n const interval = window.setInterval(sendConfig, AUTH_SYNC_INTERVAL_MS);\n return () => window.clearInterval(interval);\n }, [embedUrl, sendConfig]);\n\n useEffect(() => {\n if (error) onError?.(new Error(error));\n }, [error, onError]);\n\n if (isLoading) {\n return (\n loadingFallback ?? (\n <output className=\"athena-sdk-chrome flex h-full w-full items-center justify-center\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n <span className=\"sr-only\">Loading asset</span>\n </output>\n )\n );\n }\n\n if (error) {\n const embedError = new Error(error);\n if (typeof errorFallback === \"function\") return errorFallback(embedError);\n return (\n errorFallback ?? (\n <div\n className=\"athena-sdk-chrome flex h-full w-full items-center justify-center gap-2 p-4 text-sm text-muted-foreground\"\n role=\"alert\"\n >\n <AlertCircle className=\"size-4 text-destructive\" />\n <span>{error}</span>\n </div>\n )\n );\n }\n\n if (!embedUrl) return null;\n\n return (\n <iframe\n {...iframeProps}\n ref={iframeRef}\n src={iframeSrc ?? undefined}\n title={title ?? `Athena asset ${assetId}`}\n allow={allow}\n className={cn(\"block h-full w-full\", className)}\n style={{ ...DEFAULT_STYLE, ...style }}\n onLoad={() => {\n sendConfig();\n onLoad?.();\n }}\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AthenaAssetEmbed.js","sources":["../../src/assets/AthenaAssetEmbed.tsx"],"sourcesContent":["\"use client\";\n\nimport { AlertCircle, Loader2 } from \"lucide-react\";\nimport { type CSSProperties, type FC, type IframeHTMLAttributes, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useAthenaConfig } from \"../provider/AthenaContext\";\nimport {\n ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n type AthenaAssetCitationActionEvent,\n type AthenaAssetCitationBehavior,\n type AthenaAssetCitationClickEvent,\n type AthenaAssetCitationReference,\n isAthenaAssetCitationActionEvent,\n isAthenaAssetCitationClickEvent,\n isAthenaAssetEmbedReadyEvent,\n resolveAthenaAssetCitationActionBehavior,\n resolveAthenaAssetCitationBehavior,\n} from \"./asset-embed-messages\";\nimport {\n buildSdkAssetEmbedUrl,\n DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n DEFAULT_ASSET_EMBED_READ_ONLY,\n useAssetEmbed,\n} from \"./use-asset-embed\";\n\nexport interface AthenaAssetEmbedProps extends Omit<\n IframeHTMLAttributes<HTMLIFrameElement>,\n \"src\" | \"onError\" | \"onLoad\"\n> {\n assetId: string;\n /** Optional citation target to open inside the embedded asset, such as a PDF page. */\n reference?: AthenaAssetCitationReference;\n /** Defaults to the native full asset experience. */\n displayMode?: \"minimal\" | \"full\";\n /** Defaults to false so authorized users can edit the embedded asset. */\n readOnly?: boolean;\n expiresInSeconds?: number;\n citationBehavior?: AthenaAssetCitationBehavior;\n onCitationClick?: (event: AthenaAssetCitationClickEvent) => void;\n /** Controls the citation popover's actions, including the (+) Open in Spaces button. */\n citationActionBehavior?: AthenaAssetCitationBehavior;\n onCitationAction?: (event: AthenaAssetCitationActionEvent) => void;\n onLoad?: () => void;\n onError?: (error: Error) => void;\n loadingFallback?: React.ReactNode;\n errorFallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: 0,\n};\nconst AUTH_SYNC_INTERVAL_MS = 60_000;\n\nexport const AthenaAssetEmbed: FC<AthenaAssetEmbedProps> = ({\n assetId,\n reference,\n displayMode = DEFAULT_ASSET_EMBED_DISPLAY_MODE,\n readOnly = DEFAULT_ASSET_EMBED_READ_ONLY,\n expiresInSeconds,\n citationBehavior,\n onCitationClick,\n citationActionBehavior,\n onCitationAction,\n onLoad,\n onError,\n loadingFallback,\n errorFallback,\n className,\n style,\n title,\n allow = \"clipboard-write; fullscreen\",\n ...iframeProps\n}) => {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const athenaConfig = useAthenaConfig();\n const { backendUrl, appUrl, apiKey } = athenaConfig;\n const { embedUrl, isLoading, error } = useAssetEmbed(assetId, {\n backendUrl,\n appUrl,\n apiKey,\n token: athenaConfig.token,\n readOnly,\n expiresInSeconds,\n displayMode,\n });\n const targetOrigin = useMemo(() => {\n if (!embedUrl) return null;\n try {\n return new URL(embedUrl, window.location.href).origin;\n } catch {\n return null;\n }\n }, [embedUrl]);\n const iframeSrc = useMemo(\n () => (embedUrl ? buildSdkAssetEmbedUrl(embedUrl, reference) : null),\n [embedUrl, reference],\n );\n const effectiveCitationBehavior = resolveAthenaAssetCitationBehavior({\n citationBehavior,\n hasCitationClickHandler: !!onCitationClick,\n });\n const effectiveCitationActionBehavior = resolveAthenaAssetCitationActionBehavior({\n citationActionBehavior,\n hasCitationActionHandler: !!onCitationAction,\n });\n\n const sendConfig = useCallback(() => {\n if (!targetOrigin) return;\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: ATHENA_ASSET_EMBED_CONFIG_MESSAGE,\n version: 1,\n ...(athenaConfig.token ? { token: athenaConfig.token } : {}),\n citationBehavior: effectiveCitationBehavior,\n citationActionBehavior: effectiveCitationActionBehavior,\n },\n targetOrigin,\n );\n }, [athenaConfig, effectiveCitationActionBehavior, effectiveCitationBehavior, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl || !targetOrigin) return;\n const handleMessage = (event: MessageEvent<unknown>) => {\n if (event.origin !== targetOrigin || event.source !== iframeRef.current?.contentWindow) return;\n if (isAthenaAssetEmbedReadyEvent(event.data)) {\n sendConfig();\n return;\n }\n if (isAthenaAssetCitationClickEvent(event.data)) {\n onCitationClick?.(event.data);\n return;\n }\n if (isAthenaAssetCitationActionEvent(event.data)) {\n onCitationAction?.(event.data);\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [embedUrl, onCitationAction, onCitationClick, sendConfig, targetOrigin]);\n\n useEffect(() => {\n if (!embedUrl) return;\n sendConfig();\n const interval = window.setInterval(sendConfig, AUTH_SYNC_INTERVAL_MS);\n return () => window.clearInterval(interval);\n }, [embedUrl, sendConfig]);\n\n useEffect(() => {\n if (error) onError?.(new Error(error));\n }, [error, onError]);\n\n if (isLoading) {\n return (\n loadingFallback ?? (\n <output className=\"athena-sdk-chrome flex h-full w-full items-center justify-center\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n <span className=\"sr-only\">Loading asset</span>\n </output>\n )\n );\n }\n\n if (error) {\n const embedError = new Error(error);\n if (typeof errorFallback === \"function\") return errorFallback(embedError);\n return (\n errorFallback ?? (\n <div\n className=\"athena-sdk-chrome flex h-full w-full items-center justify-center gap-2 p-4 text-sm text-muted-foreground\"\n role=\"alert\"\n >\n <AlertCircle className=\"size-4 text-destructive\" />\n <span>{error}</span>\n </div>\n )\n );\n }\n\n if (!embedUrl) return null;\n\n return (\n <iframe\n {...iframeProps}\n ref={iframeRef}\n src={iframeSrc ?? undefined}\n title={title ?? `Athena asset ${assetId}`}\n allow={allow}\n className={cn(\"block h-full w-full\", className)}\n style={{ ...DEFAULT_STYLE, ...style }}\n onLoad={() => {\n sendConfig();\n onLoad?.();\n }}\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,23 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
- require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
5
- const react$1 = require("react");
6
- require("@assistant-ui/tap");
7
- require("statewire");
8
- require("../packages/agent-runtime/src/statewire-suspended.cjs");
9
- require("../packages/agent-runtime/src/conversation-list.cjs");
10
- require("@tanstack/react-query");
11
- require("../packages/agent-runtime/src/statewire-state.cjs");
12
- require("../packages/agent-runtime/src/messages.cjs");
13
- require("@assistant-ui/store");
14
- require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
15
- require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
16
- require("../packages/agent-runtime/src/thread-status.cjs");
17
- require("@assistant-ui/react-statewire");
18
- const githubWakeEvent = require("../packages/agent-runtime/src/github-wake-event.cjs");
19
- require("@assistant-ui/core");
20
- require("../packages/agent-runtime/src/thread-handoff.cjs");
21
4
  const tiptapText = require("./tiptap-text.cjs");
22
5
  const AthenaChatErrorBoundary = require("./AthenaChatErrorBoundary.cjs");
23
6
  const StatewireApprovalCard = require("./StatewireApprovalCard.cjs");
@@ -45,6 +28,7 @@ const useDictation = require("../dictation/use-dictation.cjs");
45
28
  const DictationStrip = require("../dictation/DictationStrip.cjs");
46
29
  const dictationControls = require("../dictation/dictation-controls.cjs");
47
30
  const dictationState = require("../dictation/dictation-state.cjs");
31
+ const useAthenaDictationEngine = require("../dictation/use-athena-dictation-engine.cjs");
48
32
  const tiptapComposer = require("../chat-ui/composer/tiptap-composer.cjs");
49
33
  const apiClient = require("../chat-ui/mentions/suggestions/data/api-client.cjs");
50
34
  const messageComponents = require("../chat-ui/messages/message-components.cjs");
@@ -56,6 +40,7 @@ const composerKeyboardHint = require("./composer-keyboard-hint.cjs");
56
40
  const usePrefersReducedMotion = require("../lib/use-prefers-reduced-motion.cjs");
57
41
  const react = require("@assistant-ui/react");
58
42
  const lucideReact = require("lucide-react");
43
+ const react$1 = require("react");
59
44
  const threadIdContext = require("../threads/thread-id-context.cjs");
60
45
  const FileUploadButton = require("../composer/FileUploadButton.cjs");
61
46
  const ComposerQuotePreview = require("../composer/ComposerQuotePreview.cjs");
@@ -72,6 +57,7 @@ const index = require("../toolkits/index.cjs");
72
57
  const runActivity = require("./run-activity.cjs");
73
58
  const messageTime = require("./message-time.cjs");
74
59
  const threadScrollToBottom = require("./thread-scroll-to-bottom.cjs");
60
+ const githubWakeEvent = require("../packages/agent-runtime/src/github-wake-event.cjs");
75
61
  const cnfast = require("cnfast");
76
62
  function QuotePostMessageBridge() {
77
63
  QuoteContext.useQuoteFromPostMessage();
@@ -351,8 +337,9 @@ const AthenaChatComposer = ({ tools, slots, dictation, welcomeSuggestionCount })
351
337
  },
352
338
  [aui]
353
339
  );
340
+ const dictationEngine = useAthenaDictationEngine.useAthenaDictationEngine(dictationOptions == null ? void 0 : dictationOptions.engine);
354
341
  const dictationCtl = useDictation.useDictation({
355
- engine: dictationOptions == null ? void 0 : dictationOptions.engine,
342
+ engine: dictationEngine,
356
343
  lang: dictationOptions == null ? void 0 : dictationOptions.lang,
357
344
  // A recognizer that gives up on its own (silence window) still hands
358
345
  // over what it heard instead of dropping the words with the session.
@@ -420,12 +407,16 @@ const AthenaChatComposer = ({ tools, slots, dictation, welcomeSuggestionCount })
420
407
  [attachFiles]
421
408
  );
422
409
  const stopDictation = react$1.useCallback(async () => {
423
- appendSpokenText(await dictationCtl.stop());
410
+ appendSpokenText((await dictationCtl.stop()).text);
424
411
  }, [appendSpokenText, dictationCtl]);
425
412
  const sendDictation = react$1.useCallback(async () => {
426
413
  var _a;
427
- const spoken = await dictationCtl.stop();
414
+ const { text: spoken, error } = await dictationCtl.stop();
428
415
  const text = dictationState.composeDictationDraft(aui.composer.getState().text ?? "", spoken);
416
+ if (error) {
417
+ aui.composer.setText(text);
418
+ return;
419
+ }
429
420
  const extras = attachmentsRef.current.length > 0 || quoteRef.current !== null;
430
421
  if (!text && !extras) return;
431
422
  aui.composer.setText(text);
@@ -433,12 +424,12 @@ const AthenaChatComposer = ({ tools, slots, dictation, welcomeSuggestionCount })
433
424
  if (action === "stop") return;
434
425
  try {
435
426
  await ((_a = slots == null ? void 0 : slots.onBeforeSend) == null ? void 0 : _a.call(slots, { action }));
436
- } catch (error) {
427
+ } catch (error2) {
437
428
  athenaDiagnostics.athenaDiagnostics.emit("composer.dictation", {
438
429
  level: "warn",
439
430
  data: {
440
431
  phase: "before_send_rejected",
441
- error: error instanceof Error ? error.message : String(error)
432
+ error: error2 instanceof Error ? error2.message : String(error2)
442
433
  }
443
434
  });
444
435
  return;
@@ -487,7 +478,8 @@ const AthenaChatComposer = ({ tools, slots, dictation, welcomeSuggestionCount })
487
478
  {
488
479
  status: dictationCtl.status,
489
480
  transcript: dictationCtl.transcript,
490
- stream: dictationCtl.stream
481
+ stream: dictationCtl.stream,
482
+ stoppingLabel: dictationCtl.engine.stoppingLabel
491
483
  }
492
484
  ),
493
485
  dictationEnabled && dictationCtl.status === dictationState.DICTATION_STATUSES.error && dictationCtl.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "aui-dictation-error px-1.5 pb-1 text-destructive text-xs", role: "alert", children: dictationCtl.error.message })