@arbidocs/blocks 0.4.147 → 0.4.151

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 (339) hide show
  1. package/dist/ConnectedNativeDocxComparison-OFPIXNJB.js +35 -0
  2. package/dist/ConnectedNativeDocxComparison-OFPIXNJB.js.map +1 -0
  3. package/dist/ConnectedNativeDocxComparison-Y5BNLNH6.cjs +44 -0
  4. package/dist/ConnectedNativeDocxComparison-Y5BNLNH6.cjs.map +1 -0
  5. package/dist/ConnectedNativeDocxEditor-HTEW5JAH.cjs +46 -0
  6. package/dist/ConnectedNativeDocxEditor-HTEW5JAH.cjs.map +1 -0
  7. package/dist/ConnectedNativeDocxEditor-LRYU5HPA.js +33 -0
  8. package/dist/ConnectedNativeDocxEditor-LRYU5HPA.js.map +1 -0
  9. package/dist/ConnectedStreamedWordArtifact-QAUVUCSX.js +35 -0
  10. package/dist/ConnectedStreamedWordArtifact-QAUVUCSX.js.map +1 -0
  11. package/dist/ConnectedStreamedWordArtifact-QW74LKHN.cjs +44 -0
  12. package/dist/ConnectedStreamedWordArtifact-QW74LKHN.cjs.map +1 -0
  13. package/dist/FactTextEditor-YESAU2IJ.js +25 -0
  14. package/dist/FactTextEditor-YESAU2IJ.js.map +1 -0
  15. package/dist/FactTextEditor-YUPBCTXK.cjs +27 -0
  16. package/dist/FactTextEditor-YUPBCTXK.cjs.map +1 -0
  17. package/dist/{NativeDocxEditor-BE2OEOTJ.cjs → NativeDocxEditor-5VBNM5I7.cjs} +8 -8
  18. package/dist/{NativeDocxEditor-BE2OEOTJ.cjs.map → NativeDocxEditor-5VBNM5I7.cjs.map} +1 -1
  19. package/dist/{NativeDocxEditor-KOPFMRYW.js → NativeDocxEditor-XT5ZLFGU.js} +4 -4
  20. package/dist/{NativeDocxEditor-KOPFMRYW.js.map → NativeDocxEditor-XT5ZLFGU.js.map} +1 -1
  21. package/dist/agents/index.cjs +263 -264
  22. package/dist/agents/index.js +6 -7
  23. package/dist/calendar/index.cjs +117 -125
  24. package/dist/calendar/index.d.ts +0 -1
  25. package/dist/calendar/index.js +1 -1
  26. package/dist/chat/index.cjs +78 -78
  27. package/dist/chat/index.js +3 -3
  28. package/dist/{chunk-2FL7QJKJ.js → chunk-265GOG4W.js} +3 -3
  29. package/dist/{chunk-2FL7QJKJ.js.map → chunk-265GOG4W.js.map} +1 -1
  30. package/dist/{chunk-LTU35TQN.cjs → chunk-2FLWPM3B.cjs} +636 -31
  31. package/dist/chunk-2FLWPM3B.cjs.map +1 -0
  32. package/dist/{chunk-SUUPR735.js → chunk-3PCBYOIZ.js} +4 -4
  33. package/dist/{chunk-SUUPR735.js.map → chunk-3PCBYOIZ.js.map} +1 -1
  34. package/dist/{chunk-WIZ7Z7FN.js → chunk-4236BRZK.js} +46 -221
  35. package/dist/chunk-4236BRZK.js.map +1 -0
  36. package/dist/{chunk-IL3WB3YX.cjs → chunk-4JNKXOFZ.cjs} +3 -3
  37. package/dist/{chunk-IL3WB3YX.cjs.map → chunk-4JNKXOFZ.cjs.map} +1 -1
  38. package/dist/{chunk-ODRHHWHY.cjs → chunk-4KMLM3GY.cjs} +4 -4
  39. package/dist/chunk-4KMLM3GY.cjs.map +1 -0
  40. package/dist/chunk-6I6CVX5G.cjs +22 -0
  41. package/dist/chunk-6I6CVX5G.cjs.map +1 -0
  42. package/dist/{chunk-MHFF5N65.cjs → chunk-757OYF6G.cjs} +4 -38
  43. package/dist/chunk-757OYF6G.cjs.map +1 -0
  44. package/dist/chunk-B3FMUFAW.cjs +1956 -0
  45. package/dist/chunk-B3FMUFAW.cjs.map +1 -0
  46. package/dist/{chunk-B3AHCIV5.js → chunk-BJ24VPOA.js} +4 -55
  47. package/dist/chunk-BJ24VPOA.js.map +1 -0
  48. package/dist/chunk-C7PTF6BQ.cjs +172 -0
  49. package/dist/chunk-C7PTF6BQ.cjs.map +1 -0
  50. package/dist/{chunk-LZRMXJIE.js → chunk-COA3S3CZ.js} +3 -3
  51. package/dist/{chunk-LZRMXJIE.js.map → chunk-COA3S3CZ.js.map} +1 -1
  52. package/dist/{chunk-VUR63NMQ.js → chunk-CROTH2BS.js} +6 -6
  53. package/dist/{chunk-VUR63NMQ.js.map → chunk-CROTH2BS.js.map} +1 -1
  54. package/dist/{chunk-AO7SK6WP.cjs → chunk-CU2O32Z4.cjs} +31 -31
  55. package/dist/{chunk-AO7SK6WP.cjs.map → chunk-CU2O32Z4.cjs.map} +1 -1
  56. package/dist/chunk-D3WFIFRY.cjs +659 -0
  57. package/dist/chunk-D3WFIFRY.cjs.map +1 -0
  58. package/dist/{chunk-DAHCRVPM.js → chunk-DB2OXRQC.js} +84 -82
  59. package/dist/chunk-DB2OXRQC.js.map +1 -0
  60. package/dist/{chunk-QXMR5YHC.js → chunk-DIB4JYUY.js} +19 -3
  61. package/dist/chunk-DIB4JYUY.js.map +1 -0
  62. package/dist/chunk-DVB5ZKOF.js +22 -0
  63. package/dist/chunk-DVB5ZKOF.js.map +1 -0
  64. package/dist/chunk-EYJMMGXF.js +19 -0
  65. package/dist/chunk-EYJMMGXF.js.map +1 -0
  66. package/dist/chunk-FAXXN7KI.cjs +213 -0
  67. package/dist/chunk-FAXXN7KI.cjs.map +1 -0
  68. package/dist/{chunk-2MJWWPHY.js → chunk-G4IYES7G.js} +140 -15
  69. package/dist/chunk-G4IYES7G.js.map +1 -0
  70. package/dist/{chunk-T5I4NRFP.cjs → chunk-GFOEWPAP.cjs} +8 -8
  71. package/dist/{chunk-T5I4NRFP.cjs.map → chunk-GFOEWPAP.cjs.map} +1 -1
  72. package/dist/{chunk-QI6AIHWP.cjs → chunk-GOWXP5KT.cjs} +145 -14
  73. package/dist/chunk-GOWXP5KT.cjs.map +1 -0
  74. package/dist/chunk-HALD6ZB5.cjs +18 -0
  75. package/dist/chunk-HALD6ZB5.cjs.map +1 -0
  76. package/dist/chunk-HUJF2XM2.js +6584 -0
  77. package/dist/chunk-HUJF2XM2.js.map +1 -0
  78. package/dist/{chunk-NRFAWUVD.js → chunk-JAANWQGB.js} +157 -157
  79. package/dist/chunk-JAANWQGB.js.map +1 -0
  80. package/dist/{chunk-7RJTEWYM.js → chunk-JGOST4IL.js} +350 -64
  81. package/dist/chunk-JGOST4IL.js.map +1 -0
  82. package/dist/chunk-KHXEIEXN.js +41 -0
  83. package/dist/chunk-KHXEIEXN.js.map +1 -0
  84. package/dist/chunk-KQYPP72K.js +644 -0
  85. package/dist/chunk-KQYPP72K.js.map +1 -0
  86. package/dist/chunk-KUT2Y7JF.cjs +43 -0
  87. package/dist/chunk-KUT2Y7JF.cjs.map +1 -0
  88. package/dist/{chunk-6YTHQ73P.cjs → chunk-LLYZGH3L.cjs} +3 -56
  89. package/dist/chunk-LLYZGH3L.cjs.map +1 -0
  90. package/dist/{chunk-YSHIC4NJ.cjs → chunk-LXTOOUEN.cjs} +159 -154
  91. package/dist/chunk-LXTOOUEN.cjs.map +1 -0
  92. package/dist/{chunk-EVUEIBNU.js → chunk-M4S75AEJ.js} +44 -5
  93. package/dist/chunk-M4S75AEJ.js.map +1 -0
  94. package/dist/{chunk-V5OAXIBN.cjs → chunk-NPR5BGFF.cjs} +11 -11
  95. package/dist/{chunk-V5OAXIBN.cjs.map → chunk-NPR5BGFF.cjs.map} +1 -1
  96. package/dist/{chunk-PLJ7PHWU.cjs → chunk-NS7NVX4E.cjs} +3 -3
  97. package/dist/{chunk-PLJ7PHWU.cjs.map → chunk-NS7NVX4E.cjs.map} +1 -1
  98. package/dist/{chunk-AINU3EJ6.cjs → chunk-Q4BY2CQQ.cjs} +92 -90
  99. package/dist/chunk-Q4BY2CQQ.cjs.map +1 -0
  100. package/dist/chunk-QN47Q4N7.js +16 -0
  101. package/dist/chunk-QN47Q4N7.js.map +1 -0
  102. package/dist/{chunk-I2QSDQQV.cjs → chunk-QT3A4PFC.cjs} +21 -2
  103. package/dist/chunk-QT3A4PFC.cjs.map +1 -0
  104. package/dist/{chunk-ZM26YEOT.js → chunk-RY2SODRN.js} +3 -3
  105. package/dist/{chunk-ZM26YEOT.js.map → chunk-RY2SODRN.js.map} +1 -1
  106. package/dist/chunk-SDOEHEJP.js +208 -0
  107. package/dist/chunk-SDOEHEJP.js.map +1 -0
  108. package/dist/{chunk-DETZZBG2.cjs → chunk-SIB6C7P7.cjs} +43 -2
  109. package/dist/chunk-SIB6C7P7.cjs.map +1 -0
  110. package/dist/{chunk-MFY2ZNP6.cjs → chunk-SMN32BQ3.cjs} +4 -4
  111. package/dist/chunk-SMN32BQ3.cjs.map +1 -0
  112. package/dist/chunk-T74Q3MCZ.cjs +6751 -0
  113. package/dist/chunk-T74Q3MCZ.cjs.map +1 -0
  114. package/dist/{chunk-AOSUHWIL.js → chunk-TZOQKV64.js} +4 -37
  115. package/dist/chunk-TZOQKV64.js.map +1 -0
  116. package/dist/{chunk-U37AYUPI.cjs → chunk-U6JQ4KMX.cjs} +46 -233
  117. package/dist/chunk-U6JQ4KMX.cjs.map +1 -0
  118. package/dist/chunk-WFA2GVZJ.js +16 -0
  119. package/dist/chunk-WFA2GVZJ.js.map +1 -0
  120. package/dist/chunk-WU34CHU5.js +1907 -0
  121. package/dist/chunk-WU34CHU5.js.map +1 -0
  122. package/dist/{chunk-O4YPVYPO.cjs → chunk-YAEXSCUW.cjs} +364 -60
  123. package/dist/chunk-YAEXSCUW.cjs.map +1 -0
  124. package/dist/{chunk-H74HEPKT.js → chunk-YXNNNP57.js} +598 -13
  125. package/dist/chunk-YXNNNP57.js.map +1 -0
  126. package/dist/chunk-Z27QMJ6S.cjs +25 -0
  127. package/dist/chunk-Z27QMJ6S.cjs.map +1 -0
  128. package/dist/{chunk-CSI2B2H5.js → chunk-Z4NQ3TED.js} +4 -4
  129. package/dist/chunk-Z4NQ3TED.js.map +1 -0
  130. package/dist/{chunk-DGV7HQA7.js → chunk-ZLEYLCE4.js} +4 -4
  131. package/dist/chunk-ZLEYLCE4.js.map +1 -0
  132. package/dist/chunk-ZNLTEZEF.js +170 -0
  133. package/dist/chunk-ZNLTEZEF.js.map +1 -0
  134. package/dist/chunk-ZP6Q3KXU.cjs +18 -0
  135. package/dist/chunk-ZP6Q3KXU.cjs.map +1 -0
  136. package/dist/citations/index.cjs +14 -14
  137. package/dist/citations/index.js +2 -2
  138. package/dist/collaboration/index.cjs +35 -35
  139. package/dist/collaboration/index.js +1 -1
  140. package/dist/connect/docx.cjs +21 -26
  141. package/dist/connect/docx.cjs.map +1 -1
  142. package/dist/connect/docx.js +10 -26
  143. package/dist/connect/docx.js.map +1 -1
  144. package/dist/connect/index.cjs +8662 -2824
  145. package/dist/connect/index.cjs.map +1 -1
  146. package/dist/connect/index.d.ts +10 -2
  147. package/dist/connect/index.js +8467 -2670
  148. package/dist/connect/index.js.map +1 -1
  149. package/dist/connect/viewer.cjs +2357 -0
  150. package/dist/connect/viewer.cjs.map +1 -0
  151. package/dist/connect/viewer.d.ts +8 -0
  152. package/dist/connect/viewer.js +2350 -0
  153. package/dist/connect/viewer.js.map +1 -0
  154. package/dist/connection/ConnectedWorkflowsTable.d.ts +2 -12
  155. package/dist/connection/ai.d.ts +2 -9
  156. package/dist/connection/billing/AddAddonDialog.d.ts +24 -0
  157. package/dist/connection/billing/BillingCard.d.ts +18 -0
  158. package/dist/connection/billing/BillingProjectEntity.d.ts +9 -0
  159. package/dist/connection/billing/ChangePlanDialog.d.ts +20 -0
  160. package/dist/connection/billing/ChangeProPlan.d.ts +20 -0
  161. package/dist/connection/billing/CheckoutTotal.d.ts +12 -0
  162. package/dist/connection/billing/DailyCapEditor.d.ts +4 -0
  163. package/dist/connection/billing/InvoicesModal.d.ts +6 -0
  164. package/dist/connection/billing/NewProjectFlow.d.ts +14 -0
  165. package/dist/connection/billing/PlanChangeLines.d.ts +13 -0
  166. package/dist/connection/billing/PlanSelector.d.ts +50 -0
  167. package/dist/connection/billing/ProjectBilling.d.ts +24 -0
  168. package/dist/connection/billing/ProjectDetail.d.ts +16 -0
  169. package/dist/connection/billing/ProjectUsageCard.d.ts +21 -0
  170. package/dist/connection/billing/ProjectUsageContent.d.ts +18 -0
  171. package/dist/connection/billing/ProjectsTable.d.ts +13 -0
  172. package/dist/connection/billing/ReduceAddonDialog.d.ts +18 -0
  173. package/dist/connection/billing/ReferralReward.d.ts +32 -0
  174. package/dist/connection/billing/SharedProjects.d.ts +13 -0
  175. package/dist/connection/billing/StripeCheckoutModal.d.ts +32 -0
  176. package/dist/connection/billing/SubscriptionPlans.d.ts +15 -0
  177. package/dist/connection/billing/SubscriptionStatus.d.ts +10 -0
  178. package/dist/connection/billing/addon-pricing.d.ts +97 -0
  179. package/dist/connection/billing/api-error.d.ts +6 -0
  180. package/dist/connection/billing/billing-country.d.ts +14 -0
  181. package/dist/connection/billing/billing-focus.d.ts +11 -0
  182. package/dist/connection/billing/index.d.ts +22 -0
  183. package/dist/connection/billing/plan-badge.d.ts +15 -0
  184. package/dist/connection/billing/plan-change-outcome.d.ts +15 -0
  185. package/dist/connection/billing/plan-constants.d.ts +29 -0
  186. package/dist/connection/billing/plan-pricing.d.ts +67 -0
  187. package/dist/connection/billing/quota-items.d.ts +33 -0
  188. package/dist/connection/billing/referral-reward.d.ts +28 -0
  189. package/dist/connection/billing/refusal-copy.d.ts +5 -0
  190. package/dist/connection/billing/reward-balance.d.ts +19 -0
  191. package/dist/connection/billing/support.d.ts +35 -0
  192. package/dist/connection/billing/tax-quote.d.ts +36 -0
  193. package/dist/connection/billing/useAddonPurchase.d.ts +32 -0
  194. package/dist/connection/billing/useAutoRefreshPendingProjects.d.ts +11 -0
  195. package/dist/connection/billing/useCheckoutQuote.d.ts +30 -0
  196. package/dist/connection/billing/useOpenBillingPortal.d.ts +12 -0
  197. package/dist/connection/calendar/CalendarSettingsDialog.d.ts +1 -1
  198. package/dist/connection/facts/ConnectedFactsPage.d.ts +50 -0
  199. package/dist/connection/facts/FactMarkdownEditor.d.ts +57 -0
  200. package/dist/connection/facts/FactSourcesPopover.d.ts +38 -0
  201. package/dist/connection/facts/FactTextEditor.d.ts +2 -0
  202. package/dist/connection/facts/factNouns.d.ts +4 -0
  203. package/dist/connection/facts/factPageColumns.d.ts +37 -0
  204. package/dist/connection/facts/types.d.ts +127 -0
  205. package/dist/connection/facts/useFactActions.d.ts +10 -0
  206. package/dist/connection/facts/useFactComposer.d.ts +54 -0
  207. package/dist/connection/facts/useFactFilters.d.ts +101 -0
  208. package/dist/connection/facts/useFactSelection.d.ts +82 -0
  209. package/dist/connection/facts/useFactsGrid.d.ts +87 -0
  210. package/dist/connection/facts/useFactsPageView.d.ts +4 -0
  211. package/dist/connection/mail/ConnectedMailComposer.d.ts +3 -1
  212. package/dist/connection/mail/ConnectedMailbox.d.ts +4 -2
  213. package/dist/connection/mail/MailComposerForm.d.ts +4 -2
  214. package/dist/connection/mail/MailRecipientInput.d.ts +14 -0
  215. package/dist/connection/mail/index.d.ts +1 -1
  216. package/dist/connection/mail/types.d.ts +10 -0
  217. package/dist/connection/search/ConnectedSearchPage.d.ts +64 -0
  218. package/dist/connection/search/SearchResultRows.d.ts +38 -0
  219. package/dist/connection/search/index.d.ts +2 -0
  220. package/dist/connection/tags/ConnectedTagTable.d.ts +108 -0
  221. package/dist/connection/tags/ConnectedTagsPage.d.ts +55 -0
  222. package/dist/connection/tags/DocTagPassages.d.ts +25 -0
  223. package/dist/connection/tags/GlossaryExport.d.ts +7 -0
  224. package/dist/connection/tags/TagCombineFilter.d.ts +14 -0
  225. package/dist/connection/tags/TagPlacement.d.ts +16 -0
  226. package/dist/connection/tags/TagsPageSections.d.ts +36 -0
  227. package/dist/connection/tags/tagCombine.d.ts +55 -0
  228. package/dist/connection/useConnectedWorkNotifications.d.ts +7 -24
  229. package/dist/connection/viewer/ConnectedDocumentToolsProvider.d.ts +11 -0
  230. package/dist/connection/viewer/ConnectedDocumentViewer.d.ts +21 -0
  231. package/dist/connection/viewer/FinaliseTranslationButton.d.ts +15 -0
  232. package/dist/connection/viewer/ViewerPdfPane.d.ts +46 -0
  233. package/dist/connection/viewer/parsed/ParsedPassage.d.ts +48 -0
  234. package/dist/connection/viewer/parsed/ParsedTextView.d.ts +17 -0
  235. package/dist/connection/viewer/parsed/PassageTagPanel.d.ts +18 -0
  236. package/dist/connection/viewer/parsed/citation-line.d.ts +17 -0
  237. package/dist/connection/viewer/parsed/document-tags.d.ts +8 -0
  238. package/dist/connection/viewer/parsed/useChunkTagging.d.ts +46 -0
  239. package/dist/connection/viewer/parsed/useCitationSelection.d.ts +27 -0
  240. package/dist/connection/viewer/parsed/useDocumentLabels.d.ts +38 -0
  241. package/dist/connection/viewer/parsed/useLazyPages.d.ts +18 -0
  242. package/dist/connection/viewer/parsed/usePageScrollSync.d.ts +17 -0
  243. package/dist/connection/viewer/parsed/usePassageCopy.d.ts +25 -0
  244. package/dist/connection/viewer/support.d.ts +97 -0
  245. package/dist/connection/viewer/useImageCrop.d.ts +13 -0
  246. package/dist/connection/viewer/useViewedDocument.d.ts +70 -0
  247. package/dist/connection/viewer/useViewerBlobs.d.ts +15 -0
  248. package/dist/connection/viewer/useViewerTabs.d.ts +18 -0
  249. package/dist/connection/viewer/useViewerVersions.d.ts +11 -0
  250. package/dist/connection/workspace-settings/useConnectedWorkspaceSettings.d.ts +6 -0
  251. package/dist/document-tools/index.cjs +59 -652
  252. package/dist/document-tools/index.cjs.map +1 -1
  253. package/dist/document-tools/index.js +2 -641
  254. package/dist/document-tools/index.js.map +1 -1
  255. package/dist/docx/index.cjs +48 -47
  256. package/dist/docx/index.js +4 -3
  257. package/dist/facts/FactsBulkBar.d.ts +6 -3
  258. package/dist/facts/cited-version-ref.d.ts +1 -0
  259. package/dist/facts/index.cjs +204 -1940
  260. package/dist/facts/index.cjs.map +1 -1
  261. package/dist/facts/index.d.ts +1 -0
  262. package/dist/facts/index.js +13 -1895
  263. package/dist/facts/index.js.map +1 -1
  264. package/dist/files/TagPassagePanel.d.ts +2 -1
  265. package/dist/files/ViewerChrome.d.ts +5 -4
  266. package/dist/files/ViewerControlBar.d.ts +12 -0
  267. package/dist/files/doc-labels.d.ts +35 -0
  268. package/dist/files/grid/FilterButton.d.ts +12 -0
  269. package/dist/files/grid/RowDensityControl.d.ts +18 -0
  270. package/dist/files/grid/row-density.d.ts +27 -0
  271. package/dist/files/index.cjs +778 -7099
  272. package/dist/files/index.cjs.map +1 -1
  273. package/dist/files/index.d.ts +5 -0
  274. package/dist/files/index.js +13 -6918
  275. package/dist/files/index.js.map +1 -1
  276. package/dist/index.cjs +993 -1209
  277. package/dist/index.cjs.map +1 -1
  278. package/dist/index.js +22 -355
  279. package/dist/index.js.map +1 -1
  280. package/dist/retrieval/SearchSnippet.d.ts +6 -0
  281. package/dist/retrieval/index.cjs +74 -41
  282. package/dist/retrieval/index.d.ts +2 -0
  283. package/dist/retrieval/index.js +2 -1
  284. package/dist/retrieval/search-results.d.ts +46 -0
  285. package/dist/settings/Billing.d.ts +0 -66
  286. package/dist/settings/SubscriptionParts.d.ts +1 -50
  287. package/dist/settings/index.cjs +166 -214
  288. package/dist/settings/index.d.ts +3 -2
  289. package/dist/settings/index.js +1 -1
  290. package/dist/settings/inverted-index-filter.d.ts +26 -0
  291. package/dist/studio/index.cjs +3 -3
  292. package/dist/studio/index.js +2 -2
  293. package/dist/tags/definitions.d.ts +10 -0
  294. package/dist/tags/index.d.ts +4 -1
  295. package/dist/tags/page/ExtractEntitiesDialog.d.ts +24 -0
  296. package/dist/tags/page/TagPicker.d.ts +16 -0
  297. package/dist/tags/page/tagsPageLabels.d.ts +36 -0
  298. package/dist/workflow-canvas/index.cjs +19 -20
  299. package/dist/workflow-canvas/index.cjs.map +1 -1
  300. package/dist/workflow-canvas/index.js +6 -7
  301. package/dist/workflow-canvas/index.js.map +1 -1
  302. package/node_modules/@arbidocs/coedit/package.json +1 -1
  303. package/package.json +13 -4
  304. package/dist/calendar/access-setup.d.ts +0 -8
  305. package/dist/chunk-2MJWWPHY.js.map +0 -1
  306. package/dist/chunk-3AFWGEDJ.cjs +0 -53
  307. package/dist/chunk-3AFWGEDJ.cjs.map +0 -1
  308. package/dist/chunk-6YTHQ73P.cjs.map +0 -1
  309. package/dist/chunk-7RJTEWYM.js.map +0 -1
  310. package/dist/chunk-AINU3EJ6.cjs.map +0 -1
  311. package/dist/chunk-AOSUHWIL.js.map +0 -1
  312. package/dist/chunk-B3AHCIV5.js.map +0 -1
  313. package/dist/chunk-CSI2B2H5.js.map +0 -1
  314. package/dist/chunk-DAHCRVPM.js.map +0 -1
  315. package/dist/chunk-DETZZBG2.cjs.map +0 -1
  316. package/dist/chunk-DGV7HQA7.js.map +0 -1
  317. package/dist/chunk-EVUEIBNU.js.map +0 -1
  318. package/dist/chunk-H74HEPKT.js.map +0 -1
  319. package/dist/chunk-I2QSDQQV.cjs.map +0 -1
  320. package/dist/chunk-J5CWKFSC.js +0 -170
  321. package/dist/chunk-J5CWKFSC.js.map +0 -1
  322. package/dist/chunk-LTU35TQN.cjs.map +0 -1
  323. package/dist/chunk-MFY2ZNP6.cjs.map +0 -1
  324. package/dist/chunk-MHFF5N65.cjs.map +0 -1
  325. package/dist/chunk-NRFAWUVD.js.map +0 -1
  326. package/dist/chunk-O4YPVYPO.cjs.map +0 -1
  327. package/dist/chunk-ODRHHWHY.cjs.map +0 -1
  328. package/dist/chunk-QI6AIHWP.cjs.map +0 -1
  329. package/dist/chunk-QXMR5YHC.js.map +0 -1
  330. package/dist/chunk-RFXJYIDV.js +0 -50
  331. package/dist/chunk-RFXJYIDV.js.map +0 -1
  332. package/dist/chunk-U37AYUPI.cjs.map +0 -1
  333. package/dist/chunk-WIZ7Z7FN.js.map +0 -1
  334. package/dist/chunk-XVUOMWMD.cjs +0 -177
  335. package/dist/chunk-XVUOMWMD.cjs.map +0 -1
  336. package/dist/chunk-YSHIC4NJ.cjs.map +0 -1
  337. package/dist/connection/ConnectedTagTable.d.ts +0 -32
  338. package/dist/connection/calendar/CopyField.d.ts +0 -9
  339. package/dist/connection/calendar/OpenAccessPanel.d.ts +0 -7
@@ -0,0 +1,2350 @@
1
+ "use client";
2
+ import { HtmlPassage, ViewerTitle, ViewerTabBar, ViewerImageActions, ViewerFrame, ViewerMessage, DocumentLabelBar, ViewerControlBar, ViewerZoomControl, PdfPageNav, ViewerPageCounter, summariseDocTags, isDocumentLabel, ViewerPreviewUnavailable, ViewerLoadError, HtmlViewerRoot, CitedRunNav, HtmlViewerSurface, HtmlPage, HtmlViewerEmpty, TagPassagePanel } from '../chunk-HUJF2XM2.js';
3
+ import { useDocumentViewerSupport } from '../chunk-EYJMMGXF.js';
4
+ import '../chunk-JGOST4IL.js';
5
+ import '../chunk-RC6VTY2H.js';
6
+ import { useConnectedConversations, useConnectedDocuments, useConnectedTags } from '../chunk-DN2KI4BU.js';
7
+ import { useConnectedWorkspace } from '../chunk-US3S4DCB.js';
8
+ import { MarkupViewNote, SignatureStatus, AnnotateButton, ShowOriginalButton, DownloadMarkupButton, SignButton, RequestSignaturesButton, MarkupNotices, SignedEditNote, VersionSnapshotBar, SignatureRequestBanner } from '../chunk-KQYPP72K.js';
9
+ import '../chunk-EQB3WELX.js';
10
+ import { ViewerStatusNote, ViewerHeaderStart, ViewerHeaderEnd, ViewerPane } from '../chunk-6HKLTYNN.js';
11
+ import { SignDocumentDialog } from '../chunk-2YOVK524.js';
12
+ import '../chunk-JJA6GQKH.js';
13
+ import '../chunk-H4D7WKDY.js';
14
+ import { ShareControl } from '../chunk-K4BGOPGG.js';
15
+ import '../chunk-SDOEHEJP.js';
16
+ import '../chunk-A3XPS2EU.js';
17
+ import { buildDeepLinkUrl } from '../chunk-SV65E4QW.js';
18
+ import '../chunk-M4S75AEJ.js';
19
+ import '../chunk-5LXQPP2K.js';
20
+ import '../chunk-RLWIUUQ5.js';
21
+ import '../chunk-YKQ2DPIP.js';
22
+ import '../chunk-NUNKSZKU.js';
23
+ import '../chunk-YU2KUMGE.js';
24
+ import '../chunk-N5YEF3LC.js';
25
+ import { ArtifactCompareBar, ArtifactPreview, ArtifactCodeView, VersionTimeline } from '../chunk-65S53MZK.js';
26
+ import '../chunk-NS4JD2VR.js';
27
+ import '../chunk-LOJVUGBJ.js';
28
+ import { TabHeader } from '../chunk-4WWM3GQ5.js';
29
+ import '../chunk-OKERRHLH.js';
30
+ import '../chunk-7XF5SFJ2.js';
31
+ import { useRegisterOpenDocument, savedDocumentIdFor } from '../chunk-YBLIKTJK.js';
32
+ import '../chunk-AUS3KBHJ.js';
33
+ import { useIsPhone } from '../chunk-SLSBJRWW.js';
34
+ import '../chunk-NPLYHR2E.js';
35
+ import '../chunk-7F6CBP3Z.js';
36
+ import { PassageMark, NoteMark, LabelMark, PassagePill } from '../chunk-JAANWQGB.js';
37
+ import { useBlocksEnvironment } from '../chunk-TBEVGWY3.js';
38
+ import '../chunk-TX2ZICS7.js';
39
+ import { fmtDate } from '../chunk-OXF2IFXG.js';
40
+ import '../chunk-VUNV25KB.js';
41
+ import React, { memo, lazy, useMemo, useCallback, useState, useRef, useEffect, Suspense } from 'react';
42
+ import { MessageSquare, Mail, Languages, FileCheck2, MonitorPlay, Code, FileText, History } from 'lucide-react';
43
+ import { useArbi, refreshDocuments, arbiQueryKeys, useArbiSessionState, useArbiSessionStore, ImageCropModal, DEFAULT_ASPECT_OPTIONS, useDocumentVersionList, useDocument, useParsedDocument, hasVideoTrack, useFinaliseTranslation, DocIcon, XlsIcon, HtmlIcon, VidIcon, AudIcon, ImgIcon, EmlIcon, PdfIcon, useAssignDocTags, useUpdateDocTag, useRemoveDocTags } from '@arbidocs/react';
44
+ import { parseVersionRef, versionLabel, findVersion, documentVersions, toArtifactVersions, artifactKindFromMode, artifactKindFromFileName, useArtifactSource } from '@arbidocs/react/artifacts';
45
+ import { useOptionalDocumentTools, documentBytesKey, clientUpload, DocumentToolsProvider, useDocumentTools, useDocumentSignatures, useDocumentMarkup, canAnnotate, SIGNED_LOCKED_REASON, useDocumentBytes, fetchDocumentFile } from '@arbidocs/react/document-tools';
46
+ import { XlsxViewer, cycleZoom, VideoViewer, AudioViewer, ImageViewer, useProcessedChunks, useScrollAnchor, usePinchZoom, PdfViewer, computeSelectionRuns, usePageIntersectionObserver } from '@arbidocs/react/viewers';
47
+ import { MarkdownRenderer, Button, getEntityLabel, isImageFile, isVideoFile, isAudioFile, isDownloadOnlyFile, friendlyFileType, getEntityColor, TagEntity } from '@arbidocs/react/ui';
48
+ import { useQueryClient } from '@tanstack/react-query';
49
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
50
+
51
+ function ConnectedDocumentToolsProvider({ children }) {
52
+ const enclosing = useOptionalDocumentTools();
53
+ return enclosing ? /* @__PURE__ */ jsx(Fragment, { children }) : /* @__PURE__ */ jsx(OwnDocumentTools, { children });
54
+ }
55
+ function OwnDocumentTools({ children }) {
56
+ const arbi = useArbi();
57
+ const queryClient = useQueryClient();
58
+ const { user, ensureWorkspaceOpen } = useConnectedWorkspace();
59
+ const { notify: environmentNotify, openDocument: openInHost } = useBlocksEnvironment();
60
+ const client = arbi.isLoggedIn ? arbi.getClient().fetch : null;
61
+ const signer = useMemo(
62
+ () => user ? { name: user.name, email: user.email, externalId: user.externalId } : null,
63
+ [user]
64
+ );
65
+ const notify = useCallback(
66
+ (message, kind, options) => environmentNotify(message, kind, {
67
+ description: options?.description,
68
+ action: options?.action
69
+ }),
70
+ [environmentNotify]
71
+ );
72
+ const onDocumentsChanged = useCallback(
73
+ async (ids, change) => {
74
+ const refresh = [refreshDocuments(queryClient, arbi, ids)];
75
+ if (change === "signed" || change === "version")
76
+ for (const id of ids)
77
+ refresh.push(
78
+ queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documentVersions(id) }),
79
+ queryClient.invalidateQueries({ queryKey: documentBytesKey(id) })
80
+ );
81
+ await Promise.all(refresh);
82
+ },
83
+ [queryClient, arbi]
84
+ );
85
+ const uploadDocument = useCallback(
86
+ async (request) => {
87
+ if (!client) throw new Error("Sign in to save a copy.");
88
+ await ensureWorkspaceOpen();
89
+ return clientUpload(client)(request);
90
+ },
91
+ [client, ensureWorkspaceOpen]
92
+ );
93
+ const openDocument = useCallback((ref) => openInHost(ref), [openInHost]);
94
+ if (!client) return /* @__PURE__ */ jsx(Fragment, { children });
95
+ return /* @__PURE__ */ jsx(
96
+ DocumentToolsProvider,
97
+ {
98
+ client,
99
+ user: signer,
100
+ notify,
101
+ openDocument,
102
+ onDocumentsChanged,
103
+ uploadDocument,
104
+ children
105
+ }
106
+ );
107
+ }
108
+ var isTranslationDraft = (doc) => !!doc?.derived_from?.some((d) => d.role === "translation") && !doc.derived_from.some((d) => d.role === "final");
109
+ function FinaliseTranslationButton({
110
+ document: document2,
111
+ isCompact
112
+ }) {
113
+ const finalise = useFinaliseTranslation();
114
+ const { openDocument } = useDocumentTools();
115
+ const { notify } = useBlocksEnvironment();
116
+ if (!document2 || !isTranslationDraft(document2)) return null;
117
+ const pending = finalise.isPending;
118
+ const onClick = async () => {
119
+ try {
120
+ const { document_ext_id: finalId } = await finalise.mutateAsync(document2.external_id);
121
+ notify("Saved the final PDF of this translation", "success");
122
+ openDocument?.(finalId);
123
+ } catch (error) {
124
+ const detail = error?.detail;
125
+ notify(
126
+ typeof detail === "string" ? detail : "The final PDF could not be saved. Try again.",
127
+ "error"
128
+ );
129
+ }
130
+ };
131
+ return /* @__PURE__ */ jsxs(
132
+ Button,
133
+ {
134
+ type: "button",
135
+ variant: "outline",
136
+ size: isCompact ? "icon" : "sm",
137
+ title: "Finalise: save this translation as a new PDF, labelled Translation and linked to the original",
138
+ "aria-label": "Finalise",
139
+ "data-testid": "finalise-translation-button",
140
+ className: "pointer-coarse:min-h-11",
141
+ disabled: pending,
142
+ onClick: () => void onClick(),
143
+ children: [
144
+ /* @__PURE__ */ jsx(FileCheck2, { className: "size-4" }),
145
+ !isCompact && /* @__PURE__ */ jsx("span", { className: "ml-1", children: pending ? "Finalising\u2026" : "Finalise" })
146
+ ]
147
+ }
148
+ );
149
+ }
150
+ function useImageCrop(documentId, fileName, imageBlob) {
151
+ const { uploadDocument, onDocumentsChanged, openDocument } = useDocumentTools();
152
+ const { notify } = useBlocksEnvironment();
153
+ const [cropImageUrl, setCropImageUrl] = useState(null);
154
+ const handleOpenCrop = useCallback(() => {
155
+ if (!imageBlob) return;
156
+ setCropImageUrl(URL.createObjectURL(imageBlob));
157
+ }, [imageBlob]);
158
+ const closeCrop = useCallback(() => {
159
+ setCropImageUrl((url) => {
160
+ if (url) URL.revokeObjectURL(url);
161
+ return null;
162
+ });
163
+ }, []);
164
+ const handleCropComplete = useCallback(
165
+ async (result) => {
166
+ const baseName = (fileName || "image").replace(/\.[^.]+$/, "");
167
+ const file = new File([result.blob], `${baseName} (cropped).png`, { type: "image/png" });
168
+ try {
169
+ const response = await uploadDocument({
170
+ file,
171
+ query: { derived_from: [documentId], derived_role: "crop" }
172
+ });
173
+ const newDocId = response?.doc_ext_ids?.[0];
174
+ if (newDocId) {
175
+ await onDocumentsChanged?.([newDocId], "copy");
176
+ openDocument?.(newDocId);
177
+ }
178
+ notify("Cropped image saved", "success");
179
+ } catch {
180
+ notify("Failed to save the cropped image", "error");
181
+ } finally {
182
+ closeCrop();
183
+ }
184
+ },
185
+ [fileName, documentId, uploadDocument, onDocumentsChanged, openDocument, notify, closeCrop]
186
+ );
187
+ return { cropImageUrl, handleOpenCrop, closeCrop, handleCropComplete };
188
+ }
189
+ var DOCX_EXTENSIONS = /* @__PURE__ */ new Set([".docx", ".doc"]);
190
+ var XLSX_EXTENSIONS = /* @__PURE__ */ new Set([".xlsx", ".xls"]);
191
+ var EMAIL_EXTENSIONS = /* @__PURE__ */ new Set([".eml", ".msg"]);
192
+ function fileExtension(fileName) {
193
+ if (!fileName) return "";
194
+ return fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
195
+ }
196
+ function useViewedDocument(documentId) {
197
+ const support = useDocumentViewerSupport();
198
+ const [webmHasVideoTrack, setWebmHasVideoTrack] = useState(null);
199
+ useEffect(() => setWebmHasVideoTrack(null), [documentId]);
200
+ const streamingDoc = support.streamingDocuments?.[documentId];
201
+ const isStreaming = !!streamingDoc && !streamingDoc.isComplete;
202
+ const draftDoc = support.draftDocuments?.[documentId];
203
+ const isDraft = !!draftDoc;
204
+ const isCaptureDraft = draftDoc?.kind === "audio" || draftDoc?.kind === "photo" || draftDoc?.kind === "video";
205
+ const isTextDraft = draftDoc?.kind === "text";
206
+ const { workspaceId, live } = useConnectedWorkspace();
207
+ const { data: record } = useDocument(documentId, {
208
+ enabled: live && !!workspaceId && !isStreaming && !isDraft,
209
+ // A new version (Save version, a signed copy) is processed before its PDF exists: keep
210
+ // re-reading until it is done, so the PDF tab and the signing tools come back on their own.
211
+ pollWhileProcessing: true
212
+ });
213
+ const documentData = record?.external_id === documentId ? record : void 0;
214
+ const { data: tags } = useConnectedTags();
215
+ const labelSummaries = useMemo(
216
+ () => summariseDocTags(documentData?.doctags ?? [], tags.filter(isDocumentLabel)),
217
+ [documentData, tags]
218
+ );
219
+ const fileName = documentData?.file_name;
220
+ const isMarkdown = fileExtension(fileName) === ".md";
221
+ const isImage = isImageFile(fileName);
222
+ const isWebmFile = fileExtension(fileName) === ".webm";
223
+ const isVideo = isWebmFile && webmHasVideoTrack === false ? false : isVideoFile(fileName);
224
+ const isAudio = isWebmFile && webmHasVideoTrack === false ? true : isAudioFile(fileName);
225
+ const isBlobArtifact = streamingDoc?.mode === "image" || documentData?.wp_type === "artifact" && (isImage || isVideo || isAudio);
226
+ const isArtifact = (!!streamingDoc || isTextDraft || documentData?.wp_type === "artifact" || isMarkdown) && !isBlobArtifact;
227
+ const liveKind = isArtifact ? artifactKindFromMode(streamingDoc?.mode ?? void 0) ?? artifactKindFromFileName(fileName) : null;
228
+ const savedDocumentId = savedDocumentIdFor({
229
+ documentId,
230
+ isDraft,
231
+ isStreaming,
232
+ isBlobArtifact,
233
+ documentData
234
+ });
235
+ const { data: liveSourceFetched } = useArtifactSource(
236
+ documentId,
237
+ !!liveKind && !streamingDoc && !!documentData && !isDraft
238
+ );
239
+ const liveSource = streamingDoc ? streamingDoc.content : liveSourceFetched ?? "";
240
+ const hasParsedDocStatus = documentData?.status === "completed" || documentData?.status === "low-content";
241
+ const { data: parsedDoc, isLoading: isParsedDocLoading } = useParsedDocument(
242
+ documentId,
243
+ "final",
244
+ {
245
+ enabled: !!documentId && live && !isStreaming && !isDraft && !isBlobArtifact && hasParsedDocStatus
246
+ }
247
+ );
248
+ const hasParsedContent = (parsedDoc?.chunks?.length ?? 0) > 0;
249
+ return {
250
+ workspaceId,
251
+ documentData,
252
+ streamingDoc,
253
+ isStreaming,
254
+ draftDoc,
255
+ isDraft,
256
+ isCaptureDraft,
257
+ isTextDraft,
258
+ labelSummaries,
259
+ isImage,
260
+ isWebmFile,
261
+ setWebmHasVideoTrack,
262
+ isVideo,
263
+ isAudio,
264
+ isMedia: isVideo || isAudio,
265
+ isBlobArtifact,
266
+ savedDocumentId,
267
+ isArtifact,
268
+ liveKind,
269
+ liveSource,
270
+ isDocx: DOCX_EXTENSIONS.has(fileExtension(fileName)),
271
+ isXlsx: XLSX_EXTENSIONS.has(fileExtension(fileName)),
272
+ isEmail: EMAIL_EXTENSIONS.has(fileExtension(fileName)),
273
+ isDownloadOnly: isDownloadOnlyFile(fileName),
274
+ isParsedDocLoading,
275
+ hasParsedContent
276
+ };
277
+ }
278
+ function useViewerBlobs(documentId, doc) {
279
+ const { documentData, isArtifact, isDocx, isXlsx, isDownloadOnly, isWebmFile } = doc;
280
+ const { setWebmHasVideoTrack } = doc;
281
+ const { client, saveFile } = useDocumentTools();
282
+ const { notify } = useBlocksEnvironment();
283
+ const { loadOfflineCopy } = useDocumentViewerSupport();
284
+ const currentVersion = documentData?.current_version ?? 1;
285
+ const name = documentData?.file_name;
286
+ const original = isImageFile(name) || isVideoFile(name) || isAudioFile(name);
287
+ const fallback = loadOfflineCopy && documentData && !parseVersionRef(documentId).version ? () => loadOfflineCopy(documentData) : void 0;
288
+ const pdf = useDocumentBytes(documentId, {
289
+ version: currentVersion,
290
+ kind: original ? "original" : "pdf",
291
+ enabled: !isArtifact && !!documentData && !isDownloadOnly && (!isDocx || documentData.status === "completed" || documentData.status === "low-content"),
292
+ fallback
293
+ });
294
+ const [pdfBlob, setPdfBlob] = useState(null);
295
+ useEffect(() => setPdfBlob(null), [documentId]);
296
+ useEffect(() => {
297
+ if (pdf.data) setPdfBlob(pdf.data);
298
+ }, [pdf.data]);
299
+ useEffect(() => {
300
+ if (!isWebmFile || !pdfBlob) return;
301
+ let cancelled = false;
302
+ void hasVideoTrack(pdfBlob).then((result) => {
303
+ if (!cancelled) setWebmHasVideoTrack(result);
304
+ });
305
+ return () => {
306
+ cancelled = true;
307
+ };
308
+ }, [isWebmFile, pdfBlob, setWebmHasVideoTrack]);
309
+ const xlsx = useDocumentBytes(documentId, {
310
+ version: currentVersion,
311
+ kind: "original",
312
+ enabled: !isArtifact && !!documentData && isXlsx
313
+ });
314
+ const handleDirectDownload = useCallback(async () => {
315
+ try {
316
+ saveFile(await fetchDocumentFile(client, documentId), documentData?.file_name || "download");
317
+ } catch {
318
+ notify("Failed to download file", "error");
319
+ }
320
+ }, [client, saveFile, notify, documentId, documentData?.file_name]);
321
+ return {
322
+ pdfBlob,
323
+ isPdfLoading: pdf.isLoading,
324
+ pdfError: pdf.error,
325
+ xlsxBlob: xlsx.data ?? null,
326
+ xlsxError: xlsx.error,
327
+ handleDirectDownload
328
+ };
329
+ }
330
+ function useViewerTabs(doc, isCompact, hasHistory = false) {
331
+ const {
332
+ documentData,
333
+ isArtifact,
334
+ isDocx,
335
+ isXlsx,
336
+ isEmail,
337
+ isVideo,
338
+ isAudio,
339
+ isImage,
340
+ liveKind,
341
+ hasParsedContent,
342
+ isParsedDocLoading
343
+ } = doc;
344
+ const session = useArbiSessionStore();
345
+ const {
346
+ tab: activeTab,
347
+ compareId,
348
+ tabRequest,
349
+ phonePdfChosen
350
+ } = useArbiSessionState((s) => s.documentViewer);
351
+ const setActiveTab = (tab) => session.setDocumentViewer({ tab });
352
+ const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === "Text";
353
+ const isPhone = useIsPhone();
354
+ const phoneDefaultDecidedFor = useRef(null);
355
+ const hasDocumentData = !!documentData;
356
+ const documentKey = documentData?.external_id;
357
+ useEffect(() => {
358
+ if (isArtifact && (activeTab === "pdf" || !liveKind && activeTab === "docx")) {
359
+ setActiveTab(liveKind ? "preview" : "edit");
360
+ } else if (isDocx && activeTab === "pdf") {
361
+ setActiveTab("docx");
362
+ } else if (!liveKind && activeTab === "preview") {
363
+ setActiveTab(isArtifact ? "edit" : "pdf");
364
+ } else if (!isArtifact && documentData && activeTab === "edit") {
365
+ setActiveTab(isDocx ? "docx" : isXlsx ? "xlsx" : "pdf");
366
+ } else if (!isArtifact && !isDocx && !isXlsx && documentData && (activeTab === "docx" || activeTab === "xlsx")) {
367
+ setActiveTab("pdf");
368
+ }
369
+ }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind]);
370
+ useEffect(() => {
371
+ if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return;
372
+ phoneDefaultDecidedFor.current = documentKey;
373
+ session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab });
374
+ }, [documentKey, tabRequest]);
375
+ const hasVersionsTab = isArtifact || isDocx || hasHistory;
376
+ useEffect(() => {
377
+ if (activeTab === "versions" && documentData && !hasVersionsTab) {
378
+ setActiveTab(isXlsx ? "xlsx" : "pdf");
379
+ }
380
+ }, [activeTab, documentData, hasVersionsTab]);
381
+ useEffect(() => {
382
+ if (activeTab === "html" && documentData !== void 0 && !isParsedDocLoading && !hasParsedContent && !compareId) {
383
+ setActiveTab(isArtifact ? "edit" : isDocx ? "docx" : isXlsx ? "xlsx" : "pdf");
384
+ }
385
+ }, [
386
+ activeTab,
387
+ documentData,
388
+ isParsedDocLoading,
389
+ hasParsedContent,
390
+ compareId,
391
+ isArtifact,
392
+ isDocx,
393
+ isXlsx
394
+ ]);
395
+ useEffect(() => {
396
+ if (!isPhone || !documentKey || isParsedDocLoading) return;
397
+ if (phoneDefaultDecidedFor.current === documentKey) return;
398
+ phoneDefaultDecidedFor.current = documentKey;
399
+ const opensOnPdf = !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail;
400
+ if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === "pdf") {
401
+ setActiveTab("html");
402
+ }
403
+ }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent]);
404
+ const handleTabChange = (tabId) => {
405
+ const change = { tab: tabId };
406
+ if (tabId !== "html" && compareId) change.compareId = null;
407
+ if (isPhone && (tabId === "pdf" || tabId === "html")) change.phonePdfChosen = tabId === "pdf";
408
+ session.setDocumentViewer(change);
409
+ };
410
+ const mediaTab = isVideo ? { icon: /* @__PURE__ */ jsx(VidIcon, { size: 20 }), tooltip: "Video" } : isAudio ? { icon: /* @__PURE__ */ jsx(AudIcon, { size: 20 }), tooltip: "Audio" } : isImage ? { icon: /* @__PURE__ */ jsx(ImgIcon, { size: 20 }), tooltip: "Image" } : isEmail ? { icon: /* @__PURE__ */ jsx(EmlIcon, { size: 20 }), tooltip: "Email" } : isTextFile ? { icon: /* @__PURE__ */ jsx(FileText, { className: "size-5" }), tooltip: "Text" } : documentData ? { icon: /* @__PURE__ */ jsx(PdfIcon, { size: 20 }), tooltip: "PDF" } : (
411
+ // The file type is unknown until the record loads: name no guess (a text file
412
+ // would flip from PDF to Text once it arrives).
413
+ { icon: /* @__PURE__ */ jsx(FileText, { className: "size-5" }), tooltip: "Document" }
414
+ );
415
+ const tabLabel = (id, label) => !isCompact || activeTab === id || id === "html" ? label : void 0;
416
+ const versionsTab = {
417
+ id: "versions",
418
+ icon: /* @__PURE__ */ jsx(History, { className: "size-5" }),
419
+ tooltip: "Versions",
420
+ label: tabLabel("versions", "Versions")
421
+ };
422
+ const viewerTabs = [
423
+ ...isArtifact ? [
424
+ ...liveKind ? [
425
+ {
426
+ id: "preview",
427
+ icon: /* @__PURE__ */ jsx(MonitorPlay, { className: "size-5" }),
428
+ tooltip: "Preview",
429
+ label: tabLabel("preview", "Preview")
430
+ }
431
+ ] : [],
432
+ {
433
+ id: "edit",
434
+ icon: liveKind ? /* @__PURE__ */ jsx(Code, { className: "size-5" }) : /* @__PURE__ */ jsx(FileText, { className: "size-5" }),
435
+ tooltip: liveKind ? "Code" : "Editor",
436
+ label: tabLabel("edit", liveKind ? "Code" : "Document")
437
+ },
438
+ versionsTab
439
+ ] : [
440
+ ...isDocx ? [
441
+ {
442
+ id: "docx",
443
+ icon: /* @__PURE__ */ jsx(DocIcon, { size: 20 }),
444
+ tooltip: "DOCX (with track changes & comments)",
445
+ label: tabLabel("docx", "DOCX")
446
+ }
447
+ ] : [],
448
+ ...isXlsx ? [
449
+ {
450
+ id: "xlsx",
451
+ icon: /* @__PURE__ */ jsx(XlsIcon, { size: 20 }),
452
+ tooltip: "Spreadsheet",
453
+ label: tabLabel("xlsx", "Sheet")
454
+ }
455
+ ] : [],
456
+ { id: "pdf", ...mediaTab, label: tabLabel("pdf", mediaTab.tooltip) },
457
+ ...hasVersionsTab ? [versionsTab] : []
458
+ ],
459
+ ...(hasParsedContent || compareId) && !liveKind ? [
460
+ {
461
+ id: "html",
462
+ icon: compareId ? /* @__PURE__ */ jsx(FileText, { className: "size-5" }) : /* @__PURE__ */ jsx(HtmlIcon, { size: 20 }),
463
+ tooltip: compareId ? "Word redline" : "HTML",
464
+ label: tabLabel("html", compareId ? "Compare" : "HTML")
465
+ }
466
+ ] : []
467
+ ];
468
+ return { activeTab, handleTabChange, viewerTabs };
469
+ }
470
+ function useViewerVersions(docId) {
471
+ const plainId = docId ? parseVersionRef(docId).docId : "";
472
+ const { data: documents } = useConnectedDocuments();
473
+ const listed = useMemo(
474
+ () => plainId ? documents.find((d) => d.external_id === plainId) : void 0,
475
+ [documents, plainId]
476
+ );
477
+ const { data: history } = useDocumentVersionList(plainId, { enabled: !!plainId && !listed });
478
+ const versions = useMemo(
479
+ () => listed ? documentVersions(listed) : toArtifactVersions(plainId || null, history),
480
+ [listed, history, plainId]
481
+ );
482
+ const translations = useMemo(() => {
483
+ if (!plainId) return [];
484
+ return documents.flatMap((doc) => {
485
+ const link = doc.derived_from?.find(
486
+ (d) => d.role === "translation" && d.doc_ext_id === plainId
487
+ );
488
+ return link ? [
489
+ {
490
+ id: doc.external_id,
491
+ name: doc.doc_metadata?.title || doc.file_name || doc.external_id,
492
+ createdAt: doc.created_at,
493
+ sourceVersion: link.version ?? null,
494
+ final: !!doc.derived_from?.some((d) => d.role === "final")
495
+ }
496
+ ] : [];
497
+ }).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
498
+ }, [documents, plainId]);
499
+ return { versions, translations };
500
+ }
501
+
502
+ // src/connection/viewer/parsed/document-tags.ts
503
+ function isDocumentTag(tag) {
504
+ if (tag.kind === "search") return false;
505
+ const onDocs = (tag.doctag_count ?? 0) > 0;
506
+ const onFacts = (tag.facttag_count ?? 0) > 0;
507
+ return onDocs || !onFacts;
508
+ }
509
+ function hasChunkInCitations(citations, chunkExtId) {
510
+ return (citations ?? []).some((d) => d.chunks?.some((c) => c.chunk_id === chunkExtId));
511
+ }
512
+ function removeChunkFromCitations(citations, chunkExtId) {
513
+ if (!citations) return null;
514
+ const next = citations.map((d) => ({ ...d, chunks: (d.chunks ?? []).filter((c) => c.chunk_id !== chunkExtId) })).filter((d) => d.chunks.length > 0);
515
+ return next.length ? next : null;
516
+ }
517
+ function addChunkToCitations(citations, documentId, chunkExtId) {
518
+ const chunk = { chunk_id: chunkExtId, page: null };
519
+ const list = citations ?? [];
520
+ const idx = list.findIndex((d) => d.doc_ext_id === documentId);
521
+ if (idx === -1) return [...list, { doc_ext_id: documentId, chunks: [chunk] }];
522
+ const doc = list[idx];
523
+ if ((doc.chunks ?? []).some((c) => c.chunk_id === chunkExtId)) return list;
524
+ const next = [...list];
525
+ next[idx] = { ...doc, chunks: [...doc.chunks ?? [], chunk] };
526
+ return next;
527
+ }
528
+ function useChunkTagging({ documentId, documentDoctags }) {
529
+ const createDocTag = useAssignDocTags();
530
+ const updateDocTag = useUpdateDocTag();
531
+ const deleteDocTag = useRemoveDocTags();
532
+ const getChunkTagState = useCallback(
533
+ (chunkExtId) => {
534
+ const appliedTags = documentDoctags.filter(
535
+ (dt) => hasChunkInCitations(dt.citations, chunkExtId)
536
+ );
537
+ const isTagApplied = (tagExtId) => {
538
+ return appliedTags.some((dt) => dt.tag_ext_id === tagExtId);
539
+ };
540
+ const getDoctagForChunk = (tagExtId) => {
541
+ return appliedTags.find((dt) => dt.tag_ext_id === tagExtId);
542
+ };
543
+ return {
544
+ appliedTags,
545
+ isTagApplied,
546
+ getDoctagForChunk
547
+ };
548
+ },
549
+ [documentDoctags]
550
+ );
551
+ const toggleChunkTag = useCallback(
552
+ async (chunkExtId, tag, note) => {
553
+ const existingDoctag = documentDoctags.find((dt) => dt.tag_ext_id === tag.external_id);
554
+ const isChunkTagged = hasChunkInCitations(existingDoctag?.citations, chunkExtId);
555
+ if (isChunkTagged) {
556
+ const updatedCitations = removeChunkFromCitations(existingDoctag.citations, chunkExtId);
557
+ if (!updatedCitations) {
558
+ await deleteDocTag.mutateAsync({
559
+ tagId: tag.external_id,
560
+ docIds: [documentId]
561
+ });
562
+ } else {
563
+ await updateDocTag.mutateAsync({
564
+ tagId: tag.external_id,
565
+ docId: documentId,
566
+ citations: updatedCitations,
567
+ note: existingDoctag.note
568
+ });
569
+ }
570
+ } else {
571
+ if (existingDoctag) {
572
+ const updatedCitations = addChunkToCitations(
573
+ existingDoctag.citations,
574
+ documentId,
575
+ chunkExtId
576
+ );
577
+ await updateDocTag.mutateAsync({
578
+ tagId: tag.external_id,
579
+ docId: documentId,
580
+ citations: updatedCitations,
581
+ note: note ?? existingDoctag.note
582
+ });
583
+ } else {
584
+ const newCitations = addChunkToCitations(null, documentId, chunkExtId);
585
+ await createDocTag.mutateAsync({
586
+ tagId: tag.external_id,
587
+ docIds: [documentId],
588
+ citations: newCitations,
589
+ note
590
+ });
591
+ }
592
+ }
593
+ },
594
+ [documentId, documentDoctags, createDocTag, updateDocTag, deleteDocTag]
595
+ );
596
+ const updateChunkTagNote = useCallback(
597
+ async (_chunkExtId, tag, note) => {
598
+ const existingDoctag = documentDoctags.find((dt) => dt.tag_ext_id === tag.external_id);
599
+ if (!existingDoctag) return;
600
+ await updateDocTag.mutateAsync({
601
+ tagId: tag.external_id,
602
+ docId: documentId,
603
+ citations: existingDoctag.citations,
604
+ note
605
+ });
606
+ },
607
+ [documentId, documentDoctags, updateDocTag]
608
+ );
609
+ const getChunkTagColors = useCallback(
610
+ (chunkExtId, workspaceTags) => {
611
+ const { appliedTags } = getChunkTagState(chunkExtId);
612
+ return appliedTags.map((dt) => {
613
+ const tag = workspaceTags.find((t) => t.external_id === dt.tag_ext_id);
614
+ return tag?.external_id;
615
+ }).filter((id) => !!id);
616
+ },
617
+ [getChunkTagState]
618
+ );
619
+ const isLoading = createDocTag.isPending || updateDocTag.isPending || deleteDocTag.isPending;
620
+ return {
621
+ getChunkTagState,
622
+ toggleChunkTag,
623
+ updateChunkTagNote,
624
+ getChunkTagColors,
625
+ isLoading
626
+ };
627
+ }
628
+ var GROUP_TITLES = {
629
+ checkbox: "Label",
630
+ select: "Choice",
631
+ text: "Text",
632
+ number: "Number"
633
+ };
634
+ function PassageTagPanel({
635
+ documentId,
636
+ chunkExtId,
637
+ chunkContent,
638
+ pageNumber,
639
+ documentDoctags,
640
+ onClose,
641
+ onViewTaggedChunks
642
+ }) {
643
+ const { createTag } = useDocumentViewerSupport();
644
+ const [editingNoteTagId, setEditingNoteTagId] = useState(null);
645
+ const [noteValue, setNoteValue] = useState("");
646
+ const { data: allTags } = useConnectedTags();
647
+ const workspaceTags = useMemo(() => allTags.filter(isDocumentTag), [allTags]);
648
+ const { getChunkTagState, toggleChunkTag, updateChunkTagNote, isLoading } = useChunkTagging({
649
+ documentId,
650
+ documentDoctags
651
+ });
652
+ const chunkState = useMemo(() => getChunkTagState(chunkExtId), [getChunkTagState, chunkExtId]);
653
+ const groupedTags = useMemo(() => {
654
+ const groups2 = {
655
+ checkbox: [],
656
+ select: [],
657
+ text: [],
658
+ number: []
659
+ };
660
+ workspaceTags.forEach((tag) => {
661
+ const group = tag.kind === "label" ? "checkbox" : tag.kind === "annotation" ? tag.tag_type.type : null;
662
+ if (group && groups2[group]) {
663
+ groups2[group].push(tag);
664
+ }
665
+ });
666
+ return groups2;
667
+ }, [workspaceTags]);
668
+ const handleToggleTag = useCallback(
669
+ async (tag) => {
670
+ try {
671
+ await toggleChunkTag(chunkExtId, tag);
672
+ } catch (error) {
673
+ console.error("Failed to toggle chunk tag:", error);
674
+ }
675
+ },
676
+ [chunkExtId, toggleChunkTag]
677
+ );
678
+ const handleStartEditNote = useCallback(
679
+ (tagExtId) => {
680
+ const doctag = chunkState.getDoctagForChunk(tagExtId);
681
+ setNoteValue(doctag?.note || "");
682
+ setEditingNoteTagId(tagExtId);
683
+ },
684
+ [chunkState]
685
+ );
686
+ const handleSaveNote = useCallback(
687
+ async (tag) => {
688
+ try {
689
+ await updateChunkTagNote(chunkExtId, tag, noteValue || null);
690
+ } catch (error) {
691
+ console.error("Failed to save note:", error);
692
+ }
693
+ setEditingNoteTagId(null);
694
+ setNoteValue("");
695
+ },
696
+ [chunkExtId, noteValue, updateChunkTagNote]
697
+ );
698
+ const preview = useMemo(() => {
699
+ const maxLength = 200;
700
+ if (chunkContent.length <= maxLength) return chunkContent;
701
+ return chunkContent.slice(0, maxLength) + "...";
702
+ }, [chunkContent]);
703
+ const groups = useMemo(
704
+ () => Object.entries(groupedTags).filter(([, tags]) => tags.length > 0).map(([type, tags]) => ({
705
+ id: type,
706
+ title: GROUP_TITLES[type] ?? type,
707
+ tags: tags.map((tag) => ({
708
+ id: tag.external_id,
709
+ color: getEntityColor(tag.external_id, "medium"),
710
+ isApplied: chunkState.isTagApplied(tag.external_id),
711
+ note: chunkState.getDoctagForChunk(tag.external_id)?.note,
712
+ badge: /* @__PURE__ */ jsx(TagEntity, { tag, size: "sm", showTooltip: false })
713
+ }))
714
+ })),
715
+ [groupedTags, chunkState]
716
+ );
717
+ const tagById = useMemo(
718
+ () => new Map(workspaceTags.map((tag) => [tag.external_id, tag])),
719
+ [workspaceTags]
720
+ );
721
+ return /* @__PURE__ */ jsx(
722
+ TagPassagePanel,
723
+ {
724
+ pageNumber,
725
+ preview,
726
+ groups,
727
+ isEmpty: workspaceTags.length === 0,
728
+ isBusy: isLoading,
729
+ editingNoteTagId,
730
+ noteValue,
731
+ onNoteChange: setNoteValue,
732
+ onToggle: (id) => {
733
+ const tag = tagById.get(id);
734
+ if (tag) void handleToggleTag(tag);
735
+ },
736
+ onViewTagged: onViewTaggedChunks,
737
+ onStartNote: handleStartEditNote,
738
+ onSaveNote: (id) => {
739
+ const tag = tagById.get(id);
740
+ if (tag) void handleSaveNote(tag);
741
+ },
742
+ onCancelNote: () => {
743
+ setEditingNoteTagId(null);
744
+ setNoteValue("");
745
+ },
746
+ onCreate: createTag,
747
+ onClose
748
+ }
749
+ );
750
+ }
751
+ var ParsedPassage = memo(function ParsedPassage2({
752
+ chunk,
753
+ pageNumber,
754
+ isHighlighted,
755
+ isSelected,
756
+ isCitationHighlight,
757
+ isActiveCitation,
758
+ factCitationActive,
759
+ isCitationMode,
760
+ runIsStart,
761
+ runIsEnd,
762
+ runEndIndex,
763
+ labels,
764
+ activeTagColor,
765
+ onTagPassage,
766
+ onShowLabel,
767
+ onRemoveLabel,
768
+ onChunkClick,
769
+ formatChunkWithCitation,
770
+ getPassageDeepLink,
771
+ copyToClipboard,
772
+ onOpenNavigator
773
+ }) {
774
+ const chunkId = chunk.chunkExtId;
775
+ const formattedContent = chunkId ? formatChunkWithCitation(chunk.content, pageNumber || void 0, chunkId) : "";
776
+ const isStrong = isActiveCitation || !factCitationActive && isSelected;
777
+ const isLight = isCitationHighlight || !factCitationActive && isHighlighted;
778
+ const ownIndex = chunk.chunkIndex !== void 0 ? chunk.chunkIndex + 1 : void 0;
779
+ const runLabel = runEndIndex !== void 0 && ownIndex !== void 0 && runEndIndex > ownIndex ? `\xB6${ownIndex}\u2013${runEndIndex}` : `\xB6${ownIndex ?? ""}`;
780
+ const showLabel = !!chunkId && (!isSelected || runIsStart);
781
+ const copyPassage = (type, text, href) => copyToClipboard(text, {
782
+ type,
783
+ documentTitle: chunk.docTitle || "Document",
784
+ pageNumber: pageNumber || void 0,
785
+ passageIndex: chunk.chunkIndex,
786
+ passageContent: formattedContent,
787
+ href
788
+ });
789
+ const passageItems = chunkId ? [
790
+ {
791
+ id: "copy-passage",
792
+ label: "Copy passage with citation",
793
+ primary: true,
794
+ testId: "passage-copy",
795
+ onSelect: () => copyPassage("passage", formattedContent, getPassageDeepLink(chunkId) || void 0)
796
+ },
797
+ {
798
+ id: "copy-link",
799
+ label: "Copy passage link",
800
+ testId: "passage-copy-link",
801
+ onSelect: () => {
802
+ const link = getPassageDeepLink(chunkId);
803
+ if (link) copyPassage("link", link, link);
804
+ }
805
+ },
806
+ ...onTagPassage ? [
807
+ {
808
+ id: "label",
809
+ label: "Label this passage",
810
+ testId: "passage-label",
811
+ onSelect: () => onTagPassage(chunkId)
812
+ }
813
+ ] : [],
814
+ ...onOpenNavigator ? [
815
+ {
816
+ id: "navigator",
817
+ label: "Open in navigator",
818
+ testId: "passage-navigator",
819
+ onSelect: onOpenNavigator
820
+ }
821
+ ] : []
822
+ ] : [];
823
+ const labelItems = chunkId ? labels.flatMap((l, i) => {
824
+ const suffix = labels.length > 1 ? ` \u201C${l.name}\u201D` : " label";
825
+ return [
826
+ ...onShowLabel ? [
827
+ {
828
+ id: `show-${l.tagExtId}`,
829
+ label: `Show${suffix}`,
830
+ primary: i === 0,
831
+ testId: "label-show",
832
+ onSelect: () => onShowLabel(l.tagExtId)
833
+ }
834
+ ] : [],
835
+ ...onRemoveLabel ? [
836
+ {
837
+ id: `remove-${l.tagExtId}`,
838
+ label: `Remove${suffix}`,
839
+ destructive: true,
840
+ testId: "label-remove",
841
+ onSelect: () => onRemoveLabel(chunkId, l.tagExtId)
842
+ }
843
+ ] : []
844
+ ];
845
+ }) : [];
846
+ return /* @__PURE__ */ jsx(
847
+ HtmlPassage,
848
+ {
849
+ chunkId,
850
+ highlight: isStrong ? "strong" : isLight ? "light" : void 0,
851
+ isHit: isHighlighted,
852
+ isSelected,
853
+ runIsStart,
854
+ runIsEnd,
855
+ isClickable: isCitationMode,
856
+ onSelect: onChunkClick && chunkId ? (extend) => onChunkClick(chunkId, extend) : void 0,
857
+ isTagged: labels.length > 0,
858
+ activeTagColor,
859
+ tagMark: labels.length > 0 ? /* @__PURE__ */ jsx(
860
+ LabelMark,
861
+ {
862
+ colors: labels.map((l) => l.color),
863
+ name: `Labels: ${labels.map((l) => l.name).join(", ")}`,
864
+ menuLabel: "Label actions",
865
+ testId: `passage-tag-dots-${chunkId}`,
866
+ preview: /* @__PURE__ */ jsx("span", { className: "block font-medium", children: labels.map((l) => l.name).join(", ") }),
867
+ items: labelItems
868
+ }
869
+ ) : void 0,
870
+ runMarker: isSelected && runIsStart ? /* @__PURE__ */ jsx(
871
+ NoteMark,
872
+ {
873
+ label: runLabel,
874
+ title: "Cited by this note \u2014 click a passage to add, shift-click for a range",
875
+ testId: `note-marker-${chunkId}`
876
+ }
877
+ ) : void 0,
878
+ mark: showLabel && chunkId ? /* @__PURE__ */ jsx(
879
+ PassageMark,
880
+ {
881
+ label: runLabel,
882
+ menuLabel: "Passage actions",
883
+ testId: `passage-mark-${chunkId}`,
884
+ items: passageItems
885
+ }
886
+ ) : void 0,
887
+ children: /* @__PURE__ */ jsx(MarkdownRenderer, { children: chunk.content })
888
+ }
889
+ );
890
+ });
891
+
892
+ // src/connection/viewer/parsed/citation-line.ts
893
+ function formatCitation(data) {
894
+ const { documentTitle, documentDate, pageNumber } = data;
895
+ let citation = "";
896
+ if (documentTitle) {
897
+ citation += `${documentTitle}`;
898
+ }
899
+ if (documentDate) {
900
+ citation += documentTitle ? `, ${documentDate}` : documentDate;
901
+ }
902
+ if (pageNumber) {
903
+ citation += citation ? `, p. ${pageNumber}` : `p. ${pageNumber}`;
904
+ }
905
+ return citation;
906
+ }
907
+
908
+ // src/connection/viewer/parsed/usePassageCopy.ts
909
+ function usePassageCopy({
910
+ documentId,
911
+ documentData,
912
+ selectedWorkspaceId
913
+ }) {
914
+ const { notify, runtimeConfig } = useBlocksEnvironment();
915
+ const deploymentDomain = runtimeConfig.deploymentDomain;
916
+ const formatChunkWithCitation = useCallback(
917
+ (chunkContent, pageNumber, chunkExtId) => {
918
+ const docDate = documentData?.doc_metadata?.doc_date;
919
+ const citation = formatCitation({
920
+ documentTitle: documentData?.doc_metadata?.title || documentData?.file_name || "",
921
+ documentDate: docDate ? new Date(docDate).toISOString().split("T")[0] : void 0,
922
+ pageNumber
923
+ });
924
+ const deepLinkUrl = selectedWorkspaceId && documentId && chunkExtId ? buildDeepLinkUrl(
925
+ { workspaceId: selectedWorkspaceId, documentId, chunkId: chunkExtId },
926
+ deploymentDomain
927
+ ) : "";
928
+ let result = `"${chunkContent.trim()}"`;
929
+ if (citation) {
930
+ result += `
931
+
932
+ \u2014 ${citation}`;
933
+ }
934
+ if (deepLinkUrl) {
935
+ result += `
936
+ [ARBI Docs link](${deepLinkUrl})`;
937
+ }
938
+ return result;
939
+ },
940
+ [documentData, selectedWorkspaceId, documentId, deploymentDomain]
941
+ );
942
+ const getPassageDeepLink = useCallback(
943
+ (chunkExtId) => {
944
+ if (!selectedWorkspaceId || !documentId || !chunkExtId) {
945
+ return "";
946
+ }
947
+ return buildDeepLinkUrl(
948
+ { workspaceId: selectedWorkspaceId, documentId, chunkId: chunkExtId },
949
+ deploymentDomain
950
+ );
951
+ },
952
+ [selectedWorkspaceId, documentId, deploymentDomain]
953
+ );
954
+ const copyToClipboard = useCallback(
955
+ async (text, passageInfo) => {
956
+ try {
957
+ if (passageInfo?.href) {
958
+ const isLink = passageInfo.type === "link";
959
+ const { documentTitle, pageNumber, passageIndex, href } = passageInfo;
960
+ const pageNotation = pageNumber ? `p.${pageNumber}` : "";
961
+ const passageNotation = passageIndex !== void 0 ? `(${passageIndex})` : "";
962
+ const citation = `${documentTitle}${pageNotation ? `, ${pageNotation}${passageNotation}` : ""}`;
963
+ let html;
964
+ let plainText;
965
+ if (isLink) {
966
+ html = `<a href="${href}" target="_blank" rel="noopener noreferrer">${citation}</a>`;
967
+ plainText = href;
968
+ } else {
969
+ const linkHtml = `<p><a href="${href}" target="_blank" rel="noopener noreferrer">${citation}</a></p>`;
970
+ html = `${linkHtml}<blockquote style="margin: 8px 0; padding-left: 12px; border-left: 3px solid #ccc;">${text}</blockquote>`;
971
+ plainText = `${href}
972
+
973
+ ${text}
974
+
975
+ \u2014 ${citation}`;
976
+ }
977
+ const clipboardItem = new ClipboardItem({
978
+ "text/html": new Blob([html], { type: "text/html" }),
979
+ "text/plain": new Blob([plainText], { type: "text/plain" })
980
+ });
981
+ await navigator.clipboard.write([clipboardItem]);
982
+ const prefix = isLink ? "Link copied:" : "Passage copied:";
983
+ const notificationElement = React.createElement(
984
+ "span",
985
+ { className: "inline-flex items-center gap-2" },
986
+ prefix,
987
+ React.createElement(PassagePill, {
988
+ icon: React.createElement(HtmlIcon, { size: 16, className: "flex-shrink-0" }),
989
+ documentTitle: passageInfo.documentTitle,
990
+ pageNumber: passageInfo.pageNumber,
991
+ passageIndex: passageInfo.passageIndex,
992
+ href: passageInfo.href,
993
+ onClick: (e) => e.stopPropagation(),
994
+ showTooltip: false
995
+ })
996
+ );
997
+ notify(notificationElement, "success", {
998
+ workspaceId: selectedWorkspaceId || void 0,
999
+ // The bell entry deep-links back to the copied passage.
1000
+ href: passageInfo.href
1001
+ });
1002
+ } else {
1003
+ await navigator.clipboard.writeText(text);
1004
+ notify("Copied to clipboard", "success");
1005
+ }
1006
+ } catch (err) {
1007
+ console.error("Clipboard copy failed:", err);
1008
+ notify("Failed to copy to clipboard.", "error");
1009
+ }
1010
+ },
1011
+ [selectedWorkspaceId, notify]
1012
+ );
1013
+ return {
1014
+ formatChunkWithCitation,
1015
+ getPassageDeepLink,
1016
+ copyToClipboard
1017
+ };
1018
+ }
1019
+ function useDocumentLabels(documentId, doctags, orderedChunkIds) {
1020
+ const { data: allTags } = useConnectedTags();
1021
+ const workspaceTags = useMemo(() => allTags.filter(isDocumentTag), [allTags]);
1022
+ const documentDoctags = useMemo(() => doctags ?? [], [doctags]);
1023
+ const tagSummaries = useMemo(
1024
+ () => summariseDocTags(documentDoctags, workspaceTags),
1025
+ [documentDoctags, workspaceTags]
1026
+ );
1027
+ const labelSummaries = useMemo(
1028
+ () => summariseDocTags(documentDoctags, workspaceTags.filter(isDocumentLabel)),
1029
+ [documentDoctags, workspaceTags]
1030
+ );
1031
+ const labelsByChunk = useMemo(() => {
1032
+ const map = /* @__PURE__ */ new Map();
1033
+ for (const s of tagSummaries) {
1034
+ const label = {
1035
+ tagExtId: s.tagExtId,
1036
+ name: s.name,
1037
+ color: getEntityColor(s.tagExtId, "medium")
1038
+ };
1039
+ for (const id of s.chunkIds) {
1040
+ const list = map.get(id);
1041
+ if (list) list.push(label);
1042
+ else map.set(id, [label]);
1043
+ }
1044
+ }
1045
+ return map;
1046
+ }, [tagSummaries]);
1047
+ const { toggleChunkTag } = useChunkTagging({ documentId, documentDoctags });
1048
+ const removeLabel = useCallback(
1049
+ async (chunkExtId, tagExtId) => {
1050
+ const tag = workspaceTags.find((t) => t.external_id === tagExtId);
1051
+ if (!tag) return;
1052
+ try {
1053
+ await toggleChunkTag(chunkExtId, tag);
1054
+ } catch (error) {
1055
+ console.error("Failed to remove passage label", error);
1056
+ }
1057
+ },
1058
+ [workspaceTags, toggleChunkTag]
1059
+ );
1060
+ const [activeTagExtId, setActiveTagExtId] = useState(null);
1061
+ const [tagCursor, setTagCursor] = useState(0);
1062
+ const [taggingChunkId, setTaggingChunkId] = useState(null);
1063
+ const activeTagSummary = tagSummaries.find((t) => t.tagExtId === activeTagExtId);
1064
+ const activeTagColor = activeTagExtId ? getEntityColor(activeTagExtId, "medium") : void 0;
1065
+ const activeChunkIds = useMemo(
1066
+ () => new Set(activeTagSummary?.chunkIds ?? []),
1067
+ [activeTagSummary]
1068
+ );
1069
+ const orderedActiveIds = useMemo(
1070
+ () => orderedChunkIds.filter((id) => activeChunkIds.has(id)),
1071
+ [orderedChunkIds, activeChunkIds]
1072
+ );
1073
+ const gotoTagged = useCallback(
1074
+ (delta) => {
1075
+ if (orderedActiveIds.length === 0) return;
1076
+ const next = (tagCursor + delta + orderedActiveIds.length) % orderedActiveIds.length;
1077
+ setTagCursor(next);
1078
+ document.getElementById(orderedActiveIds[next])?.scrollIntoView({ behavior: "smooth", block: "center" });
1079
+ },
1080
+ [tagCursor, orderedActiveIds]
1081
+ );
1082
+ const selectTag = useCallback((tagExtId) => {
1083
+ setActiveTagExtId(tagExtId);
1084
+ setTagCursor(0);
1085
+ }, []);
1086
+ useEffect(() => {
1087
+ if (!activeTagExtId || orderedActiveIds.length === 0) return;
1088
+ document.getElementById(orderedActiveIds[0])?.scrollIntoView({ behavior: "smooth", block: "center" });
1089
+ }, [activeTagExtId]);
1090
+ return {
1091
+ documentDoctags,
1092
+ labelSummaries,
1093
+ labelsByChunk,
1094
+ removeLabel,
1095
+ activeTagExtId,
1096
+ activeTagColor,
1097
+ activeChunkIds,
1098
+ tagCursor,
1099
+ gotoTagged,
1100
+ selectTag,
1101
+ taggingChunkId,
1102
+ setTaggingChunkId
1103
+ };
1104
+ }
1105
+ var NONE = [];
1106
+ var noop = () => {
1107
+ };
1108
+ function useCitationSelection({
1109
+ documentId,
1110
+ containerRef,
1111
+ processedChunks,
1112
+ orderedChunkIds,
1113
+ pageOf
1114
+ }) {
1115
+ const { passageCitation } = useDocumentViewerSupport();
1116
+ const activeCitationContext = passageCitation?.active ?? null;
1117
+ const setPendingPassagesForCitation = passageCitation?.pick ?? noop;
1118
+ const setUnselectedPassagesForCitation = passageCitation?.unpick ?? noop;
1119
+ const viewingPassageId = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null);
1120
+ const [selectedChunks, setSelectedChunks] = useState(/* @__PURE__ */ new Set());
1121
+ const selectedChunksRef = useRef(selectedChunks);
1122
+ selectedChunksRef.current = selectedChunks;
1123
+ const selectionAnchorRef = useRef(null);
1124
+ const factCitationChunkIds = passageCitation?.highlighted ?? NONE;
1125
+ const factCitationSet = useMemo(() => new Set(factCitationChunkIds), [factCitationChunkIds]);
1126
+ const factCitationActive = factCitationSet.size > 0;
1127
+ const factCitationSetRef = useRef(factCitationSet);
1128
+ factCitationSetRef.current = factCitationSet;
1129
+ const isCitationMode = !!activeCitationContext && activeCitationContext.documentId === documentId;
1130
+ const selectionRuns = useMemo(
1131
+ () => computeSelectionRuns(processedChunks, selectedChunks),
1132
+ [processedChunks, selectedChunks]
1133
+ );
1134
+ const runStartIds = useMemo(
1135
+ () => orderedChunkIds.filter((id) => selectionRuns.get(id)?.isStart),
1136
+ [orderedChunkIds, selectionRuns]
1137
+ );
1138
+ const [runCursor, setRunCursor] = useState(0);
1139
+ const gotoRun = useCallback(
1140
+ (delta) => {
1141
+ if (runStartIds.length === 0) return;
1142
+ const next = (runCursor + delta + runStartIds.length) % runStartIds.length;
1143
+ setRunCursor(next);
1144
+ document.getElementById(runStartIds[next])?.scrollIntoView({ behavior: "smooth", block: "center" });
1145
+ },
1146
+ [runCursor, runStartIds]
1147
+ );
1148
+ useEffect(() => {
1149
+ if (runCursor >= runStartIds.length) setRunCursor(0);
1150
+ }, [runStartIds.length, runCursor]);
1151
+ useEffect(() => {
1152
+ setSelectedChunks(/* @__PURE__ */ new Set());
1153
+ }, [activeCitationContext?.key, activeCitationContext?.documentId]);
1154
+ const handleSelectionEnd = useCallback(() => {
1155
+ if (!activeCitationContext || activeCitationContext.documentId !== documentId) return;
1156
+ const selection = window.getSelection();
1157
+ if (!selection || selection.isCollapsed || selection.rangeCount === 0) return;
1158
+ const container = containerRef.current;
1159
+ if (!container) return;
1160
+ const newSelectedChunks = /* @__PURE__ */ new Set();
1161
+ container.querySelectorAll("[data-chunk-id]").forEach((el) => {
1162
+ const chunkId = el.getAttribute("data-chunk-id");
1163
+ if (!chunkId) return;
1164
+ if (selection.containsNode(el, true)) newSelectedChunks.add(chunkId);
1165
+ });
1166
+ if (newSelectedChunks.size > 0) {
1167
+ setSelectedChunks((prev) => /* @__PURE__ */ new Set([...prev, ...newSelectedChunks]));
1168
+ setPendingPassagesForCitation(
1169
+ Array.from(newSelectedChunks).map((id) => ({ chunk_id: id, page: pageOf(id) }))
1170
+ );
1171
+ }
1172
+ selection.removeAllRanges();
1173
+ }, [activeCitationContext, documentId, containerRef, setPendingPassagesForCitation, pageOf]);
1174
+ const handleChunkClick = useCallback(
1175
+ (chunkId, extendFromAnchor) => {
1176
+ if (!activeCitationContext || activeCitationContext.documentId !== documentId) return;
1177
+ const anchorId = selectionAnchorRef.current;
1178
+ const anchorIdx = anchorId ? orderedChunkIds.indexOf(anchorId) : -1;
1179
+ const targetIdx = orderedChunkIds.indexOf(chunkId);
1180
+ if (extendFromAnchor && anchorIdx !== -1 && targetIdx !== -1) {
1181
+ const [from, to] = anchorIdx <= targetIdx ? [anchorIdx, targetIdx] : [targetIdx, anchorIdx];
1182
+ const range = orderedChunkIds.slice(from, to + 1);
1183
+ setSelectedChunks((prev) => /* @__PURE__ */ new Set([...prev, ...range]));
1184
+ setPendingPassagesForCitation(range.map((id) => ({ chunk_id: id, page: pageOf(id) })));
1185
+ return;
1186
+ }
1187
+ selectionAnchorRef.current = chunkId;
1188
+ const wasSelected = factCitationSetRef.current.size ? factCitationSetRef.current.has(chunkId) : selectedChunksRef.current.has(chunkId);
1189
+ setSelectedChunks((prev) => {
1190
+ const next = new Set(prev);
1191
+ if (wasSelected) next.delete(chunkId);
1192
+ else next.add(chunkId);
1193
+ return next;
1194
+ });
1195
+ if (wasSelected) setUnselectedPassagesForCitation([chunkId]);
1196
+ else setPendingPassagesForCitation([{ chunk_id: chunkId, page: pageOf(chunkId) }]);
1197
+ },
1198
+ [
1199
+ activeCitationContext,
1200
+ documentId,
1201
+ orderedChunkIds,
1202
+ setPendingPassagesForCitation,
1203
+ setUnselectedPassagesForCitation,
1204
+ pageOf
1205
+ ]
1206
+ );
1207
+ return {
1208
+ isCitationMode,
1209
+ selectedChunks,
1210
+ selectionRuns,
1211
+ runStartIds,
1212
+ runCursor,
1213
+ gotoRun,
1214
+ handleSelectionEnd,
1215
+ handleChunkClick,
1216
+ factCitationSet,
1217
+ factCitationActive,
1218
+ viewingPassageId
1219
+ };
1220
+ }
1221
+ function scrollToChunk(chunkId) {
1222
+ requestAnimationFrame(() => {
1223
+ const element = document.getElementById(chunkId);
1224
+ if (element) {
1225
+ element.scrollIntoView({ behavior: "auto", block: "center" });
1226
+ return;
1227
+ }
1228
+ setTimeout(() => {
1229
+ document.getElementById(chunkId)?.scrollIntoView({ behavior: "auto", block: "center" });
1230
+ }, 100);
1231
+ });
1232
+ }
1233
+ function usePageScrollSync({
1234
+ containerRef,
1235
+ processedChunksLength,
1236
+ scrollTrigger,
1237
+ onVisibilityUpdate
1238
+ }) {
1239
+ const session = useArbiSessionStore();
1240
+ const viewingId = useArbiSessionState((s) => s.viewingDocument?.id);
1241
+ const viewingDocumentPage = useArbiSessionState((s) => s.viewingDocument?.page ?? null);
1242
+ const viewingPassageId = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null);
1243
+ const activeTab = useArbiSessionState((s) => s.documentViewer.tab);
1244
+ const setViewingDocumentPage = useCallback(
1245
+ (page) => {
1246
+ if (viewingId) session.setViewingDocument({ id: viewingId, page });
1247
+ },
1248
+ [session, viewingId]
1249
+ );
1250
+ const [highlighted, setHighlighted] = useState(null);
1251
+ const isChunkHighlighted = useCallback(
1252
+ (chunkId) => chunkId === highlighted,
1253
+ [highlighted]
1254
+ );
1255
+ const scrollCompleteRef = useRef(false);
1256
+ const viewingPassageIdRef = useRef(viewingPassageId);
1257
+ viewingPassageIdRef.current = viewingPassageId;
1258
+ useEffect(() => {
1259
+ if (activeTab !== "html") {
1260
+ scrollCompleteRef.current = false;
1261
+ }
1262
+ }, [activeTab]);
1263
+ useEffect(() => {
1264
+ if (activeTab !== "html" || processedChunksLength === 0) return;
1265
+ if (scrollCompleteRef.current) return;
1266
+ if (viewingPassageIdRef.current) {
1267
+ scrollCompleteRef.current = true;
1268
+ return;
1269
+ }
1270
+ requestAnimationFrame(() => {
1271
+ if (viewingDocumentPage) {
1272
+ const pageElement = document.getElementById(`page-${viewingDocumentPage}`);
1273
+ if (pageElement) {
1274
+ pageElement.scrollIntoView({ behavior: "auto", block: "start" });
1275
+ setTimeout(() => {
1276
+ scrollCompleteRef.current = true;
1277
+ }, 100);
1278
+ }
1279
+ } else {
1280
+ scrollCompleteRef.current = true;
1281
+ }
1282
+ });
1283
+ }, [activeTab, processedChunksLength]);
1284
+ const lastScrolledPassageRef = useRef(null);
1285
+ useEffect(() => {
1286
+ if (!viewingPassageId) {
1287
+ lastScrolledPassageRef.current = null;
1288
+ setHighlighted(null);
1289
+ }
1290
+ }, [viewingPassageId]);
1291
+ useEffect(() => {
1292
+ if (!viewingPassageId || activeTab !== "html" || processedChunksLength === 0) return;
1293
+ if (lastScrolledPassageRef.current === viewingPassageId) return;
1294
+ lastScrolledPassageRef.current = viewingPassageId;
1295
+ setHighlighted(viewingPassageId);
1296
+ scrollToChunk(viewingPassageId);
1297
+ }, [viewingPassageId, activeTab, processedChunksLength]);
1298
+ const viewingPageRef = useRef(viewingDocumentPage);
1299
+ viewingPageRef.current = viewingDocumentPage;
1300
+ useEffect(() => {
1301
+ const viewingDocumentPage2 = viewingPageRef.current;
1302
+ if (!scrollTrigger || processedChunksLength === 0 || !viewingDocumentPage2) return;
1303
+ scrollCompleteRef.current = false;
1304
+ requestAnimationFrame(() => {
1305
+ const pageElement = document.getElementById(`page-${viewingDocumentPage2}`);
1306
+ if (pageElement) {
1307
+ pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
1308
+ }
1309
+ setTimeout(() => {
1310
+ scrollCompleteRef.current = true;
1311
+ }, 500);
1312
+ });
1313
+ }, [scrollTrigger, processedChunksLength]);
1314
+ const getPageElements = useCallback(
1315
+ () => Array.from(document.querySelectorAll('[id^="page-"]')),
1316
+ []
1317
+ );
1318
+ const getPageNumber = useCallback((element) => {
1319
+ const pageMatch = element.id.match(/page-(\d+)/);
1320
+ return pageMatch ? parseInt(pageMatch[1], 10) : 0;
1321
+ }, []);
1322
+ usePageIntersectionObserver({
1323
+ containerRef,
1324
+ scrollCompleteRef,
1325
+ isEnabled: activeTab === "html" && processedChunksLength > 0,
1326
+ getPageElements,
1327
+ getPageNumber,
1328
+ onPageChange: setViewingDocumentPage,
1329
+ onVisibilityUpdate,
1330
+ observeKey: processedChunksLength
1331
+ });
1332
+ return {
1333
+ isChunkHighlighted
1334
+ };
1335
+ }
1336
+
1337
+ // src/connection/viewer/parsed/useLazyPages.ts
1338
+ var LAZY_LOAD_BUFFER_BEFORE = 2;
1339
+ var LAZY_LOAD_BUFFER_AFTER = 5;
1340
+ var INITIAL_PAGES_TO_RENDER = 3;
1341
+ var PAGE_ASPECT_RATIO = 1.3;
1342
+ function useLazyPages({ containerRef, processedChunks, scrollTrigger }) {
1343
+ const [containerWidth, setContainerWidth] = useState(0);
1344
+ useEffect(() => {
1345
+ const el = containerRef.current;
1346
+ if (!el) return;
1347
+ const observer = new ResizeObserver((entries) => {
1348
+ setContainerWidth(entries[0]?.contentRect.width ?? 0);
1349
+ });
1350
+ observer.observe(el);
1351
+ return () => observer.disconnect();
1352
+ }, [containerRef]);
1353
+ const [renderedPages, setRenderedPages] = useState(
1354
+ () => new Set(Array.from({ length: INITIAL_PAGES_TO_RENDER }, (_, i) => i))
1355
+ );
1356
+ useEffect(() => {
1357
+ if (processedChunks.length === 0) return;
1358
+ const renderAll = () => {
1359
+ setRenderedPages((prev) => {
1360
+ if (prev.size === processedChunks.length) return prev;
1361
+ return new Set(Array.from({ length: processedChunks.length }, (_, i) => i));
1362
+ });
1363
+ };
1364
+ if (typeof window.requestIdleCallback !== "function") {
1365
+ const timer = setTimeout(renderAll, 200);
1366
+ return () => clearTimeout(timer);
1367
+ }
1368
+ const id = window.requestIdleCallback(renderAll);
1369
+ return () => window.cancelIdleCallback(id);
1370
+ }, [processedChunks.length]);
1371
+ const handleVisibilityUpdate = useCallback(
1372
+ (visibilityMap) => {
1373
+ const visiblePageNumbers = Array.from(visibilityMap.entries()).filter(([, ratio]) => ratio > 0).map(([pageNum]) => pageNum);
1374
+ if (visiblePageNumbers.length === 0) return;
1375
+ const visibleIndices = [];
1376
+ processedChunks.forEach((page, index) => {
1377
+ if (page.pageNumber !== null && visiblePageNumbers.includes(page.pageNumber)) {
1378
+ visibleIndices.push(index);
1379
+ }
1380
+ });
1381
+ if (visibleIndices.length === 0) return;
1382
+ const minIndex = Math.min(...visibleIndices);
1383
+ const maxIndex = Math.max(...visibleIndices);
1384
+ const pagesToRender = /* @__PURE__ */ new Set();
1385
+ for (let i = Math.max(0, minIndex - LAZY_LOAD_BUFFER_BEFORE); i <= Math.min(processedChunks.length - 1, maxIndex + LAZY_LOAD_BUFFER_AFTER); i++) {
1386
+ pagesToRender.add(i);
1387
+ }
1388
+ setRenderedPages((prev) => {
1389
+ for (const i of pagesToRender) if (!prev.has(i)) return /* @__PURE__ */ new Set([...prev, ...pagesToRender]);
1390
+ return prev;
1391
+ });
1392
+ },
1393
+ [processedChunks]
1394
+ );
1395
+ const viewingDocumentPage = useArbiSessionState((s) => s.viewingDocument?.page ?? null);
1396
+ const viewingPassageId = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null);
1397
+ const activeTab = useArbiSessionState((s) => s.documentViewer.tab);
1398
+ useEffect(() => {
1399
+ if (!viewingDocumentPage || processedChunks.length === 0) return;
1400
+ if (!viewingPassageId && activeTab !== "html") return;
1401
+ const targetIndex = processedChunks.findIndex((p) => p.pageNumber === viewingDocumentPage);
1402
+ if (targetIndex === -1) return;
1403
+ setRenderedPages((prev) => {
1404
+ if (prev.has(targetIndex)) return prev;
1405
+ const next = new Set(prev);
1406
+ for (let i = Math.max(0, targetIndex - LAZY_LOAD_BUFFER_BEFORE); i <= Math.min(processedChunks.length - 1, targetIndex + LAZY_LOAD_BUFFER_AFTER); i++) {
1407
+ next.add(i);
1408
+ }
1409
+ return next;
1410
+ });
1411
+ }, [viewingPassageId, viewingDocumentPage, processedChunks, activeTab]);
1412
+ const tabSwitchScrolledRef = useRef(false);
1413
+ const passageScrolledRef = useRef(null);
1414
+ useEffect(() => {
1415
+ if (activeTab !== "html") tabSwitchScrolledRef.current = false;
1416
+ }, [activeTab]);
1417
+ useEffect(() => {
1418
+ if (!viewingPassageId) passageScrolledRef.current = null;
1419
+ }, [viewingPassageId]);
1420
+ useEffect(() => {
1421
+ if (activeTab !== "html" || !viewingDocumentPage) return;
1422
+ if (viewingPassageId && passageScrolledRef.current !== viewingPassageId) {
1423
+ const target = viewingPassageId;
1424
+ const deadline = performance.now() + 3e3;
1425
+ let raf = 0;
1426
+ const tick = () => {
1427
+ const el = document.getElementById(target);
1428
+ if (el) {
1429
+ passageScrolledRef.current = target;
1430
+ tabSwitchScrolledRef.current = true;
1431
+ el.scrollIntoView({ behavior: "auto", block: "center" });
1432
+ raf = requestAnimationFrame(
1433
+ () => el.scrollIntoView({ behavior: "auto", block: "center" })
1434
+ );
1435
+ return;
1436
+ }
1437
+ if (performance.now() < deadline) raf = requestAnimationFrame(tick);
1438
+ };
1439
+ raf = requestAnimationFrame(tick);
1440
+ return () => cancelAnimationFrame(raf);
1441
+ }
1442
+ if (tabSwitchScrolledRef.current) return;
1443
+ const pageElement = document.getElementById(`page-${viewingDocumentPage}`);
1444
+ if (!pageElement) return;
1445
+ tabSwitchScrolledRef.current = true;
1446
+ requestAnimationFrame(() => {
1447
+ pageElement.scrollIntoView({ behavior: "auto", block: "start" });
1448
+ });
1449
+ }, [renderedPages, activeTab, viewingDocumentPage, viewingPassageId]);
1450
+ const { isChunkHighlighted } = usePageScrollSync({
1451
+ containerRef,
1452
+ processedChunksLength: processedChunks.length,
1453
+ scrollTrigger,
1454
+ onVisibilityUpdate: handleVisibilityUpdate
1455
+ });
1456
+ return {
1457
+ renderedPages,
1458
+ isChunkHighlighted,
1459
+ placeholderHeight: containerWidth ? containerWidth * PAGE_ASPECT_RATIO : 500
1460
+ };
1461
+ }
1462
+ var EMPTY_LABELS = [];
1463
+ function ParsedTextView({
1464
+ documentId,
1465
+ stage = "final",
1466
+ onLoadSuccess,
1467
+ scrollTrigger,
1468
+ zoom = 1,
1469
+ onZoomChange
1470
+ }) {
1471
+ const { workspaceId } = useConnectedWorkspace();
1472
+ const { openInNavigator } = useDocumentViewerSupport();
1473
+ const containerRef = useRef(null);
1474
+ const { data: documentRecord } = useDocument(parseVersionRef(documentId).docId, {
1475
+ enabled: !!documentId && !!workspaceId
1476
+ });
1477
+ const documentData = documentRecord ?? void 0;
1478
+ const { data: parsedDoc, isLoading, error } = useParsedDocument(documentId, stage);
1479
+ const { processedChunks, maxPageNumber } = useProcessedChunks(
1480
+ parsedDoc?.chunks,
1481
+ parsedDoc?.footnotes || {}
1482
+ );
1483
+ const pageByChunk = useMemo(() => {
1484
+ const map = /* @__PURE__ */ new Map();
1485
+ for (const page of processedChunks) {
1486
+ for (const chunk of page.chunks) {
1487
+ if (chunk.chunkExtId) map.set(chunk.chunkExtId, page.pageNumber ?? void 0);
1488
+ }
1489
+ }
1490
+ return map;
1491
+ }, [processedChunks]);
1492
+ const pageOf = useCallback((id) => pageByChunk.get(id), [pageByChunk]);
1493
+ const orderedChunkIds = useMemo(
1494
+ () => processedChunks.flatMap(
1495
+ (page) => page.chunks.map((c) => c.chunkExtId).filter((id) => !!id)
1496
+ ),
1497
+ [processedChunks]
1498
+ );
1499
+ const totalPages = useMemo(
1500
+ () => processedChunks.filter((p) => p.pageNumber !== null).length,
1501
+ [processedChunks]
1502
+ );
1503
+ const labels = useDocumentLabels(documentId, documentData?.doctags, orderedChunkIds);
1504
+ const citation = useCitationSelection({
1505
+ documentId,
1506
+ containerRef,
1507
+ processedChunks,
1508
+ orderedChunkIds,
1509
+ pageOf
1510
+ });
1511
+ const { renderedPages, isChunkHighlighted, placeholderHeight } = useLazyPages({
1512
+ containerRef,
1513
+ processedChunks,
1514
+ scrollTrigger
1515
+ });
1516
+ useScrollAnchor(containerRef, processedChunks.length);
1517
+ usePinchZoom({ containerRef, zoom, onZoomChange });
1518
+ const { formatChunkWithCitation, getPassageDeepLink, copyToClipboard } = usePassageCopy({
1519
+ documentId,
1520
+ documentData,
1521
+ selectedWorkspaceId: workspaceId
1522
+ });
1523
+ const handleOpenNavigator = useMemo(
1524
+ () => openInNavigator ? () => openInNavigator(documentId) : void 0,
1525
+ [openInNavigator, documentId]
1526
+ );
1527
+ useEffect(() => {
1528
+ if (maxPageNumber > 0 && onLoadSuccess) {
1529
+ try {
1530
+ onLoadSuccess(maxPageNumber);
1531
+ } catch (err) {
1532
+ console.error("Error in onLoadSuccess callback:", err);
1533
+ }
1534
+ }
1535
+ }, [maxPageNumber, onLoadSuccess]);
1536
+ if (isLoading) return /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading parsed document..." });
1537
+ if (error) {
1538
+ return /* @__PURE__ */ jsx(ViewerMessage, { children: /* @__PURE__ */ jsx("span", { className: "text-red-text", children: "Failed to load parsed document" }) });
1539
+ }
1540
+ const taggingChunk = labels.taggingChunkId ? processedChunks.flatMap((page) => page.chunks).find((c) => c.chunkExtId === labels.taggingChunkId) : void 0;
1541
+ return /* @__PURE__ */ jsxs(HtmlViewerRoot, { children: [
1542
+ /* @__PURE__ */ jsx(
1543
+ DocumentLabelBar,
1544
+ {
1545
+ summaries: labels.labelSummaries,
1546
+ activeTagExtId: labels.activeTagExtId,
1547
+ cursor: labels.tagCursor,
1548
+ onSelect: labels.selectTag,
1549
+ onStep: labels.gotoTagged
1550
+ }
1551
+ ),
1552
+ labels.taggingChunkId && /* @__PURE__ */ jsx(
1553
+ PassageTagPanel,
1554
+ {
1555
+ documentId,
1556
+ chunkExtId: labels.taggingChunkId,
1557
+ chunkContent: taggingChunk?.content ?? "",
1558
+ pageNumber: pageOf(labels.taggingChunkId),
1559
+ documentDoctags: labels.documentDoctags,
1560
+ onClose: () => labels.setTaggingChunkId(null),
1561
+ onViewTaggedChunks: (tagExtId) => {
1562
+ labels.selectTag(tagExtId);
1563
+ labels.setTaggingChunkId(null);
1564
+ }
1565
+ }
1566
+ ),
1567
+ !citation.factCitationActive && citation.runStartIds.length > 0 && /* @__PURE__ */ jsx(
1568
+ CitedRunNav,
1569
+ {
1570
+ position: citation.runCursor + 1,
1571
+ total: citation.runStartIds.length,
1572
+ onStep: citation.gotoRun
1573
+ }
1574
+ ),
1575
+ /* @__PURE__ */ jsx(HtmlViewerSurface, { surfaceRef: containerRef, onMouseUp: citation.handleSelectionEnd, children: processedChunks.length > 0 ? processedChunks.map((page, pageIndex) => /* @__PURE__ */ jsx(
1576
+ HtmlPage,
1577
+ {
1578
+ pageNumber: page.pageNumber,
1579
+ totalPages,
1580
+ isRendered: renderedPages.has(pageIndex),
1581
+ placeholderHeight,
1582
+ zoom,
1583
+ children: page.chunks.map((chunk, chunkIndex) => {
1584
+ const id = chunk.chunkExtId;
1585
+ const run = id ? citation.selectionRuns.get(id) : void 0;
1586
+ return /* @__PURE__ */ jsx(
1587
+ ParsedPassage,
1588
+ {
1589
+ chunk,
1590
+ pageNumber: page.pageNumber,
1591
+ isHighlighted: !!(id && isChunkHighlighted(id)),
1592
+ isSelected: !!(id && citation.selectedChunks.has(id)),
1593
+ isCitationHighlight: !!(id && citation.factCitationSet.has(id)),
1594
+ isActiveCitation: !!(id && citation.factCitationActive && citation.viewingPassageId === id && // Only while it is STILL cited: clicking it off must clear it.
1595
+ citation.factCitationSet.has(id)),
1596
+ factCitationActive: citation.factCitationActive,
1597
+ isCitationMode: citation.isCitationMode,
1598
+ runIsStart: !!run?.isStart,
1599
+ runIsEnd: !!run?.isEnd,
1600
+ runEndIndex: run?.endIndex,
1601
+ onChunkClick: citation.isCitationMode ? citation.handleChunkClick : void 0,
1602
+ formatChunkWithCitation,
1603
+ getPassageDeepLink,
1604
+ copyToClipboard,
1605
+ onOpenNavigator: handleOpenNavigator,
1606
+ labels: id ? labels.labelsByChunk.get(id) ?? EMPTY_LABELS : EMPTY_LABELS,
1607
+ activeTagColor: id && labels.activeChunkIds.has(id) ? labels.activeTagColor : void 0,
1608
+ onTagPassage: labels.setTaggingChunkId,
1609
+ onShowLabel: labels.selectTag,
1610
+ onRemoveLabel: labels.removeLabel
1611
+ },
1612
+ chunkIndex
1613
+ );
1614
+ })
1615
+ },
1616
+ pageIndex
1617
+ )) : /* @__PURE__ */ jsx(HtmlViewerEmpty, {}) })
1618
+ ] });
1619
+ }
1620
+ var AnnotatedPdfViewer = lazy(
1621
+ () => import('../document-tools/viewer/index.js').then((m) => ({ default: m.AnnotatedPdfViewer }))
1622
+ );
1623
+ var SignaturePlacementViewer = lazy(
1624
+ () => import('../document-tools/viewer/index.js').then((m) => ({ default: m.SignaturePlacementViewer }))
1625
+ );
1626
+ var SignatureRequestEditor = lazy(
1627
+ () => import('../document-tools/viewer/index.js').then((m) => ({ default: m.SignatureRequestEditor }))
1628
+ );
1629
+ var GuidedSigningViewer = lazy(
1630
+ () => import('../document-tools/viewer/index.js').then((m) => ({ default: m.GuidedSigningViewer }))
1631
+ );
1632
+ function SessionPdfViewer(props) {
1633
+ const session = useArbiSessionStore();
1634
+ const viewingId = useArbiSessionState((s) => s.viewingDocument?.id);
1635
+ const { isDetached } = useDocumentViewerSupport();
1636
+ const onPageChange = useCallback(
1637
+ (page) => {
1638
+ if (viewingId) session.setViewingDocument({ id: viewingId, page });
1639
+ },
1640
+ [session, viewingId]
1641
+ );
1642
+ return /* @__PURE__ */ jsx(PdfViewer, { ...props, onPageChange, disableFontFace: !!isDetached });
1643
+ }
1644
+ function ViewerPdfPane({
1645
+ documentId,
1646
+ doc,
1647
+ pdfBlob,
1648
+ isPdfLoading,
1649
+ pdfError,
1650
+ onDownload,
1651
+ viewerProps,
1652
+ signatureFlow,
1653
+ onSignatureFlow,
1654
+ currentUserId,
1655
+ placingSignature,
1656
+ onPlacingDone,
1657
+ annotating,
1658
+ markup,
1659
+ pdfSnapshotNumber,
1660
+ isSigned
1661
+ }) {
1662
+ const { documentData, isDownloadOnly, isVideo, isAudio, isImage, isDocx } = doc;
1663
+ const showMarkup = markup.hasMarkup && !markup.showOriginal;
1664
+ if (isDownloadOnly) {
1665
+ return /* @__PURE__ */ jsx(
1666
+ ViewerPreviewUnavailable,
1667
+ {
1668
+ extension: fileExtension(documentData?.file_name),
1669
+ onDownload
1670
+ }
1671
+ );
1672
+ }
1673
+ const loadingLabel = isVideo ? "Loading video..." : isAudio ? "Loading audio..." : isImage ? "Loading image..." : !documentData ? "Loading document..." : friendlyFileType(documentData.file_type, documentData.file_name) === "Text" ? "Loading text..." : "Loading PDF...";
1674
+ const errorLabel = isVideo ? "Failed to load video" : isAudio ? "Failed to load audio" : isImage ? "Failed to load image" : "Failed to load PDF";
1675
+ if (isDocx && documentData && !["completed", "low-content", "failed"].includes(documentData.status || "")) {
1676
+ return /* @__PURE__ */ jsx(ViewerMessage, { children: "PDF and search indexing are processing. Open the DOCX tab to edit now." });
1677
+ }
1678
+ if (isPdfLoading) return /* @__PURE__ */ jsx(ViewerMessage, { children: loadingLabel });
1679
+ if (pdfError) {
1680
+ return /* @__PURE__ */ jsx(
1681
+ ViewerLoadError,
1682
+ {
1683
+ message: isVideo || isAudio || isImage ? `${errorLabel} \u2014 download it instead.` : "Couldn't display the PDF \u2014 download it instead.",
1684
+ onDownload
1685
+ }
1686
+ );
1687
+ }
1688
+ if (!pdfBlob) return /* @__PURE__ */ jsx(ViewerMessage, { children: loadingLabel });
1689
+ if (isVideo) return /* @__PURE__ */ jsx(VideoViewer, { blob: pdfBlob, title: documentData?.file_name || "Video" });
1690
+ if (isAudio) return /* @__PURE__ */ jsx(AudioViewer, { blob: pdfBlob, title: documentData?.file_name || "Audio" });
1691
+ if (isImage) {
1692
+ return /* @__PURE__ */ jsx(ImageViewer, { blob: pdfBlob, alt: documentData?.file_name || "Document image" });
1693
+ }
1694
+ if (signatureFlow?.kind === "prepare") {
1695
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading\u2026" }), children: /* @__PURE__ */ jsx(
1696
+ SignatureRequestEditor,
1697
+ {
1698
+ ...viewerProps,
1699
+ file: pdfBlob,
1700
+ documentId,
1701
+ version: documentData?.current_version ?? void 0,
1702
+ draft: signatureFlow.draft,
1703
+ viewer: SessionPdfViewer,
1704
+ onCancel: () => onSignatureFlow(null),
1705
+ onSaved: () => onSignatureFlow(null)
1706
+ }
1707
+ ) });
1708
+ }
1709
+ if (signatureFlow?.kind === "sign" && currentUserId) {
1710
+ const { currentPage: _page, scrollTrigger: _trigger, ...guidedProps } = viewerProps;
1711
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading\u2026" }), children: /* @__PURE__ */ jsx(
1712
+ GuidedSigningViewer,
1713
+ {
1714
+ ...guidedProps,
1715
+ file: pdfBlob,
1716
+ request: signatureFlow.request,
1717
+ signer: currentUserId,
1718
+ viewer: SessionPdfViewer,
1719
+ onClose: () => onSignatureFlow(null),
1720
+ onSigned: () => onSignatureFlow(null)
1721
+ }
1722
+ ) });
1723
+ }
1724
+ if (placingSignature) {
1725
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading\u2026" }), children: /* @__PURE__ */ jsx(
1726
+ SignaturePlacementViewer,
1727
+ {
1728
+ ...viewerProps,
1729
+ file: pdfBlob,
1730
+ documentId,
1731
+ viewer: SessionPdfViewer,
1732
+ onCancel: () => onPlacingDone(),
1733
+ onContinue: (appearance) => onPlacingDone(appearance)
1734
+ }
1735
+ ) });
1736
+ }
1737
+ if (annotating || showMarkup) {
1738
+ return /* @__PURE__ */ jsx(
1739
+ Suspense,
1740
+ {
1741
+ fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: annotating ? "Loading annotation tools\u2026" : "Loading markup\u2026" }),
1742
+ children: /* @__PURE__ */ jsx(
1743
+ AnnotatedPdfViewer,
1744
+ {
1745
+ ...viewerProps,
1746
+ file: pdfBlob,
1747
+ documentId,
1748
+ version: pdfSnapshotNumber,
1749
+ editing: annotating,
1750
+ onMarkupChange: markup.onMarkupChange,
1751
+ fileName: documentData?.file_name,
1752
+ shared: documentData?.shared ?? false,
1753
+ folder: documentData?.folder,
1754
+ viewer: SessionPdfViewer,
1755
+ signed: isSigned
1756
+ },
1757
+ `${documentId}@${pdfSnapshotNumber ?? "current"}`
1758
+ )
1759
+ }
1760
+ );
1761
+ }
1762
+ return /* @__PURE__ */ jsx(SessionPdfViewer, { ...viewerProps, file: pdfBlob });
1763
+ }
1764
+ var NativeDocxEditor = lazy(
1765
+ () => import('../ConnectedNativeDocxEditor-LRYU5HPA.js').then((m) => ({
1766
+ default: m.ConnectedNativeDocxEditor
1767
+ }))
1768
+ );
1769
+ var StreamedWordArtifact = lazy(
1770
+ () => import('../ConnectedStreamedWordArtifact-QAUVUCSX.js').then((m) => ({
1771
+ default: m.ConnectedStreamedWordArtifact
1772
+ }))
1773
+ );
1774
+ var NativeDocxComparison = lazy(
1775
+ () => import('../ConnectedNativeDocxComparison-OFPIXNJB.js').then((m) => ({
1776
+ default: m.ConnectedNativeDocxComparison
1777
+ }))
1778
+ );
1779
+ var UPLOADED_NO_VERSIONS = "No earlier versions yet. Replacing, editing or signing this file adds a new version here.";
1780
+ function canChangeVisibility(doc, userId) {
1781
+ if (!doc || !userId) return false;
1782
+ return userId.startsWith("agt-") || (doc.created_by_ext_id?.startsWith("agt-") ?? false) || doc.created_by_ext_id === userId;
1783
+ }
1784
+ function ConnectedDocumentViewer(props) {
1785
+ const viewing = useArbiSessionState((s) => s.viewingDocument?.id);
1786
+ const openedId = props.documentId ?? viewing;
1787
+ if (!openedId) return null;
1788
+ return /* @__PURE__ */ jsx(ConnectedDocumentToolsProvider, { children: /* @__PURE__ */ jsx(DocumentViewerContent, { ...props, openedId }) });
1789
+ }
1790
+ function DocumentViewerContent({
1791
+ openedId,
1792
+ headerActions,
1793
+ artifactRuntimeUrl = "/artifact-runtime/"
1794
+ }) {
1795
+ const arbi = useArbi();
1796
+ const session = useArbiSessionStore();
1797
+ const support = useDocumentViewerSupport();
1798
+ const formatDate = support.formatDate ?? fmtDate;
1799
+ const tools = useDocumentTools();
1800
+ const { openConversation, notify } = useBlocksEnvironment();
1801
+ const { userId: currentUserId } = useConnectedWorkspace();
1802
+ const documentId = parseVersionRef(openedId).docId;
1803
+ const [totalPages, setTotalPages] = useState(0);
1804
+ const [isCompact, setIsCompact] = useState(false);
1805
+ const [pdfZoom, setPdfZoom] = useState(1);
1806
+ const {
1807
+ tab: zoomTab,
1808
+ textScale,
1809
+ compareId: compareDocumentId
1810
+ } = useArbiSessionState((s) => s.documentViewer);
1811
+ const zoom = zoomTab === "html" ? textScale : pdfZoom;
1812
+ const setZoom = useCallback(
1813
+ (next) => {
1814
+ const value = typeof next === "function" ? next(zoom) : next;
1815
+ if (zoomTab === "html") session.setDocumentViewer({ textScale: value });
1816
+ else setPdfZoom(value);
1817
+ },
1818
+ [zoomTab, session, zoom]
1819
+ );
1820
+ const [scrollTrigger, setScrollTrigger] = useState(0);
1821
+ const containerRef = useRef(null);
1822
+ const viewingDocumentPage = useArbiSessionState((s) => s.viewingDocument?.page ?? null);
1823
+ const setViewingDocumentPage = (page) => session.setViewingDocument({ id: openedId, page });
1824
+ const setViewingDocumentId = (id) => session.setViewingDocument({ id });
1825
+ const setActiveTab = (tab) => session.setDocumentViewer({ tab });
1826
+ const setCompareDocumentId = (id) => session.setDocumentViewer({ compareId: id });
1827
+ const { data: conversations } = useConnectedConversations();
1828
+ const snapshotRef = parseVersionRef(openedId).version ? openedId : null;
1829
+ const { versions, translations } = useViewerVersions(documentId);
1830
+ const currentVersionId = versions.find((v) => v.isCurrent)?.id ?? documentId;
1831
+ const snapshotDocumentId = snapshotRef && snapshotRef !== currentVersionId ? snapshotRef : null;
1832
+ const doc = useViewedDocument(documentId);
1833
+ const setSnapshotDocumentId = (ref) => setViewingDocumentId(ref ?? documentId);
1834
+ useRegisterOpenDocument({
1835
+ documentId: doc.savedDocumentId,
1836
+ shownId: openedId,
1837
+ showLive: () => setViewingDocumentId(documentId),
1838
+ workspaceId: doc.workspaceId
1839
+ });
1840
+ const {
1841
+ documentData,
1842
+ streamingDoc,
1843
+ isStreaming,
1844
+ draftDoc,
1845
+ isDraft,
1846
+ isCaptureDraft,
1847
+ labelSummaries,
1848
+ isImage,
1849
+ isVideo,
1850
+ isAudio,
1851
+ isMedia,
1852
+ isArtifact,
1853
+ liveKind,
1854
+ liveSource,
1855
+ isDocx,
1856
+ isXlsx,
1857
+ isDownloadOnly
1858
+ } = doc;
1859
+ const threadTitle = (id) => conversations.find((c) => c.external_id === id)?.title?.trim() || "Its thread";
1860
+ const madeInId = documentData?.conversation_ext_id ?? null;
1861
+ const madeIn = madeInId ? { id: madeInId, title: threadTitle(madeInId) } : null;
1862
+ const pdfSnapshotId = snapshotDocumentId && !isDocx && !isArtifact ? snapshotDocumentId : null;
1863
+ const shownDocumentId = pdfSnapshotId || documentId;
1864
+ const blobs = useViewerBlobs(shownDocumentId, doc);
1865
+ const { pdfBlob, xlsxBlob, xlsxError, handleDirectDownload } = blobs;
1866
+ const [annotating, setAnnotating] = useState(false);
1867
+ useEffect(() => setAnnotating(false), [documentId]);
1868
+ const hasHistory = versions.length > 1 || (documentData?.current_version ?? 1) > 1 || translations.length > 0;
1869
+ const { activeTab, handleTabChange, viewerTabs } = useViewerTabs(doc, isCompact, hasHistory);
1870
+ const crop = useImageCrop(documentId, documentData?.file_name, pdfBlob);
1871
+ const [placingSignature, setPlacingSignature] = useState(false);
1872
+ const [signAppearance, setSignAppearance] = useState();
1873
+ const [isSignOpen, setIsSignOpen] = useState(false);
1874
+ useEffect(() => setPlacingSignature(false), [documentId, snapshotDocumentId]);
1875
+ const [signatureFlow, setSignatureFlow] = useState(null);
1876
+ useEffect(() => setSignatureFlow(null), [documentId, snapshotDocumentId]);
1877
+ const { data: signatureStatus } = useDocumentSignatures(shownDocumentId, !isDraft && !liveKind);
1878
+ const isCoEditing = !snapshotDocumentId && !compareDocumentId && !isDraft && (activeTab === "docx" && isDocx || activeTab === "edit" && isArtifact && !liveKind && !isStreaming);
1879
+ const currentVersionLabel = isCoEditing ? void 0 : !snapshotDocumentId && !compareDocumentId && (isDocx || isArtifact && !liveKind) ? "Live" : versionLabel(versions, snapshotDocumentId || documentId);
1880
+ const compareVersionLabel = versionLabel(versions, compareDocumentId);
1881
+ const snapshotNumber = findVersion(versions, snapshotDocumentId)?.number;
1882
+ const pdfSnapshotNumber = pdfSnapshotId ? snapshotNumber : void 0;
1883
+ const isSigned = !!signatureStatus?.signed;
1884
+ const markup = useDocumentMarkup(documentData, pdfSnapshotNumber, isSigned);
1885
+ useEffect(() => {
1886
+ const container = containerRef.current;
1887
+ if (!container) return;
1888
+ const resizeObserver = new ResizeObserver((entries) => {
1889
+ for (const entry of entries) setIsCompact(entry.contentRect.width < 640);
1890
+ });
1891
+ resizeObserver.observe(container);
1892
+ return () => resizeObserver.disconnect();
1893
+ }, []);
1894
+ const handleLoadSuccess = useCallback((numPages) => setTotalPages(numPages), []);
1895
+ const goToPage = (page) => {
1896
+ setViewingDocumentPage(page);
1897
+ setScrollTrigger((prev) => prev + 1);
1898
+ };
1899
+ const stepPage = (delta) => {
1900
+ const next = (viewingDocumentPage || 1) + delta;
1901
+ if (next >= 1 && next <= totalPages) goToPage(next);
1902
+ };
1903
+ const documentTitle = streamingDoc?.title || draftDoc?.title || documentData?.doc_metadata?.title || documentData?.file_name || "Document";
1904
+ const pageNav = totalPages > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1905
+ /* @__PURE__ */ jsx(ViewerZoomControl, { zoom, onCycle: () => setZoom(cycleZoom(zoom)) }),
1906
+ /* @__PURE__ */ jsx(
1907
+ PdfPageNav,
1908
+ {
1909
+ canPrev: (viewingDocumentPage || 1) > 1,
1910
+ canNext: (viewingDocumentPage || 1) < totalPages,
1911
+ onPrev: () => stepPage(-1),
1912
+ onNext: () => stepPage(1),
1913
+ counter: /* @__PURE__ */ jsx(ViewerPageCounter, { page: viewingDocumentPage || 1, total: totalPages, onGoTo: goToPage })
1914
+ }
1915
+ )
1916
+ ] });
1917
+ const isComparing = !!compareDocumentId;
1918
+ const compareTarget = compareDocumentId ? parseVersionRef(compareDocumentId).docId : null;
1919
+ const compareIndicator = isComparing && compareTarget && /* @__PURE__ */ jsx(
1920
+ ArtifactCompareBar,
1921
+ {
1922
+ compareTarget: support.renderDocumentPill?.(compareTarget) ?? compareTarget,
1923
+ versionLabel: compareVersionLabel,
1924
+ mode: "flip",
1925
+ showTrackChanges: false,
1926
+ onToggleTrackChanges: () => {
1927
+ },
1928
+ onFlip: () => {
1929
+ setViewingDocumentId(compareDocumentId);
1930
+ setCompareDocumentId(documentId);
1931
+ },
1932
+ onStop: () => setCompareDocumentId(null)
1933
+ }
1934
+ );
1935
+ const titleBlock = /* @__PURE__ */ jsxs(Fragment, { children: [
1936
+ isDraft ? support.renderDraftTitle?.(documentId) : /* @__PURE__ */ jsx(
1937
+ ViewerTitle,
1938
+ {
1939
+ title: documentTitle,
1940
+ versionLabel: currentVersionLabel,
1941
+ shrink: !!liveKind || isCompact
1942
+ }
1943
+ ),
1944
+ isCompact && !isDraft && documentData?.shared && /* @__PURE__ */ jsx(ViewerStatusNote, { testId: "document-shared-status", children: "Shared with the workspace" }),
1945
+ isCompact && activeTab === "pdf" && pdfBlob && markup.hasMarkup && !annotating && !placingSignature && /* @__PURE__ */ jsx(
1946
+ MarkupViewNote,
1947
+ {
1948
+ showOriginal: markup.showOriginal,
1949
+ onToggle: () => markup.setShowOriginal((on) => !on)
1950
+ }
1951
+ ),
1952
+ !isComparing && !liveKind && documentData && support.renderRelated?.(documentData),
1953
+ isStreaming && /* @__PURE__ */ jsx(ViewerStatusNote, { pulse: true, children: "streaming..." }),
1954
+ isDraft && /* @__PURE__ */ jsx(ViewerStatusNote, { testId: "draft-unsaved-indicator", children: "Draft \u2014 not saved" }),
1955
+ signatureStatus?.signed && /* @__PURE__ */ jsx(SignatureStatus, { status: signatureStatus, formatDate })
1956
+ ] });
1957
+ const leftContent = /* @__PURE__ */ jsxs(ViewerHeaderStart, { children: [
1958
+ isDraft ? (
1959
+ // A draft's kind replaces the tabs: neither Versions nor the text view means anything
1960
+ // before the first save.
1961
+ support.renderDraftKind?.(documentId)
1962
+ ) : /* @__PURE__ */ jsx(ViewerTabBar, { tabs: viewerTabs, activeId: activeTab, onChange: handleTabChange }),
1963
+ !isCompact && titleBlock
1964
+ ] });
1965
+ const annotatable = canAnnotate({
1966
+ activeTab,
1967
+ hasPdf: !!pdfBlob,
1968
+ isImage,
1969
+ isVideo,
1970
+ isAudio,
1971
+ isDownloadOnly,
1972
+ isDraft,
1973
+ isStreaming,
1974
+ isSnapshot: !!snapshotDocumentId,
1975
+ isComparing
1976
+ });
1977
+ const signatureBanner = !isDraft && !liveKind && !snapshotDocumentId && /* @__PURE__ */ jsx(
1978
+ SignatureRequestBanner,
1979
+ {
1980
+ documentId,
1981
+ hidden: !!signatureFlow,
1982
+ onSign: (request) => {
1983
+ setAnnotating(false);
1984
+ setPlacingSignature(false);
1985
+ if (activeTab !== "pdf") handleTabChange("pdf");
1986
+ setSignatureFlow({ kind: "sign", request });
1987
+ },
1988
+ onEditDraft: (draft) => {
1989
+ if (activeTab !== "pdf") handleTabChange("pdf");
1990
+ setSignatureFlow({ kind: "prepare", draft });
1991
+ }
1992
+ }
1993
+ );
1994
+ const share = () => {
1995
+ const name = (liveKind ? documentTitle : documentData?.file_name) || void 0;
1996
+ if (support.share) {
1997
+ support.share({ id: documentId, name, isPrivate: !documentData?.shared });
1998
+ return;
1999
+ }
2000
+ void arbi.documents.update([{ external_id: documentId, shared: !documentData?.shared }]).then(() => tools.onDocumentsChanged?.([documentId], "markup")).catch(() => notify("Couldn't change who can see this document", "error"));
2001
+ };
2002
+ const shownRef = snapshotDocumentId || documentId;
2003
+ const rightContent = /* @__PURE__ */ jsxs(ViewerHeaderEnd, { isCompact, children: [
2004
+ annotatable && /* @__PURE__ */ jsx(
2005
+ AnnotateButton,
2006
+ {
2007
+ active: annotating,
2008
+ compact: isCompact,
2009
+ onClick: () => {
2010
+ setPlacingSignature(false);
2011
+ markup.setShowOriginal(false);
2012
+ setAnnotating((on) => !on);
2013
+ }
2014
+ }
2015
+ ),
2016
+ activeTab === "pdf" && pdfBlob && !placingSignature && (markup.hasMarkup || annotating) && /* @__PURE__ */ jsx(
2017
+ ShowOriginalButton,
2018
+ {
2019
+ active: markup.showOriginal,
2020
+ compact: isCompact,
2021
+ onClick: () => {
2022
+ setAnnotating(false);
2023
+ markup.setShowOriginal((on) => !on);
2024
+ }
2025
+ }
2026
+ ),
2027
+ activeTab === "pdf" && markup.hasMarkup && !annotating && /* @__PURE__ */ jsx(
2028
+ DownloadMarkupButton,
2029
+ {
2030
+ onClick: () => void markup.downloadMarkup(),
2031
+ disabledReason: isSigned ? SIGNED_LOCKED_REASON : void 0
2032
+ }
2033
+ ),
2034
+ activeTab === "pdf" && isImage && pdfBlob && /* @__PURE__ */ jsx(
2035
+ ViewerImageActions,
2036
+ {
2037
+ compact: isCompact,
2038
+ onUseAsReference: support.useImageAsReference ? () => support.useImageAsReference(documentId) : void 0,
2039
+ onCrop: crop.handleOpenCrop
2040
+ }
2041
+ ),
2042
+ madeIn && /* @__PURE__ */ jsxs(
2043
+ Button,
2044
+ {
2045
+ type: "button",
2046
+ variant: "outline",
2047
+ size: isCompact ? "icon" : "sm",
2048
+ onClick: () => openConversation(madeIn.id, {
2049
+ messageId: documentData?.source_message_ext_id ?? void 0
2050
+ }),
2051
+ title: `Open the thread it was made in: ${madeIn.title}`,
2052
+ "aria-label": `Open the thread it was made in: ${madeIn.title}`,
2053
+ "data-testid": "document-open-thread",
2054
+ children: [
2055
+ /* @__PURE__ */ jsx(MessageSquare, { className: "size-4" }),
2056
+ !isCompact && /* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate", children: madeIn.title })
2057
+ ]
2058
+ }
2059
+ ),
2060
+ documentId && doc.workspaceId && /* @__PURE__ */ jsx(
2061
+ ShareControl,
2062
+ {
2063
+ state: documentData?.shared ? "shared" : "private",
2064
+ onToggle: share,
2065
+ disabled: !canChangeVisibility(documentData, currentUserId),
2066
+ disabledTooltip: "Only the owner can change visibility",
2067
+ tooltip: documentData?.shared ? "Shared with the workspace \u2014 click to share with specific people" : "Share with the workspace, then optionally notify specific people by email",
2068
+ variant: "outline",
2069
+ compact: isCompact,
2070
+ showState: !isCompact,
2071
+ labels: {
2072
+ shared: getEntityLabel("WORKSPACE"),
2073
+ private: "Only you",
2074
+ mixed: "Partly shared"
2075
+ },
2076
+ testId: "share-document-button",
2077
+ stateTestId: "document-title-shared-indicator"
2078
+ }
2079
+ ),
2080
+ tools.emailDocument && !isDraft && !isStreaming && documentData?.file_name && /* @__PURE__ */ jsxs(Fragment, { children: [
2081
+ /* @__PURE__ */ jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": "true" }),
2082
+ /* @__PURE__ */ jsxs(
2083
+ Button,
2084
+ {
2085
+ type: "button",
2086
+ variant: "outline",
2087
+ size: isCompact ? "icon" : "sm",
2088
+ title: "Email this document",
2089
+ "aria-label": "Email",
2090
+ "data-testid": "email-document-button",
2091
+ className: "pointer-coarse:min-h-11",
2092
+ onClick: () => tools.emailDocument?.(shownRef),
2093
+ children: [
2094
+ /* @__PURE__ */ jsx(Mail, { className: "size-4" }),
2095
+ !isCompact && /* @__PURE__ */ jsx("span", { className: "ml-1", children: "Email" })
2096
+ ]
2097
+ }
2098
+ )
2099
+ ] }),
2100
+ support.translate && !isDraft && !isStreaming && !liveKind && !isImage && documentData?.file_name && /* @__PURE__ */ jsxs(
2101
+ Button,
2102
+ {
2103
+ type: "button",
2104
+ variant: "outline",
2105
+ size: isCompact ? "icon" : "sm",
2106
+ title: "Translate into another language: a new editable document, original and translation side by side",
2107
+ "aria-label": "Translate",
2108
+ "data-testid": "translate-document-button",
2109
+ className: "pointer-coarse:min-h-11",
2110
+ onClick: () => support.translate(shownRef),
2111
+ children: [
2112
+ /* @__PURE__ */ jsx(Languages, { className: "size-4" }),
2113
+ !isCompact && /* @__PURE__ */ jsx("span", { className: "ml-1", children: "Translate" })
2114
+ ]
2115
+ }
2116
+ ),
2117
+ !isStreaming && !snapshotDocumentId && /* @__PURE__ */ jsx(FinaliseTranslationButton, { document: documentData ?? void 0, isCompact }),
2118
+ annotatable && /* @__PURE__ */ jsx(
2119
+ SignButton,
2120
+ {
2121
+ active: placingSignature,
2122
+ compact: isCompact,
2123
+ onClick: () => {
2124
+ setAnnotating(false);
2125
+ setSignatureFlow(null);
2126
+ setPlacingSignature((on) => !on);
2127
+ }
2128
+ }
2129
+ ),
2130
+ annotatable && !isSigned && /* @__PURE__ */ jsx(
2131
+ RequestSignaturesButton,
2132
+ {
2133
+ active: signatureFlow?.kind === "prepare",
2134
+ compact: isCompact,
2135
+ onClick: () => {
2136
+ setAnnotating(false);
2137
+ setPlacingSignature(false);
2138
+ setSignatureFlow(signatureFlow?.kind === "prepare" ? null : { kind: "prepare" });
2139
+ }
2140
+ }
2141
+ ),
2142
+ isSignOpen && pdfBlob && /* @__PURE__ */ jsx(
2143
+ SignDocumentDialog,
2144
+ {
2145
+ open: isSignOpen,
2146
+ onOpenChange: setIsSignOpen,
2147
+ documentId,
2148
+ pdfBlob,
2149
+ version: documentData?.current_version ?? void 0,
2150
+ appearance: signAppearance
2151
+ }
2152
+ ),
2153
+ headerActions
2154
+ ] });
2155
+ const viewerProps = {
2156
+ currentPage: viewingDocumentPage || void 0,
2157
+ onLoadSuccess: handleLoadSuccess,
2158
+ scrollTrigger,
2159
+ zoom,
2160
+ onZoomChange: setZoom
2161
+ };
2162
+ return /* @__PURE__ */ jsxs(
2163
+ ViewerFrame,
2164
+ {
2165
+ frameRef: containerRef,
2166
+ contentId: documentId,
2167
+ header: /* @__PURE__ */ jsxs(Fragment, { children: [
2168
+ /* @__PURE__ */ jsx(
2169
+ TabHeader,
2170
+ {
2171
+ tabs: [],
2172
+ activeTabId: activeTab,
2173
+ onTabChange: handleTabChange,
2174
+ leftContent,
2175
+ rightContent,
2176
+ variant: "underline"
2177
+ }
2178
+ ),
2179
+ isCompact && !isCoEditing && /* @__PURE__ */ jsx("div", { "data-slot": "viewer-title-row", className: "flex min-w-0 items-center gap-2 px-3 pb-2", children: titleBlock }),
2180
+ snapshotDocumentId && /* @__PURE__ */ jsx(
2181
+ VersionSnapshotBar,
2182
+ {
2183
+ versionNumber: snapshotNumber,
2184
+ live: isDocx || isArtifact,
2185
+ onAsk: support.askAboutVersion ? () => support.askAboutVersion(snapshotDocumentId) : void 0,
2186
+ onReturn: () => setSnapshotDocumentId(null)
2187
+ }
2188
+ )
2189
+ ] }),
2190
+ compareRow: isComparing ? compareIndicator || void 0 : void 0,
2191
+ footer: (
2192
+ // Crop to a new document. Full resolution (no maxSize): a crop frames, it never downscales.
2193
+ /* @__PURE__ */ jsx(
2194
+ ImageCropModal,
2195
+ {
2196
+ open: crop.cropImageUrl !== null,
2197
+ image: crop.cropImageUrl,
2198
+ title: "Crop image",
2199
+ saveLabel: "Save as a copy",
2200
+ aspectOptions: DEFAULT_ASPECT_OPTIONS,
2201
+ output: { mimeType: "image/png" },
2202
+ onComplete: crop.handleCropComplete,
2203
+ onCancel: crop.closeCrop
2204
+ }
2205
+ )
2206
+ ),
2207
+ children: [
2208
+ isComparing && /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading comparison\u2026" }), children: /* @__PURE__ */ jsx(
2209
+ NativeDocxComparison,
2210
+ {
2211
+ baseId: compareDocumentId,
2212
+ revisedId: documentId,
2213
+ title: documentTitle
2214
+ }
2215
+ ) }),
2216
+ isCaptureDraft && support.renderCaptureDraft?.(documentId),
2217
+ !isCaptureDraft && (activeTab === "pdf" || isMedia && activeTab === "html") && !isArtifact && !isComparing && /* @__PURE__ */ jsxs(ViewerPane, { hidden: activeTab !== "pdf", children: [
2218
+ /* @__PURE__ */ jsx(DocumentLabelBar, { summaries: labelSummaries }),
2219
+ !isMedia && !isImage && signatureBanner,
2220
+ activeTab === "pdf" && !isMedia && !isImage && /* @__PURE__ */ jsx(
2221
+ MarkupNotices,
2222
+ {
2223
+ legacyPrompt: markup.legacyPrompt,
2224
+ olderNote: markup.olderNote,
2225
+ onOpenVersion: (n) => setSnapshotDocumentId(`${documentId}@v${n}`)
2226
+ }
2227
+ ),
2228
+ /* @__PURE__ */ jsx(ViewerControlBar, { controls: activeTab === "pdf" && pageNav, children: /* @__PURE__ */ jsx(
2229
+ ViewerPdfPane,
2230
+ {
2231
+ documentId,
2232
+ doc,
2233
+ pdfBlob,
2234
+ isPdfLoading: blobs.isPdfLoading,
2235
+ pdfError: blobs.pdfError,
2236
+ onDownload: () => void handleDirectDownload(),
2237
+ viewerProps,
2238
+ signatureFlow,
2239
+ onSignatureFlow: setSignatureFlow,
2240
+ currentUserId,
2241
+ placingSignature,
2242
+ onPlacingDone: (appearance) => {
2243
+ setPlacingSignature(false);
2244
+ if (!appearance) return;
2245
+ setSignAppearance(appearance);
2246
+ setIsSignOpen(true);
2247
+ },
2248
+ annotating,
2249
+ markup,
2250
+ pdfSnapshotNumber,
2251
+ isSigned
2252
+ }
2253
+ ) })
2254
+ ] }),
2255
+ activeTab === "preview" && isArtifact && liveKind && // The preview loads its JSX compiler on first use, so it stays out of the main bundle.
2256
+ /* @__PURE__ */ jsx(
2257
+ ArtifactPreview,
2258
+ {
2259
+ kind: liveKind,
2260
+ source: liveSource,
2261
+ isStreaming,
2262
+ runtimeUrl: artifactRuntimeUrl
2263
+ }
2264
+ ),
2265
+ activeTab === "edit" && isArtifact && liveKind && /* @__PURE__ */ jsx(ArtifactCodeView, { source: liveSource, fileName: documentData?.file_name ?? void 0 }),
2266
+ activeTab === "edit" && isArtifact && !liveKind && !isStreaming && !isComparing && /* @__PURE__ */ jsxs(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading editor\u2026" }), children: [
2267
+ isSigned && !snapshotDocumentId && /* @__PURE__ */ jsx(SignedEditNote, {}),
2268
+ /* @__PURE__ */ jsx(
2269
+ NativeDocxEditor,
2270
+ {
2271
+ documentId: snapshotDocumentId || documentId,
2272
+ title: documentTitle,
2273
+ draftContent: isDraft ? draftDoc?.content || "" : void 0,
2274
+ snapshot: !!snapshotDocumentId,
2275
+ onSaved: (id) => {
2276
+ if (!isDraft) return;
2277
+ support.onDraftSaved?.(documentId, id);
2278
+ setViewingDocumentId(id);
2279
+ }
2280
+ },
2281
+ `${snapshotDocumentId || documentId}-${snapshotDocumentId ? "snapshot" : "live"}`
2282
+ )
2283
+ ] }),
2284
+ activeTab === "versions" && (isArtifact || isDocx || hasHistory) && !isComparing && /* @__PURE__ */ jsx(
2285
+ VersionTimeline,
2286
+ {
2287
+ versions: versions.map((v) => ({
2288
+ ...v,
2289
+ madeIn: v.thread ? {
2290
+ label: threadTitle(v.thread.conversationId),
2291
+ onOpen: () => openConversation(v.thread.conversationId, {
2292
+ messageId: v.thread.messageId ?? void 0
2293
+ })
2294
+ } : null
2295
+ })),
2296
+ currentId: currentVersionId,
2297
+ live: !!liveKind,
2298
+ labels: isArtifact ? void 0 : { emptyDocument: UPLOADED_NO_VERSIONS },
2299
+ formatDate,
2300
+ onOpen: (id) => {
2301
+ setSnapshotDocumentId(id === currentVersionId ? null : id);
2302
+ setActiveTab(isArtifact ? "edit" : isDocx ? "docx" : "pdf");
2303
+ },
2304
+ onCompare: (id) => session.setDocumentViewer({ compareId: id, tab: "html" }),
2305
+ translations,
2306
+ onOpenTranslation: (id) => setViewingDocumentId(id)
2307
+ }
2308
+ ),
2309
+ activeTab === "xlsx" && isXlsx && (xlsxBlob ? /* @__PURE__ */ jsx(XlsxViewer, { blob: xlsxBlob }) : /* @__PURE__ */ jsx(ViewerMessage, { children: xlsxError ? "Failed to load spreadsheet" : "Loading spreadsheet..." })),
2310
+ activeTab === "docx" && isDocx && !isComparing && /* @__PURE__ */ jsxs(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Loading editor\u2026" }), children: [
2311
+ signatureBanner,
2312
+ isSigned && !snapshotDocumentId && /* @__PURE__ */ jsx(SignedEditNote, {}),
2313
+ /* @__PURE__ */ jsx(
2314
+ NativeDocxEditor,
2315
+ {
2316
+ documentId: snapshotDocumentId || documentId,
2317
+ title: documentTitle,
2318
+ snapshot: !!snapshotDocumentId
2319
+ },
2320
+ `${snapshotDocumentId || documentId}-${snapshotDocumentId ? "snapshot" : "live"}`
2321
+ )
2322
+ ] }),
2323
+ streamingDoc && isStreaming && isArtifact && !liveKind && !isComparing && (activeTab === "html" || activeTab === "edit") && /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewerMessage, { children: "Opening draft\u2026" }), children: /* @__PURE__ */ jsx(
2324
+ StreamedWordArtifact,
2325
+ {
2326
+ documentId: documentId.startsWith("doc-") ? documentId : void 0,
2327
+ title: documentTitle,
2328
+ content: streamingDoc.content,
2329
+ busy: isStreaming
2330
+ },
2331
+ documentId
2332
+ ) }),
2333
+ !isCaptureDraft && !isComparing && activeTab === "html" && !(isStreaming && isArtifact && !liveKind) && /* @__PURE__ */ jsx(ViewerPane, { children: /* @__PURE__ */ jsx(ViewerControlBar, { controls: pageNav, children: /* @__PURE__ */ jsx(
2334
+ ParsedTextView,
2335
+ {
2336
+ documentId: pdfSnapshotId || documentId,
2337
+ onLoadSuccess: handleLoadSuccess,
2338
+ scrollTrigger,
2339
+ zoom,
2340
+ onZoomChange: setZoom
2341
+ }
2342
+ ) }) })
2343
+ ]
2344
+ }
2345
+ );
2346
+ }
2347
+
2348
+ export { ConnectedDocumentToolsProvider, ConnectedDocumentViewer };
2349
+ //# sourceMappingURL=viewer.js.map
2350
+ //# sourceMappingURL=viewer.js.map