@arbidocs/react 0.5.110 → 0.5.112

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 (1011) hide show
  1. package/dist/PdfViewerImpl-QUSDLNNM.cjs +380 -0
  2. package/dist/PdfViewerImpl-QUSDLNNM.cjs.map +1 -0
  3. package/dist/{PdfViewer.d-bQH9yxFg.d.cts → PdfViewerImpl.d-B28hLEuj.d.ts} +8 -1
  4. package/dist/account/client.js +96 -0
  5. package/dist/account/client.js.map +7 -0
  6. package/dist/account/delete.js +70 -0
  7. package/dist/account/delete.js.map +7 -0
  8. package/dist/account/didit.js +34 -0
  9. package/dist/account/didit.js.map +7 -0
  10. package/dist/account/dismissed-tips.js +33 -0
  11. package/dist/account/dismissed-tips.js.map +7 -0
  12. package/dist/account/email.js +84 -0
  13. package/dist/account/email.js.map +7 -0
  14. package/dist/account/entitlements.js +47 -0
  15. package/dist/account/entitlements.js.map +7 -0
  16. package/dist/account/identity.js +270 -0
  17. package/dist/account/identity.js.map +7 -0
  18. package/dist/account/index.js +93 -0
  19. package/dist/account/index.js.map +7 -0
  20. package/dist/account/notifications.js +59 -0
  21. package/dist/account/notifications.js.map +7 -0
  22. package/dist/account/password.js +103 -0
  23. package/dist/account/password.js.map +7 -0
  24. package/dist/account/profile.js +116 -0
  25. package/dist/account/profile.js.map +7 -0
  26. package/dist/account/recovery.js +13 -0
  27. package/dist/account/recovery.js.map +7 -0
  28. package/dist/account/relevance.js +82 -0
  29. package/dist/account/relevance.js.map +7 -0
  30. package/dist/account/sessions.js +37 -0
  31. package/dist/account/sessions.js.map +7 -0
  32. package/dist/account/settings.js +39 -0
  33. package/dist/account/settings.js.map +7 -0
  34. package/dist/account/table-views.js +16 -0
  35. package/dist/account/table-views.js.map +7 -0
  36. package/dist/ai/AiAnswer.js +83 -0
  37. package/dist/ai/AiAnswer.js.map +7 -0
  38. package/dist/ai/AiMarkdown.js +40 -0
  39. package/dist/ai/AiMarkdown.js.map +7 -0
  40. package/dist/ai/ArtifactCanvas.js +193 -0
  41. package/dist/ai/ArtifactCanvas.js.map +7 -0
  42. package/dist/ai/CitationRenderer.js +413 -0
  43. package/dist/ai/CitationRenderer.js.map +7 -0
  44. package/dist/{chunk-WL2Y2T47.js → ai/MarkdownRenderer.js} +35 -101
  45. package/dist/ai/MarkdownRenderer.js.map +7 -0
  46. package/dist/ai/MessageArtifactCard.js +75 -0
  47. package/dist/ai/MessageArtifactCard.js.map +7 -0
  48. package/dist/ai/PassageCard.js +79 -0
  49. package/dist/ai/PassageCard.js.map +7 -0
  50. package/dist/ai/engine.js +110 -0
  51. package/dist/ai/engine.js.map +7 -0
  52. package/dist/ai/index.js +63 -0
  53. package/dist/ai/index.js.map +7 -0
  54. package/dist/ai/markdown-base-components.js +37 -0
  55. package/dist/ai/markdown-base-components.js.map +7 -0
  56. package/dist/ai/markdown-streaming-context.js +6 -0
  57. package/dist/ai/markdown-streaming-context.js.map +7 -0
  58. package/dist/{chunk-VSCU7K4V.js → ai/normalize-citations.js} +12 -19
  59. package/dist/ai/normalize-citations.js.map +7 -0
  60. package/dist/ai/redline.js +41 -0
  61. package/dist/ai/redline.js.map +7 -0
  62. package/dist/ai/split-markdown-blocks.js +40 -0
  63. package/dist/ai/split-markdown-blocks.js.map +7 -0
  64. package/dist/{chunk-UW2SGTI5.js → ai/stored-markdown.js} +41 -93
  65. package/dist/ai/stored-markdown.js.map +7 -0
  66. package/dist/annotations/AnnotationPageOverlay.js +807 -0
  67. package/dist/annotations/AnnotationPageOverlay.js.map +7 -0
  68. package/dist/annotations/AnnotationToolbar.js +398 -0
  69. package/dist/annotations/AnnotationToolbar.js.map +7 -0
  70. package/dist/annotations/FreezeDialog.js +170 -0
  71. package/dist/annotations/FreezeDialog.js.map +7 -0
  72. package/dist/annotations/ProductionDialog.js +354 -0
  73. package/dist/annotations/ProductionDialog.js.map +7 -0
  74. package/dist/annotations/controller.js +49 -0
  75. package/dist/annotations/controller.js.map +7 -0
  76. package/dist/annotations/freeze/browser.js +21 -0
  77. package/dist/annotations/freeze/browser.js.map +7 -0
  78. package/dist/annotations/freeze/bundle.js +201 -0
  79. package/dist/annotations/freeze/bundle.js.map +7 -0
  80. package/dist/annotations/freeze/coords.js +37 -0
  81. package/dist/annotations/freeze/coords.js.map +7 -0
  82. package/dist/annotations/freeze/freeze.js +261 -0
  83. package/dist/annotations/freeze/freeze.js.map +7 -0
  84. package/dist/annotations/freeze/hash.js +28 -0
  85. package/dist/annotations/freeze/hash.js.map +7 -0
  86. package/dist/annotations/freeze/index-page.js +78 -0
  87. package/dist/annotations/freeze/index-page.js.map +7 -0
  88. package/dist/annotations/freeze/index.d.ts +1 -1
  89. package/dist/annotations/freeze/index.js +28 -22
  90. package/dist/annotations/freeze/index.js.map +7 -1
  91. package/dist/annotations/freeze/raster.js +208 -0
  92. package/dist/annotations/freeze/raster.js.map +7 -0
  93. package/dist/annotations/freeze/stamp.js +117 -0
  94. package/dist/annotations/freeze/stamp.js.map +7 -0
  95. package/dist/annotations/freeze/types.js +14 -0
  96. package/dist/annotations/freeze/types.js.map +7 -0
  97. package/dist/annotations/freeze/vector.js +283 -0
  98. package/dist/annotations/freeze/vector.js.map +7 -0
  99. package/dist/annotations/geometry.js +81 -0
  100. package/dist/annotations/geometry.js.map +7 -0
  101. package/dist/annotations/index.js +125 -6
  102. package/dist/annotations/index.js.map +7 -1
  103. package/dist/annotations/merge.js +53 -0
  104. package/dist/annotations/merge.js.map +7 -0
  105. package/dist/{chunk-T3USOSVN.js → annotations/model.js} +23 -16
  106. package/dist/annotations/model.js.map +7 -0
  107. package/dist/annotations/overlay-geometry.js +41 -0
  108. package/dist/annotations/overlay-geometry.js.map +7 -0
  109. package/dist/annotations/redaction-log.js +33 -0
  110. package/dist/annotations/redaction-log.js.map +7 -0
  111. package/dist/annotations/selection-marks.js +122 -0
  112. package/dist/annotations/selection-marks.js.map +7 -0
  113. package/dist/annotations/state.js +140 -0
  114. package/dist/annotations/state.js.map +7 -0
  115. package/dist/annotations/store.js +49 -0
  116. package/dist/annotations/store.js.map +7 -0
  117. package/dist/annotations/useAnnotationLayer.js +306 -0
  118. package/dist/annotations/useAnnotationLayer.js.map +7 -0
  119. package/dist/annotations/useAnnotationShortcuts.js +31 -0
  120. package/dist/annotations/useAnnotationShortcuts.js.map +7 -0
  121. package/dist/annotations/useTextSelectionMarks.js +100 -0
  122. package/dist/annotations/useTextSelectionMarks.js.map +7 -0
  123. package/dist/artifacts/artifact-kind.js +19 -0
  124. package/dist/artifacts/artifact-kind.js.map +7 -0
  125. package/dist/artifacts/index.cjs +13 -13
  126. package/dist/artifacts/index.js +89 -571
  127. package/dist/artifacts/index.js.map +7 -1
  128. package/dist/{chunk-WUTL62MC.js → artifacts/normalize-markdown.js} +12 -14
  129. package/dist/artifacts/normalize-markdown.js.map +7 -0
  130. package/dist/artifacts/redline-core.js +12 -3
  131. package/dist/artifacts/redline-core.js.map +7 -1
  132. package/dist/{chunk-74N436VK.js → artifacts/redline-diff.js} +10 -9
  133. package/dist/artifacts/redline-diff.js.map +7 -0
  134. package/dist/artifacts/redline-engine.js +14 -0
  135. package/dist/artifacts/redline-engine.js.map +7 -0
  136. package/dist/artifacts/renderArtifactMarkdown.js +9 -0
  137. package/dist/artifacts/renderArtifactMarkdown.js.map +7 -0
  138. package/dist/artifacts/useArtifactEditSession.js +183 -0
  139. package/dist/artifacts/useArtifactEditSession.js.map +7 -0
  140. package/dist/artifacts/useArtifactSession.js +173 -0
  141. package/dist/artifacts/useArtifactSession.js.map +7 -0
  142. package/dist/artifacts/useArtifactSource.js +16 -0
  143. package/dist/artifacts/useArtifactSource.js.map +7 -0
  144. package/dist/artifacts/useArtifactText.js +78 -0
  145. package/dist/artifacts/useArtifactText.js.map +7 -0
  146. package/dist/artifacts/useRedline.js +65 -0
  147. package/dist/artifacts/useRedline.js.map +7 -0
  148. package/dist/artifacts/useStreamedArtifact.js +74 -0
  149. package/dist/artifacts/useStreamedArtifact.js.map +7 -0
  150. package/dist/artifacts/versions.js +68 -0
  151. package/dist/artifacts/versions.js.map +7 -0
  152. package/dist/billing.js +200 -0
  153. package/dist/billing.js.map +7 -0
  154. package/dist/boot-timeout.js +19 -0
  155. package/dist/boot-timeout.js.map +7 -0
  156. package/dist/calendar/accounts.js +213 -0
  157. package/dist/calendar/accounts.js.map +7 -0
  158. package/dist/calendar/hooks.js +409 -0
  159. package/dist/calendar/hooks.js.map +7 -0
  160. package/dist/calendar/index.js +31 -0
  161. package/dist/calendar/index.js.map +7 -0
  162. package/dist/calendar/keys.js +5 -0
  163. package/dist/calendar/keys.js.map +7 -0
  164. package/dist/calendar/offline/outbox.js +231 -0
  165. package/dist/calendar/offline/outbox.js.map +7 -0
  166. package/dist/calendar/offline/runtime.js +109 -0
  167. package/dist/calendar/offline/runtime.js.map +7 -0
  168. package/dist/calendar/offline/support.js +41 -0
  169. package/dist/calendar/offline/support.js.map +7 -0
  170. package/dist/calendar/support.js +34 -0
  171. package/dist/calendar/support.js.map +7 -0
  172. package/dist/calls/actions.js +226 -0
  173. package/dist/calls/actions.js.map +7 -0
  174. package/dist/calls/events.js +138 -0
  175. package/dist/calls/events.js.map +7 -0
  176. package/dist/calls/gate.js +19 -0
  177. package/dist/calls/gate.js.map +7 -0
  178. package/dist/calls/hooks.js +115 -0
  179. package/dist/calls/hooks.js.map +7 -0
  180. package/dist/calls/in-call-chat.js +132 -0
  181. package/dist/calls/in-call-chat.js.map +7 -0
  182. package/dist/calls/index.js +24 -0
  183. package/dist/calls/index.js.map +7 -0
  184. package/dist/calls/keys.js +17 -0
  185. package/dist/calls/keys.js.map +7 -0
  186. package/dist/calls/livekit/index.cjs +48 -48
  187. package/dist/calls/livekit/index.js +6 -958
  188. package/dist/calls/livekit/index.js.map +7 -1
  189. package/dist/calls/livekit/room.js +98 -0
  190. package/dist/calls/livekit/room.js.map +7 -0
  191. package/dist/calls/livekit/useCallRecorder.js +219 -0
  192. package/dist/calls/livekit/useCallRecorder.js.map +7 -0
  193. package/dist/calls/livekit/useCallTranscriber.js +309 -0
  194. package/dist/calls/livekit/useCallTranscriber.js.map +7 -0
  195. package/dist/calls/livekit/useHostMuteNotice.js +29 -0
  196. package/dist/calls/livekit/useHostMuteNotice.js.map +7 -0
  197. package/dist/calls/livekit/useInCallChat.js +161 -0
  198. package/dist/calls/livekit/useInCallChat.js.map +7 -0
  199. package/dist/calls/livekit/useWebinar.js +239 -0
  200. package/dist/calls/livekit/useWebinar.js.map +7 -0
  201. package/dist/calls/meeting-chat.js +149 -0
  202. package/dist/calls/meeting-chat.js.map +7 -0
  203. package/dist/calls/moderation.js +50 -0
  204. package/dist/calls/moderation.js.map +7 -0
  205. package/dist/calls/open-meeting-chat.js +29 -0
  206. package/dist/calls/open-meeting-chat.js.map +7 -0
  207. package/dist/calls/read-only.js +24 -0
  208. package/dist/calls/read-only.js.map +7 -0
  209. package/dist/calls/recording-media.js +218 -0
  210. package/dist/calls/recording-media.js.map +7 -0
  211. package/dist/calls/recording-playback.js +260 -0
  212. package/dist/calls/recording-playback.js.map +7 -0
  213. package/dist/calls/recording.js +268 -0
  214. package/dist/calls/recording.js.map +7 -0
  215. package/dist/calls/save-to-thread.js +80 -0
  216. package/dist/calls/save-to-thread.js.map +7 -0
  217. package/dist/calls/session.js +134 -0
  218. package/dist/calls/session.js.map +7 -0
  219. package/dist/calls/transcript-format.js +147 -0
  220. package/dist/calls/transcript-format.js.map +7 -0
  221. package/dist/calls/transcription.js +101 -0
  222. package/dist/calls/transcription.js.map +7 -0
  223. package/dist/calls/webinar.js +71 -0
  224. package/dist/calls/webinar.js.map +7 -0
  225. package/dist/charge-watch.js +71 -0
  226. package/dist/charge-watch.js.map +7 -0
  227. package/dist/chat/ChatBubble.js +146 -0
  228. package/dist/chat/ChatBubble.js.map +7 -0
  229. package/dist/chat/ConversationScope.js +30 -0
  230. package/dist/chat/ConversationScope.js.map +7 -0
  231. package/dist/chat/active-config.js +20 -0
  232. package/dist/chat/active-config.js.map +7 -0
  233. package/dist/chat/agent-chat-owner.js +25 -0
  234. package/dist/chat/agent-chat-owner.js.map +7 -0
  235. package/dist/chat/chat-artifacts.js +64 -0
  236. package/dist/chat/chat-artifacts.js.map +7 -0
  237. package/dist/chat/citations.js +32 -0
  238. package/dist/chat/citations.js.map +7 -0
  239. package/dist/chat/config-model.js +10 -0
  240. package/dist/chat/config-model.js.map +7 -0
  241. package/dist/chat/conversation-cache.js +676 -0
  242. package/dist/chat/conversation-cache.js.map +7 -0
  243. package/dist/chat/conversation-events.js +57 -0
  244. package/dist/chat/conversation-events.js.map +7 -0
  245. package/dist/chat/conversation-mentions.js +58 -0
  246. package/dist/chat/conversation-mentions.js.map +7 -0
  247. package/dist/chat/conversation-workspace.js +58 -0
  248. package/dist/chat/conversation-workspace.js.map +7 -0
  249. package/dist/chat/mentions.js +116 -0
  250. package/dist/chat/mentions.js.map +7 -0
  251. package/dist/chat/open-document.js +106 -0
  252. package/dist/chat/open-document.js.map +7 -0
  253. package/dist/chat/orphaned.js +44 -0
  254. package/dist/chat/orphaned.js.map +7 -0
  255. package/dist/chat/pendingFirstTurn.js +30 -0
  256. package/dist/chat/pendingFirstTurn.js.map +7 -0
  257. package/dist/chat/reply-target.js +12 -0
  258. package/dist/chat/reply-target.js.map +7 -0
  259. package/dist/chat/run-finished.js +28 -0
  260. package/dist/chat/run-finished.js.map +7 -0
  261. package/dist/chat/run-state.js +91 -0
  262. package/dist/chat/run-state.js.map +7 -0
  263. package/dist/chat/stream-handlers.js +419 -0
  264. package/dist/chat/stream-handlers.js.map +7 -0
  265. package/dist/chat/thread-binding.js +76 -0
  266. package/dist/chat/thread-binding.js.map +7 -0
  267. package/dist/chat/thread-document.js +53 -0
  268. package/dist/chat/thread-document.js.map +7 -0
  269. package/dist/chat/turn-control.js +79 -0
  270. package/dist/chat/turn-control.js.map +7 -0
  271. package/dist/chat/useAgentRunControl.js +36 -0
  272. package/dist/chat/useAgentRunControl.js.map +7 -0
  273. package/dist/chat/useAnswerAgentQuestion.js +19 -0
  274. package/dist/chat/useAnswerAgentQuestion.js.map +7 -0
  275. package/dist/chat/useAskAgain.js +32 -0
  276. package/dist/chat/useAskAgain.js.map +7 -0
  277. package/dist/chat/useAutoSendDraft.js +17 -0
  278. package/dist/chat/useAutoSendDraft.js.map +7 -0
  279. package/dist/chat/useBranchNavigation.js +97 -0
  280. package/dist/chat/useBranchNavigation.js.map +7 -0
  281. package/dist/chat/useConnectRunStream.js +169 -0
  282. package/dist/chat/useConnectRunStream.js.map +7 -0
  283. package/dist/chat/useConversation.js +431 -0
  284. package/dist/chat/useConversation.js.map +7 -0
  285. package/dist/chat/useConversationActions.js +662 -0
  286. package/dist/chat/useConversationActions.js.map +7 -0
  287. package/dist/chat/useConversationData.js +143 -0
  288. package/dist/chat/useConversationData.js.map +7 -0
  289. package/dist/chat/useConversationDocuments.js +41 -0
  290. package/dist/chat/useConversationDocuments.js.map +7 -0
  291. package/dist/chat/useConversationSettings.js +78 -0
  292. package/dist/chat/useConversationSettings.js.map +7 -0
  293. package/dist/chat/useConversationTurn.js +31 -0
  294. package/dist/chat/useConversationTurn.js.map +7 -0
  295. package/dist/chat/useConversationWorkspace.js +12 -0
  296. package/dist/chat/useConversationWorkspace.js.map +7 -0
  297. package/dist/chat/useDeleteMessage.js +15 -0
  298. package/dist/chat/useDeleteMessage.js.map +7 -0
  299. package/dist/chat/useDocumentAutoAdd.js +73 -0
  300. package/dist/chat/useDocumentAutoAdd.js.map +7 -0
  301. package/dist/chat/useMessageTimer.js +39 -0
  302. package/dist/chat/useMessageTimer.js.map +7 -0
  303. package/dist/chat/useThinkingContent.js +67 -0
  304. package/dist/chat/useThinkingContent.js.map +7 -0
  305. package/dist/chat/useThreadDocument.js +61 -0
  306. package/dist/chat/useThreadDocument.js.map +7 -0
  307. package/dist/chat/workflow-run-titles.js +50 -0
  308. package/dist/chat/workflow-run-titles.js.map +7 -0
  309. package/dist/{chunk-W2FATOTX.cjs → chunk-3JAEX57E.cjs} +4 -4
  310. package/dist/{chunk-W2FATOTX.cjs.map → chunk-3JAEX57E.cjs.map} +1 -1
  311. package/dist/{chunk-HD5H2PPP.cjs → chunk-5TRUFWKT.cjs} +66 -66
  312. package/dist/{chunk-HD5H2PPP.cjs.map → chunk-5TRUFWKT.cjs.map} +1 -1
  313. package/dist/{chunk-Z3W4XFWB.cjs → chunk-C72FSQUE.cjs} +3 -3
  314. package/dist/{chunk-Z3W4XFWB.cjs.map → chunk-C72FSQUE.cjs.map} +1 -1
  315. package/dist/{chunk-LBAG7KL7.cjs → chunk-FQVNZCTD.cjs} +3 -3
  316. package/dist/{chunk-LBAG7KL7.cjs.map → chunk-FQVNZCTD.cjs.map} +1 -1
  317. package/dist/{chunk-RVUGSM65.cjs → chunk-GKGAPU6T.cjs} +44 -44
  318. package/dist/{chunk-RVUGSM65.cjs.map → chunk-GKGAPU6T.cjs.map} +1 -1
  319. package/dist/{chunk-7LIMHY56.cjs → chunk-O32T7XRD.cjs} +3 -3
  320. package/dist/{chunk-7LIMHY56.cjs.map → chunk-O32T7XRD.cjs.map} +1 -1
  321. package/dist/chunk-PWGSIM3F.cjs +291 -0
  322. package/dist/chunk-PWGSIM3F.cjs.map +1 -0
  323. package/dist/chunk-QP3WQSAA.cjs +23 -0
  324. package/dist/chunk-QP3WQSAA.cjs.map +1 -0
  325. package/dist/chunk-T5FZICXN.cjs +50 -0
  326. package/dist/chunk-T5FZICXN.cjs.map +1 -0
  327. package/dist/{chunk-QF2BW6HZ.cjs → chunk-UDDJIUHJ.cjs} +38 -38
  328. package/dist/{chunk-QF2BW6HZ.cjs.map → chunk-UDDJIUHJ.cjs.map} +1 -1
  329. package/dist/{chunk-5HDKL6XB.cjs → chunk-YMB6XUR2.cjs} +57 -57
  330. package/dist/{chunk-5HDKL6XB.cjs.map → chunk-YMB6XUR2.cjs.map} +1 -1
  331. package/dist/config/config-hooks.js +209 -0
  332. package/dist/config/config-hooks.js.map +7 -0
  333. package/dist/connectivity.js +72 -0
  334. package/dist/connectivity.js.map +7 -0
  335. package/dist/connectors/hooks.js +263 -0
  336. package/dist/connectors/hooks.js.map +7 -0
  337. package/dist/connectors/index.js +28 -0
  338. package/dist/connectors/index.js.map +7 -0
  339. package/dist/contacts.js +100 -0
  340. package/dist/contacts.js.map +7 -0
  341. package/dist/conversation-list.js +65 -0
  342. package/dist/conversation-list.js.map +7 -0
  343. package/dist/databases.js +195 -0
  344. package/dist/databases.js.map +7 -0
  345. package/dist/datasets/aggregate.js +281 -0
  346. package/dist/datasets/aggregate.js.map +7 -0
  347. package/dist/datasets/index.js +122 -0
  348. package/dist/datasets/index.js.map +7 -0
  349. package/dist/datasets/members.js +27 -0
  350. package/dist/datasets/members.js.map +7 -0
  351. package/dist/datasets/panel.js +44 -0
  352. package/dist/datasets/panel.js.map +7 -0
  353. package/dist/datasets/registry.js +47 -0
  354. package/dist/datasets/registry.js.map +7 -0
  355. package/dist/datasets/rows-source.js +44 -0
  356. package/dist/datasets/rows-source.js.map +7 -0
  357. package/dist/datasets/sources/activity.js +83 -0
  358. package/dist/datasets/sources/activity.js.map +7 -0
  359. package/dist/datasets/sources/conversations.js +74 -0
  360. package/dist/datasets/sources/conversations.js.map +7 -0
  361. package/dist/datasets/sources/database.js +209 -0
  362. package/dist/datasets/sources/database.js.map +7 -0
  363. package/dist/datasets/sources/documents.js +93 -0
  364. package/dist/datasets/sources/documents.js.map +7 -0
  365. package/dist/datasets/sources/facts.js +56 -0
  366. package/dist/datasets/sources/facts.js.map +7 -0
  367. package/dist/datasets/sources/projects.js +117 -0
  368. package/dist/datasets/sources/projects.js.map +7 -0
  369. package/dist/datasets/sources/tags.js +67 -0
  370. package/dist/datasets/sources/tags.js.map +7 -0
  371. package/dist/datasets/sources/usage.js +268 -0
  372. package/dist/datasets/sources/usage.js.map +7 -0
  373. package/dist/datasets/sources/workflows.js +91 -0
  374. package/dist/datasets/sources/workflows.js.map +7 -0
  375. package/dist/datasets/sources/workspaces.js +67 -0
  376. package/dist/datasets/sources/workspaces.js.map +7 -0
  377. package/dist/datasets/store.js +194 -0
  378. package/dist/datasets/store.js.map +7 -0
  379. package/dist/datasets/types.js +14 -0
  380. package/dist/datasets/types.js.map +7 -0
  381. package/dist/directmessages/ConversationList.js +148 -0
  382. package/dist/directmessages/ConversationList.js.map +7 -0
  383. package/dist/directmessages/DateSeparator.js +8 -0
  384. package/dist/directmessages/DateSeparator.js.map +7 -0
  385. package/dist/directmessages/DmAvatar.js +29 -0
  386. package/dist/directmessages/DmAvatar.js.map +7 -0
  387. package/dist/directmessages/DmComposer.js +201 -0
  388. package/dist/directmessages/DmComposer.js.map +7 -0
  389. package/dist/directmessages/arrivals.js +29 -0
  390. package/dist/directmessages/arrivals.js.map +7 -0
  391. package/dist/directmessages/chat-cache.js +192 -0
  392. package/dist/directmessages/chat-cache.js.map +7 -0
  393. package/dist/directmessages/grouping.js +26 -0
  394. package/dist/directmessages/grouping.js.map +7 -0
  395. package/dist/directmessages/index.js +81 -0
  396. package/dist/directmessages/index.js.map +7 -0
  397. package/dist/directmessages/useChats.js +266 -0
  398. package/dist/directmessages/useChats.js.map +7 -0
  399. package/dist/directmessages/utils.js +23 -0
  400. package/dist/directmessages/utils.js.map +7 -0
  401. package/dist/document-tools/can-annotate.js +7 -0
  402. package/dist/document-tools/can-annotate.js.map +7 -0
  403. package/dist/document-tools/core.cjs +99 -99
  404. package/dist/document-tools/core.d.ts +2 -2
  405. package/dist/document-tools/core.js +218 -12
  406. package/dist/document-tools/core.js.map +7 -1
  407. package/dist/document-tools/document-pdf.js +76 -0
  408. package/dist/document-tools/document-pdf.js.map +7 -0
  409. package/dist/document-tools/environment.js +136 -0
  410. package/dist/document-tools/environment.js.map +7 -0
  411. package/dist/document-tools/file-shares.js +112 -0
  412. package/dist/document-tools/file-shares.js.map +7 -0
  413. package/dist/document-tools/frozen-copy.js +27 -0
  414. package/dist/document-tools/frozen-copy.js.map +7 -0
  415. package/dist/document-tools/index.cjs +101 -101
  416. package/dist/document-tools/index.d.ts +1 -1
  417. package/dist/document-tools/index.js +26 -148
  418. package/dist/document-tools/index.js.map +7 -1
  419. package/dist/document-tools/markup-download.js +51 -0
  420. package/dist/document-tools/markup-download.js.map +7 -0
  421. package/dist/document-tools/markup-store.js +138 -0
  422. package/dist/document-tools/markup-store.js.map +7 -0
  423. package/dist/document-tools/markup-transfer.js +88 -0
  424. package/dist/document-tools/markup-transfer.js.map +7 -0
  425. package/dist/document-tools/production.js +147 -0
  426. package/dist/document-tools/production.js.map +7 -0
  427. package/dist/document-tools/saved-signature.js +90 -0
  428. package/dist/document-tools/saved-signature.js.map +7 -0
  429. package/dist/document-tools/signature-requests.js +310 -0
  430. package/dist/document-tools/signature-requests.js.map +7 -0
  431. package/dist/document-tools/signing.js +127 -0
  432. package/dist/document-tools/signing.js.map +7 -0
  433. package/dist/document-tools/useDocumentBytes.js +38 -0
  434. package/dist/document-tools/useDocumentBytes.js.map +7 -0
  435. package/dist/document-tools/useDocumentMarkup.js +154 -0
  436. package/dist/document-tools/useDocumentMarkup.js.map +7 -0
  437. package/dist/document-tools/useIsOnline.js +13 -0
  438. package/dist/document-tools/useIsOnline.js.map +7 -0
  439. package/dist/document-tools/verification.js +60 -0
  440. package/dist/document-tools/verification.js.map +7 -0
  441. package/dist/documents/DocumentReview.js +220 -0
  442. package/dist/documents/DocumentReview.js.map +7 -0
  443. package/dist/documents/DraftTitleControls.js +41 -0
  444. package/dist/documents/DraftTitleControls.js.map +7 -0
  445. package/dist/documents/InlineMicButton.js +90 -0
  446. package/dist/documents/InlineMicButton.js.map +7 -0
  447. package/dist/documents/MicRecordingOverlay.js +29 -0
  448. package/dist/documents/MicRecordingOverlay.js.map +7 -0
  449. package/dist/documents/MicWaveformIndicator.js +68 -0
  450. package/dist/documents/MicWaveformIndicator.js.map +7 -0
  451. package/dist/documents/PhotoCapture.js +120 -0
  452. package/dist/documents/PhotoCapture.js.map +7 -0
  453. package/dist/documents/VideoCapture.js +129 -0
  454. package/dist/documents/VideoCapture.js.map +7 -0
  455. package/dist/documents/VoiceNoteRecorder.js +166 -0
  456. package/dist/documents/VoiceNoteRecorder.js.map +7 -0
  457. package/dist/documents/audio-segmenter.js +63 -0
  458. package/dist/documents/audio-segmenter.js.map +7 -0
  459. package/dist/documents/capture-frame.js +21 -0
  460. package/dist/documents/capture-frame.js.map +7 -0
  461. package/dist/documents/chunked-recorder.js +190 -0
  462. package/dist/documents/chunked-recorder.js.map +7 -0
  463. package/dist/documents/document-download.js +53 -0
  464. package/dist/documents/document-download.js.map +7 -0
  465. package/dist/documents/document-fields.js +109 -0
  466. package/dist/documents/document-fields.js.map +7 -0
  467. package/dist/documents/documents-cache.js +110 -0
  468. package/dist/documents/documents-cache.js.map +7 -0
  469. package/dist/documents/documents-data.js +128 -0
  470. package/dist/documents/documents-data.js.map +7 -0
  471. package/dist/documents/documents-loader.js +113 -0
  472. package/dist/documents/documents-loader.js.map +7 -0
  473. package/dist/documents/documents-writes.js +448 -0
  474. package/dist/documents/documents-writes.js.map +7 -0
  475. package/dist/documents/format-elapsed.js +10 -0
  476. package/dist/documents/format-elapsed.js.map +7 -0
  477. package/dist/documents/has-video-track.js +26 -0
  478. package/dist/documents/has-video-track.js.map +7 -0
  479. package/dist/documents/index.js +266 -0
  480. package/dist/documents/index.js.map +7 -0
  481. package/dist/documents/media-error.js +18 -0
  482. package/dist/documents/media-error.js.map +7 -0
  483. package/dist/documents/offline-documents.js +160 -0
  484. package/dist/documents/offline-documents.js.map +7 -0
  485. package/dist/documents/pending-sync.js +210 -0
  486. package/dist/documents/pending-sync.js.map +7 -0
  487. package/dist/documents/processing-live.js +122 -0
  488. package/dist/documents/processing-live.js.map +7 -0
  489. package/dist/documents/processing-order.js +59 -0
  490. package/dist/documents/processing-order.js.map +7 -0
  491. package/dist/documents/processing-settle.js +21 -0
  492. package/dist/documents/processing-settle.js.map +7 -0
  493. package/dist/documents/related-documents.js +133 -0
  494. package/dist/documents/related-documents.js.map +7 -0
  495. package/dist/documents/support.js +29 -0
  496. package/dist/documents/support.js.map +7 -0
  497. package/dist/documents/upload-files.js +169 -0
  498. package/dist/documents/upload-files.js.map +7 -0
  499. package/dist/documents/useAudioRecorder.js +315 -0
  500. package/dist/documents/useAudioRecorder.js.map +7 -0
  501. package/dist/documents/useCameraStream.js +35 -0
  502. package/dist/documents/useCameraStream.js.map +7 -0
  503. package/dist/documents/useDocumentThumbnails.js +71 -0
  504. package/dist/documents/useDocumentThumbnails.js.map +7 -0
  505. package/dist/documents/useDownloadDocuments.js +90 -0
  506. package/dist/documents/useDownloadDocuments.js.map +7 -0
  507. package/dist/documents/usePassageQuotes.js +37 -0
  508. package/dist/documents/usePassageQuotes.js.map +7 -0
  509. package/dist/documents/useUploadFiles.js +165 -0
  510. package/dist/documents/useUploadFiles.js.map +7 -0
  511. package/dist/documents/useUploadFromUrls.js +63 -0
  512. package/dist/documents/useUploadFromUrls.js.map +7 -0
  513. package/dist/documents/useVideoRecorder.js +62 -0
  514. package/dist/documents/useVideoRecorder.js.map +7 -0
  515. package/dist/entities/AgentMarkers.js +61 -0
  516. package/dist/entities/AgentMarkers.js.map +7 -0
  517. package/dist/entities/DocumentEntity.js +125 -0
  518. package/dist/entities/DocumentEntity.js.map +7 -0
  519. package/dist/entities/EntityPill.js +250 -0
  520. package/dist/entities/EntityPill.js.map +7 -0
  521. package/dist/entities/ProjectEntity.js +61 -0
  522. package/dist/entities/ProjectEntity.js.map +7 -0
  523. package/dist/entities/ShieldIcon.js +49 -0
  524. package/dist/entities/ShieldIcon.js.map +7 -0
  525. package/dist/entities/TagEntity.js +79 -0
  526. package/dist/entities/TagEntity.js.map +7 -0
  527. package/dist/entities/ThreadVisibilityIcon.js +15 -0
  528. package/dist/entities/ThreadVisibilityIcon.js.map +7 -0
  529. package/dist/entities/UserEntity.js +211 -0
  530. package/dist/entities/UserEntity.js.map +7 -0
  531. package/dist/entities/VerifiedBadge.js +19 -0
  532. package/dist/entities/VerifiedBadge.js.map +7 -0
  533. package/dist/entities/agent-avatar-colors.js +26 -0
  534. package/dist/entities/agent-avatar-colors.js.map +7 -0
  535. package/dist/entities/colors.js +64 -0
  536. package/dist/entities/colors.js.map +7 -0
  537. package/dist/entities/file-type.js +151 -0
  538. package/dist/entities/file-type.js.map +7 -0
  539. package/dist/entities/index.js +100 -0
  540. package/dist/entities/index.js.map +7 -0
  541. package/dist/entities/media-type.js +61 -0
  542. package/dist/entities/media-type.js.map +7 -0
  543. package/dist/entities/registry.js +385 -0
  544. package/dist/entities/registry.js.map +7 -0
  545. package/dist/entities/status.js +43 -0
  546. package/dist/entities/status.js.map +7 -0
  547. package/dist/entities/tag-kinds.js +23 -0
  548. package/dist/entities/tag-kinds.js.map +7 -0
  549. package/dist/entities/tag-types.js +44 -0
  550. package/dist/entities/tag-types.js.map +7 -0
  551. package/dist/entities/vocabulary.js +12 -0
  552. package/dist/entities/vocabulary.js.map +7 -0
  553. package/dist/entity-extraction.js +25 -0
  554. package/dist/entity-extraction.js.map +7 -0
  555. package/dist/facts-search.js +57 -0
  556. package/dist/facts-search.js.map +7 -0
  557. package/dist/facts.js +69 -0
  558. package/dist/facts.js.map +7 -0
  559. package/dist/hooks.js +320 -0
  560. package/dist/hooks.js.map +7 -0
  561. package/dist/host/ArbiHost.js +24 -0
  562. package/dist/host/ArbiHost.js.map +7 -0
  563. package/dist/host/assistant-copy.js +54 -0
  564. package/dist/host/assistant-copy.js.map +7 -0
  565. package/dist/host/config.js +9 -0
  566. package/dist/host/config.js.map +7 -0
  567. package/dist/host/context.js +10 -0
  568. package/dist/host/context.js.map +7 -0
  569. package/dist/host/features.js +144 -0
  570. package/dist/host/features.js.map +7 -0
  571. package/dist/host/index.js +12 -0
  572. package/dist/host/index.js.map +7 -0
  573. package/dist/{chunk-DPYBZDJB.js → host/merge.js} +7 -7
  574. package/dist/host/merge.js.map +7 -0
  575. package/dist/house-template.js +40 -0
  576. package/dist/house-template.js.map +7 -0
  577. package/dist/icons/AppleIcon.js +25 -0
  578. package/dist/icons/AppleIcon.js.map +7 -0
  579. package/dist/icons/ArbiBotHeadIcon.js +46 -0
  580. package/dist/icons/ArbiBotHeadIcon.js.map +7 -0
  581. package/dist/icons/ArbiIcon.js +24 -0
  582. package/dist/icons/ArbiIcon.js.map +7 -0
  583. package/dist/icons/AudIcon.js +56 -0
  584. package/dist/icons/AudIcon.js.map +7 -0
  585. package/dist/icons/ClaudeIcon.js +28 -0
  586. package/dist/icons/ClaudeIcon.js.map +7 -0
  587. package/dist/icons/DocIcon.js +56 -0
  588. package/dist/icons/DocIcon.js.map +7 -0
  589. package/dist/icons/EmlIcon.js +57 -0
  590. package/dist/icons/EmlIcon.js.map +7 -0
  591. package/dist/icons/FireworksIcon.js +47 -0
  592. package/dist/icons/FireworksIcon.js.map +7 -0
  593. package/dist/icons/GeminiIcon.js +37 -0
  594. package/dist/icons/GeminiIcon.js.map +7 -0
  595. package/dist/icons/GitHubIcon.js +32 -0
  596. package/dist/icons/GitHubIcon.js.map +7 -0
  597. package/dist/icons/GoogleIcon.js +53 -0
  598. package/dist/icons/GoogleIcon.js.map +7 -0
  599. package/dist/icons/HtmlIcon.js +56 -0
  600. package/dist/icons/HtmlIcon.js.map +7 -0
  601. package/dist/icons/ImgIcon.js +56 -0
  602. package/dist/icons/ImgIcon.js.map +7 -0
  603. package/dist/icons/LinkedInIcon.js +25 -0
  604. package/dist/icons/LinkedInIcon.js.map +7 -0
  605. package/dist/icons/OpenAIIcon.js +28 -0
  606. package/dist/icons/OpenAIIcon.js.map +7 -0
  607. package/dist/icons/PdfIcon.js +56 -0
  608. package/dist/icons/PdfIcon.js.map +7 -0
  609. package/dist/icons/ProviderIcon.js +42 -0
  610. package/dist/icons/ProviderIcon.js.map +7 -0
  611. package/dist/icons/TxtIcon.js +56 -0
  612. package/dist/icons/TxtIcon.js.map +7 -0
  613. package/dist/icons/VidIcon.js +56 -0
  614. package/dist/icons/VidIcon.js.map +7 -0
  615. package/dist/icons/XlsIcon.js +56 -0
  616. package/dist/icons/XlsIcon.js.map +7 -0
  617. package/dist/icons/arbi-mark.js +5 -0
  618. package/dist/icons/arbi-mark.js.map +7 -0
  619. package/dist/icons/colors.js +31 -0
  620. package/dist/icons/colors.js.map +7 -0
  621. package/dist/icons/file-type.js +105 -0
  622. package/dist/icons/file-type.js.map +7 -0
  623. package/dist/icons/index.js +55 -0
  624. package/dist/icons/index.js.map +7 -0
  625. package/dist/imagecrop/ImageCropModal.js +56 -0
  626. package/dist/imagecrop/ImageCropModal.js.map +7 -0
  627. package/dist/imagecrop/ImageCropper.js +100 -0
  628. package/dist/imagecrop/ImageCropper.js.map +7 -0
  629. package/dist/imagecrop/cropImage.js +43 -0
  630. package/dist/imagecrop/cropImage.js.map +7 -0
  631. package/dist/imagecrop/index.js +13 -0
  632. package/dist/imagecrop/index.js.map +7 -0
  633. package/dist/index.cjs +1689 -1619
  634. package/dist/index.cjs.map +1 -1
  635. package/dist/{index.d-BMhTH98a.d.ts → index.d-CYXcTKYt.d.ts} +1 -0
  636. package/dist/index.d.ts +38 -8
  637. package/dist/index.js +702 -17060
  638. package/dist/index.js.map +7 -1
  639. package/dist/lazy-chunk.d-B6YDLMKI.d.ts +31 -0
  640. package/dist/lazy-chunk.js +46 -0
  641. package/dist/lazy-chunk.js.map +7 -0
  642. package/dist/lib/collision-padding.js +13 -0
  643. package/dist/lib/collision-padding.js.map +7 -0
  644. package/dist/lib/format-friendly-date.js +55 -0
  645. package/dist/lib/format-friendly-date.js.map +7 -0
  646. package/dist/lib/format-relative-time.js +52 -0
  647. package/dist/lib/format-relative-time.js.map +7 -0
  648. package/dist/lib/markdown-to-text.js +35 -0
  649. package/dist/lib/markdown-to-text.js.map +7 -0
  650. package/dist/lib/toast-interaction.js +9 -0
  651. package/dist/lib/toast-interaction.js.map +7 -0
  652. package/dist/lib/utils.js +9 -0
  653. package/dist/lib/utils.js.map +7 -0
  654. package/dist/mail/client.js +103 -0
  655. package/dist/mail/client.js.map +7 -0
  656. package/dist/mail/document-attachment.js +38 -0
  657. package/dist/mail/document-attachment.js.map +7 -0
  658. package/dist/mail/filing.js +132 -0
  659. package/dist/mail/filing.js.map +7 -0
  660. package/dist/mail/hooks.js +393 -0
  661. package/dist/mail/hooks.js.map +7 -0
  662. package/dist/mail/index.js +120 -0
  663. package/dist/mail/index.js.map +7 -0
  664. package/dist/mail/offline/changes.js +258 -0
  665. package/dist/mail/offline/changes.js.map +7 -0
  666. package/dist/mail/offline/confirm-sign-out.js +37 -0
  667. package/dist/mail/offline/confirm-sign-out.js.map +7 -0
  668. package/dist/mail/offline/crypto.js +26 -0
  669. package/dist/mail/offline/crypto.js.map +7 -0
  670. package/dist/mail/offline/drafts.js +69 -0
  671. package/dist/mail/offline/drafts.js.map +7 -0
  672. package/dist/mail/offline/hooks.js +104 -0
  673. package/dist/mail/offline/hooks.js.map +7 -0
  674. package/dist/mail/offline/index.js +48 -0
  675. package/dist/mail/offline/index.js.map +7 -0
  676. package/dist/mail/offline/live.js +233 -0
  677. package/dist/mail/offline/live.js.map +7 -0
  678. package/dist/mail/offline/mailbox.js +191 -0
  679. package/dist/mail/offline/mailbox.js.map +7 -0
  680. package/dist/mail/offline/outbox.js +167 -0
  681. package/dist/mail/offline/outbox.js.map +7 -0
  682. package/dist/mail/offline/reads.js +159 -0
  683. package/dist/mail/offline/reads.js.map +7 -0
  684. package/dist/mail/offline/runtime.js +100 -0
  685. package/dist/mail/offline/runtime.js.map +7 -0
  686. package/dist/mail/offline/settings.js +84 -0
  687. package/dist/mail/offline/settings.js.map +7 -0
  688. package/dist/mail/offline/store.js +29 -0
  689. package/dist/mail/offline/store.js.map +7 -0
  690. package/dist/mail/offline/sync.js +251 -0
  691. package/dist/mail/offline/sync.js.map +7 -0
  692. package/dist/mail/offline/wipe.js +19 -0
  693. package/dist/mail/offline/wipe.js.map +7 -0
  694. package/dist/mail/thread-keys.js +53 -0
  695. package/dist/mail/thread-keys.js.map +7 -0
  696. package/dist/mail/threads.js +71 -0
  697. package/dist/mail/threads.js.map +7 -0
  698. package/dist/mail/useMailClient.js +42 -0
  699. package/dist/mail/useMailClient.js.map +7 -0
  700. package/dist/model-connections.js +58 -0
  701. package/dist/model-connections.js.map +7 -0
  702. package/dist/notifications/ActivityFeed.js +70 -0
  703. package/dist/notifications/ActivityFeed.js.map +7 -0
  704. package/dist/notifications/NotificationBell.js +200 -0
  705. package/dist/notifications/NotificationBell.js.map +7 -0
  706. package/dist/notifications/Toaster.js +24 -0
  707. package/dist/notifications/Toaster.js.map +7 -0
  708. package/dist/notifications/activity-types.js +65 -0
  709. package/dist/notifications/activity-types.js.map +7 -0
  710. package/dist/notifications/bell.js +24 -0
  711. package/dist/notifications/bell.js.map +7 -0
  712. package/dist/notifications/calendar-notifications.js +79 -0
  713. package/dist/notifications/calendar-notifications.js.map +7 -0
  714. package/dist/notifications/index.js +108 -0
  715. package/dist/notifications/index.js.map +7 -0
  716. package/dist/notifications/live.js +28 -0
  717. package/dist/notifications/live.js.map +7 -0
  718. package/dist/notifications/notification-types.js +127 -0
  719. package/dist/notifications/notification-types.js.map +7 -0
  720. package/dist/{chunk-BF5KW5ZI.js → notifications/notify-store.js} +24 -74
  721. package/dist/notifications/notify-store.js.map +7 -0
  722. package/dist/notifications/server-notifications.js +452 -0
  723. package/dist/notifications/server-notifications.js.map +7 -0
  724. package/dist/notifications/useNotifications.js +34 -0
  725. package/dist/notifications/useNotifications.js.map +7 -0
  726. package/dist/offline-store/network.js +11 -0
  727. package/dist/offline-store/network.js.map +7 -0
  728. package/dist/offline-store/store.js +136 -0
  729. package/dist/offline-store/store.js.map +7 -0
  730. package/dist/offline-store/wipe.js +8 -0
  731. package/dist/offline-store/wipe.js.map +7 -0
  732. package/dist/offline.js +58 -0
  733. package/dist/offline.js.map +7 -0
  734. package/dist/people.js +122 -0
  735. package/dist/people.js.map +7 -0
  736. package/dist/projects.js +30 -0
  737. package/dist/projects.js.map +7 -0
  738. package/dist/query-client.js +63 -0
  739. package/dist/query-client.js.map +7 -0
  740. package/dist/{query-keys.d-ChgpJLPF.d.ts → query-keys.d-B1Am9tIF.d.ts} +1 -1
  741. package/dist/{chunk-6H3O63TQ.js → query-keys.js} +19 -32
  742. package/dist/query-keys.js.map +7 -0
  743. package/dist/query-persist.js +66 -0
  744. package/dist/query-persist.js.map +7 -0
  745. package/dist/queued-writes.js +59 -0
  746. package/dist/queued-writes.js.map +7 -0
  747. package/dist/remote-control.js +67 -0
  748. package/dist/remote-control.js.map +7 -0
  749. package/dist/search/index.js +23 -0
  750. package/dist/search/index.js.map +7 -0
  751. package/dist/search/session.js +58 -0
  752. package/dist/search/session.js.map +7 -0
  753. package/dist/search/useSemanticSearch.js +82 -0
  754. package/dist/search/useSemanticSearch.js.map +7 -0
  755. package/dist/session/chat.js +512 -0
  756. package/dist/session/chat.js.map +7 -0
  757. package/dist/session/documents.js +196 -0
  758. package/dist/session/documents.js.map +7 -0
  759. package/dist/session/drafts.js +103 -0
  760. package/dist/session/drafts.js.map +7 -0
  761. package/dist/session/index.js +123 -0
  762. package/dist/session/index.js.map +7 -0
  763. package/dist/session/layout.js +339 -0
  764. package/dist/session/layout.js.map +7 -0
  765. package/dist/session/persist.js +106 -0
  766. package/dist/session/persist.js.map +7 -0
  767. package/dist/session/session-hooks.js +53 -0
  768. package/dist/session/session-hooks.js.map +7 -0
  769. package/dist/session/signed-in.js +36 -0
  770. package/dist/session/signed-in.js.map +7 -0
  771. package/dist/session/store.js +166 -0
  772. package/dist/session/store.js.map +7 -0
  773. package/dist/session/thread-tabs.js +121 -0
  774. package/dist/session/thread-tabs.js.map +7 -0
  775. package/dist/session/ui-state-storage.js +76 -0
  776. package/dist/session/ui-state-storage.js.map +7 -0
  777. package/dist/session/workspace.js +77 -0
  778. package/dist/session/workspace.js.map +7 -0
  779. package/dist/shell/index.cjs +37 -37
  780. package/dist/shell/index.js +43 -10
  781. package/dist/shell/index.js.map +7 -1
  782. package/dist/skill-pack.js +111 -0
  783. package/dist/skill-pack.js.map +7 -0
  784. package/dist/storage.js +186 -0
  785. package/dist/storage.js.map +7 -0
  786. package/dist/support/index.js +35 -0
  787. package/dist/support/index.js.map +7 -0
  788. package/dist/tags.js +204 -0
  789. package/dist/tags.js.map +7 -0
  790. package/dist/ui/DebouncedInput.js +109 -0
  791. package/dist/ui/DebouncedInput.js.map +7 -0
  792. package/dist/ui/DictateContext.js +8 -0
  793. package/dist/ui/DictateContext.js.map +7 -0
  794. package/dist/ui/IconToggle.js +79 -0
  795. package/dist/ui/IconToggle.js.map +7 -0
  796. package/dist/ui/VerifiedToggle.js +38 -0
  797. package/dist/ui/VerifiedToggle.js.map +7 -0
  798. package/dist/ui/VisibilityToggle.js +103 -0
  799. package/dist/ui/VisibilityToggle.js.map +7 -0
  800. package/dist/ui/avatar.js +40 -0
  801. package/dist/ui/avatar.js.map +7 -0
  802. package/dist/ui/badge.js +28 -0
  803. package/dist/ui/badge.js.map +7 -0
  804. package/dist/ui/button.js +48 -0
  805. package/dist/ui/button.js.map +7 -0
  806. package/dist/ui/card.js +90 -0
  807. package/dist/ui/card.js.map +7 -0
  808. package/dist/ui/checkbox.js +22 -0
  809. package/dist/ui/checkbox.js.map +7 -0
  810. package/dist/ui/collapsible.js +10 -0
  811. package/dist/ui/collapsible.js.map +7 -0
  812. package/dist/ui/command.js +103 -0
  813. package/dist/ui/command.js.map +7 -0
  814. package/dist/{chunk-YNNAJJ5Z.js → ui/dialog.js} +30 -68
  815. package/dist/ui/dialog.js.map +7 -0
  816. package/dist/{chunk-47CCGUWR.js → ui/dropdown-menu.js} +40 -45
  817. package/dist/ui/dropdown-menu.js.map +7 -0
  818. package/dist/ui/hover-card.js +36 -0
  819. package/dist/ui/hover-card.js.map +7 -0
  820. package/dist/ui/index.cjs +167 -154
  821. package/dist/ui/index.d.ts +2 -1
  822. package/dist/ui/index.js +290 -9
  823. package/dist/ui/index.js.map +7 -1
  824. package/dist/ui/input.js +65 -0
  825. package/dist/ui/input.js.map +7 -0
  826. package/dist/ui/label.js +16 -0
  827. package/dist/ui/label.js.map +7 -0
  828. package/dist/ui/mark-menu.js +300 -0
  829. package/dist/ui/mark-menu.js.map +7 -0
  830. package/dist/ui/popover.js +40 -0
  831. package/dist/ui/popover.js.map +7 -0
  832. package/dist/ui/portal-container.js +17 -0
  833. package/dist/ui/portal-container.js.map +7 -0
  834. package/dist/ui/progress.js +24 -0
  835. package/dist/ui/progress.js.map +7 -0
  836. package/dist/ui/radio-group.js +29 -0
  837. package/dist/ui/radio-group.js.map +7 -0
  838. package/dist/ui/scroll-area.js +39 -0
  839. package/dist/ui/scroll-area.js.map +7 -0
  840. package/dist/ui/select.js +130 -0
  841. package/dist/ui/select.js.map +7 -0
  842. package/dist/ui/separator.js +23 -0
  843. package/dist/ui/separator.js.map +7 -0
  844. package/dist/ui/slider.js +23 -0
  845. package/dist/ui/slider.js.map +7 -0
  846. package/dist/ui/switch.js +28 -0
  847. package/dist/ui/switch.js.map +7 -0
  848. package/dist/ui/table.js +75 -0
  849. package/dist/ui/table.js.map +7 -0
  850. package/dist/ui/tabs.js +48 -0
  851. package/dist/ui/tabs.js.map +7 -0
  852. package/dist/ui/textarea.js +63 -0
  853. package/dist/ui/textarea.js.map +7 -0
  854. package/dist/ui/toggle-group.js +43 -0
  855. package/dist/ui/toggle-group.js.map +7 -0
  856. package/dist/ui/toggle.js +40 -0
  857. package/dist/ui/toggle.js.map +7 -0
  858. package/dist/ui/tooltip.js +215 -0
  859. package/dist/ui/tooltip.js.map +7 -0
  860. package/dist/usage-metered.js +8 -0
  861. package/dist/usage-metered.js.map +7 -0
  862. package/dist/useArbi.js +16 -0
  863. package/dist/useArbi.js.map +7 -0
  864. package/dist/useInstallSkillPack.js +81 -0
  865. package/dist/useInstallSkillPack.js.map +7 -0
  866. package/dist/usermenu/UserMenu.js +188 -0
  867. package/dist/usermenu/UserMenu.js.map +7 -0
  868. package/dist/usermenu/index.js +5 -0
  869. package/dist/usermenu/index.js.map +7 -0
  870. package/dist/users/index.js +15 -0
  871. package/dist/users/index.js.map +7 -0
  872. package/dist/users/user-display.js +60 -0
  873. package/dist/users/user-display.js.map +7 -0
  874. package/dist/viewers/AudioViewer.js +23 -0
  875. package/dist/viewers/AudioViewer.js.map +7 -0
  876. package/dist/viewers/DocxViewer.js +81 -0
  877. package/dist/viewers/DocxViewer.js.map +7 -0
  878. package/dist/viewers/ImageViewer.js +31 -0
  879. package/dist/viewers/ImageViewer.js.map +7 -0
  880. package/dist/viewers/PdfViewer.cjs +17 -0
  881. package/dist/viewers/PdfViewer.cjs.map +1 -0
  882. package/dist/viewers/PdfViewer.d.ts +9 -0
  883. package/dist/viewers/PdfViewer.js +20 -0
  884. package/dist/viewers/PdfViewer.js.map +7 -0
  885. package/dist/viewers/PdfViewerImpl.js +384 -0
  886. package/dist/viewers/PdfViewerImpl.js.map +7 -0
  887. package/dist/viewers/VideoViewer.js +31 -0
  888. package/dist/viewers/VideoViewer.js.map +7 -0
  889. package/dist/viewers/XlsxViewer.js +102 -0
  890. package/dist/viewers/XlsxViewer.js.map +7 -0
  891. package/dist/viewers/index.cjs +79 -653
  892. package/dist/viewers/index.cjs.map +1 -1
  893. package/dist/viewers/index.d.ts +3 -1
  894. package/dist/viewers/index.js +60 -903
  895. package/dist/viewers/index.js.map +7 -1
  896. package/dist/viewers/page-scroll.js +59 -0
  897. package/dist/viewers/page-scroll.js.map +7 -0
  898. package/dist/viewers/pdf-viewer-constants.js +9 -0
  899. package/dist/viewers/pdf-viewer-constants.js.map +7 -0
  900. package/dist/{chunk-PTOP7OHG.js → viewers/pdfjs-polyfills.js} +5 -6
  901. package/dist/viewers/pdfjs-polyfills.js.map +7 -0
  902. package/dist/viewers/selection-runs.js +38 -0
  903. package/dist/viewers/selection-runs.js.map +7 -0
  904. package/dist/viewers/usePageIntersectionObserver.js +68 -0
  905. package/dist/viewers/usePageIntersectionObserver.js.map +7 -0
  906. package/dist/viewers/useProcessedChunks.js +58 -0
  907. package/dist/viewers/useProcessedChunks.js.map +7 -0
  908. package/dist/viewers/viewer-zoom.js +163 -0
  909. package/dist/viewers/viewer-zoom.js.map +7 -0
  910. package/dist/websocket/ArbiWebSocketProvider.js +207 -0
  911. package/dist/websocket/ArbiWebSocketProvider.js.map +7 -0
  912. package/dist/websocket/context.js +14 -0
  913. package/dist/websocket/context.js.map +7 -0
  914. package/dist/websocket/hooks.js +30 -0
  915. package/dist/websocket/hooks.js.map +7 -0
  916. package/dist/websocket/index.js +22 -0
  917. package/dist/websocket/index.js.map +7 -0
  918. package/dist/websocket/live-updates.js +38 -0
  919. package/dist/websocket/live-updates.js.map +7 -0
  920. package/dist/websocket/reconnect.js +13 -0
  921. package/dist/websocket/reconnect.js.map +7 -0
  922. package/dist/websocket/store.js +58 -0
  923. package/dist/websocket/store.js.map +7 -0
  924. package/dist/workforce.js +607 -0
  925. package/dist/workforce.js.map +7 -0
  926. package/dist/workspaces/access-request.js +35 -0
  927. package/dist/workspaces/access-request.js.map +7 -0
  928. package/dist/workspaces/archive.js +59 -0
  929. package/dist/workspaces/archive.js.map +7 -0
  930. package/dist/workspaces/current.js +20 -0
  931. package/dist/workspaces/current.js.map +7 -0
  932. package/dist/workspaces/delete-workspaces.js +15 -0
  933. package/dist/workspaces/delete-workspaces.js.map +7 -0
  934. package/dist/workspaces/export-archive.js +40 -0
  935. package/dist/workspaces/export-archive.js.map +7 -0
  936. package/dist/workspaces/index.js +99 -0
  937. package/dist/workspaces/index.js.map +7 -0
  938. package/dist/workspaces/settings.js +45 -0
  939. package/dist/workspaces/settings.js.map +7 -0
  940. package/dist/workspaces/shell-workspaces.js +49 -0
  941. package/dist/workspaces/shell-workspaces.js.map +7 -0
  942. package/dist/workspaces/switch.js +234 -0
  943. package/dist/workspaces/switch.js.map +7 -0
  944. package/dist/workspaces/transfer.js +170 -0
  945. package/dist/workspaces/transfer.js.map +7 -0
  946. package/dist/workspaces/useShellWorkspaces.js +86 -0
  947. package/dist/workspaces/useShellWorkspaces.js.map +7 -0
  948. package/dist/workspaces/workspace-users.js +65 -0
  949. package/dist/workspaces/workspace-users.js.map +7 -0
  950. package/package.json +12 -4
  951. package/dist/PdfViewer.d-bQH9yxFg.d.ts +0 -55
  952. package/dist/ProductionDialog.d-CpzslFn0.d.cts +0 -51
  953. package/dist/annotations/freeze/index.d.cts +0 -205
  954. package/dist/annotations/index.d.cts +0 -360
  955. package/dist/artifacts/index.d.cts +0 -476
  956. package/dist/artifacts/redline-core.d.cts +0 -39
  957. package/dist/bundle-YNOX7VIL.js +0 -5
  958. package/dist/bundle-YNOX7VIL.js.map +0 -1
  959. package/dist/bundle.d-BnCSbHy2.d.cts +0 -85
  960. package/dist/calls/livekit/index.d.cts +0 -280
  961. package/dist/chunk-47CCGUWR.js.map +0 -1
  962. package/dist/chunk-6H3O63TQ.js.map +0 -1
  963. package/dist/chunk-74N436VK.js.map +0 -1
  964. package/dist/chunk-APZZQZ6P.js +0 -147
  965. package/dist/chunk-APZZQZ6P.js.map +0 -1
  966. package/dist/chunk-BF5KW5ZI.js.map +0 -1
  967. package/dist/chunk-CPQ3CU4B.js +0 -246
  968. package/dist/chunk-CPQ3CU4B.js.map +0 -1
  969. package/dist/chunk-DPYBZDJB.js.map +0 -1
  970. package/dist/chunk-DQALOQPI.js +0 -2766
  971. package/dist/chunk-DQALOQPI.js.map +0 -1
  972. package/dist/chunk-FZJMA32S.js +0 -1011
  973. package/dist/chunk-FZJMA32S.js.map +0 -1
  974. package/dist/chunk-H5M7FXLB.js +0 -2057
  975. package/dist/chunk-H5M7FXLB.js.map +0 -1
  976. package/dist/chunk-HDCRPPBW.js +0 -75
  977. package/dist/chunk-HDCRPPBW.js.map +0 -1
  978. package/dist/chunk-NIKPG4PW.js +0 -1128
  979. package/dist/chunk-NIKPG4PW.js.map +0 -1
  980. package/dist/chunk-NNAJLY6B.js +0 -4974
  981. package/dist/chunk-NNAJLY6B.js.map +0 -1
  982. package/dist/chunk-OYPKKHXY.js +0 -559
  983. package/dist/chunk-OYPKKHXY.js.map +0 -1
  984. package/dist/chunk-P6WLV5UY.js +0 -644
  985. package/dist/chunk-P6WLV5UY.js.map +0 -1
  986. package/dist/chunk-PTOP7OHG.js.map +0 -1
  987. package/dist/chunk-SN5YV6FF.js +0 -11
  988. package/dist/chunk-SN5YV6FF.js.map +0 -1
  989. package/dist/chunk-T3USOSVN.js.map +0 -1
  990. package/dist/chunk-T4CLW3DN.js +0 -2560
  991. package/dist/chunk-T4CLW3DN.js.map +0 -1
  992. package/dist/chunk-UW2SGTI5.js.map +0 -1
  993. package/dist/chunk-VSCU7K4V.js.map +0 -1
  994. package/dist/chunk-WL2Y2T47.js.map +0 -1
  995. package/dist/chunk-WUTL62MC.js.map +0 -1
  996. package/dist/chunk-Y3MTRA7D.js +0 -97
  997. package/dist/chunk-Y3MTRA7D.js.map +0 -1
  998. package/dist/chunk-YNNAJJ5Z.js.map +0 -1
  999. package/dist/document-tools/core.d.cts +0 -883
  1000. package/dist/document-tools/index.d.cts +0 -90
  1001. package/dist/index.d-BMhTH98a.d.cts +0 -2035
  1002. package/dist/index.d-oR5FKZpJ.d.cts +0 -579
  1003. package/dist/index.d.cts +0 -15893
  1004. package/dist/model.d-CNtRWKVK.d.cts +0 -110
  1005. package/dist/query-keys.d-ChgpJLPF.d.cts +0 -337
  1006. package/dist/shell/index.d.cts +0 -6
  1007. package/dist/store.d-GADDvC7w.d.cts +0 -35
  1008. package/dist/stored-markdown.d-Bp18vrbr.d.cts +0 -125
  1009. package/dist/ui/index.d.cts +0 -25
  1010. package/dist/useAudioRecorder.d-B9rlMI_E.d.cts +0 -778
  1011. package/dist/viewers/index.d.cts +0 -260
@@ -1,2560 +0,0 @@
1
- import { parseAnnotation, parseLayer, emptyLayer, clampRect, isEffectiveRedaction } from './chunk-T3USOSVN.js';
2
- import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './chunk-YNNAJJ5Z.js';
3
- import { usePortalContainer, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-47CCGUWR.js';
4
- import { cn } from './chunk-SN5YV6FF.js';
5
- import { useState, useRef, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
6
- import { MessageSquare, Check, X, RotateCcw, Trash2, Send, Undo2, Redo2, EyeOff, GripVertical, ChevronUp, ChevronDown, MousePointer2, Highlighter, Square, Stamp, ScanText } from 'lucide-react';
7
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
-
9
- // src/annotations/state.ts
10
- var HISTORY_LIMIT = 200;
11
- function createHistory(layer) {
12
- return { present: layer, past: [], future: [] };
13
- }
14
- function reduceLayer(layer, action) {
15
- switch (action.type) {
16
- case "replaceAll":
17
- return action.layer;
18
- case "add": {
19
- const annotation = parseAnnotation(action.annotation);
20
- if (layer.annotations.some((a) => a.id === annotation.id)) {
21
- throw new Error(`annotation ${annotation.id} already exists`);
22
- }
23
- return {
24
- ...layer,
25
- annotations: [...layer.annotations, annotation],
26
- updatedAt: annotation.updatedAt
27
- };
28
- }
29
- case "addMany": {
30
- let next = layer;
31
- for (const annotation of action.annotations)
32
- next = reduceLayer(next, { type: "add", annotation });
33
- return next;
34
- }
35
- case "update": {
36
- const found = layer.annotations.find((a) => a.id === action.id);
37
- if (!found) return layer;
38
- const next = parseAnnotation({
39
- ...found,
40
- ...action.patch,
41
- id: found.id,
42
- kind: found.kind,
43
- page: found.page,
44
- createdAt: found.createdAt,
45
- updatedAt: action.now
46
- });
47
- return replace(layer, next, action.now);
48
- }
49
- case "remove": {
50
- if (!layer.annotations.some((a) => a.id === action.id)) return layer;
51
- return {
52
- ...layer,
53
- annotations: layer.annotations.filter((a) => a.id !== action.id),
54
- updatedAt: action.now
55
- };
56
- }
57
- case "setRedactionStatus": {
58
- const ids = new Set(action.ids);
59
- let changed = false;
60
- const annotations = layer.annotations.map((a) => {
61
- if (a.kind !== "redaction" || !ids.has(a.id) || a.status === action.status) return a;
62
- changed = true;
63
- const next = { ...a, status: action.status, updatedAt: action.now };
64
- delete next.reviewedBy;
65
- delete next.reviewedAt;
66
- if (action.status !== "pending" && action.by) {
67
- next.reviewedBy = action.by;
68
- next.reviewedAt = action.now;
69
- }
70
- return next;
71
- });
72
- return changed ? { ...layer, annotations, updatedAt: action.now } : layer;
73
- }
74
- case "reply": {
75
- const found = layer.annotations.find((a) => a.id === action.id);
76
- if (!found || found.kind !== "comment") return layer;
77
- const next = parseAnnotation({
78
- ...found,
79
- replies: [...found.replies, action.reply],
80
- updatedAt: action.now
81
- });
82
- return replace(layer, next, action.now);
83
- }
84
- case "resolve": {
85
- const found = layer.annotations.find((a) => a.id === action.id);
86
- if (!found || found.kind !== "comment" || found.resolved === action.resolved) return layer;
87
- return replace(
88
- layer,
89
- { ...found, resolved: action.resolved, updatedAt: action.now },
90
- action.now
91
- );
92
- }
93
- }
94
- }
95
- function replace(layer, next, now) {
96
- return {
97
- ...layer,
98
- annotations: layer.annotations.map((a) => a.id === next.id ? next : a),
99
- updatedAt: now
100
- };
101
- }
102
- function applyAction(history, action) {
103
- const present = reduceLayer(history.present, action);
104
- if (present === history.present) return history;
105
- const past = [...history.past, history.present];
106
- return {
107
- present,
108
- past: past.length > HISTORY_LIMIT ? past.slice(past.length - HISTORY_LIMIT) : past,
109
- future: []
110
- };
111
- }
112
- function undo(history) {
113
- const previous = history.past[history.past.length - 1];
114
- if (!previous) return history;
115
- return {
116
- present: previous,
117
- past: history.past.slice(0, -1),
118
- future: [history.present, ...history.future]
119
- };
120
- }
121
- function redo(history) {
122
- const [next, ...rest] = history.future;
123
- if (!next) return history;
124
- return { present: next, past: [...history.past, history.present], future: rest };
125
- }
126
- var canUndo = (h) => h.past.length > 0;
127
- var canRedo = (h) => h.future.length > 0;
128
- function annotationsOnPage(layer, page) {
129
- return layer.annotations.filter((a) => a.page === page);
130
- }
131
- function pendingRedactions(layer) {
132
- return layer.annotations.filter((a) => a.kind === "redaction" && a.status === "pending");
133
- }
134
-
135
- // src/annotations/store.ts
136
- var AnnotationStoreOfflineError = class extends Error {
137
- constructor(message = "You are offline") {
138
- super(message);
139
- this.name = "AnnotationStoreOfflineError";
140
- }
141
- };
142
- function createMemoryStore(now = () => (/* @__PURE__ */ new Date()).toISOString()) {
143
- const layers = /* @__PURE__ */ new Map();
144
- return {
145
- async load(documentId) {
146
- const raw = layers.get(documentId);
147
- return raw ? parseLayer(JSON.parse(raw)) : emptyLayer(documentId, now());
148
- },
149
- async save(layer) {
150
- layers.set(layer.documentId, JSON.stringify(parseLayer(layer)));
151
- }
152
- };
153
- }
154
- var STORAGE_PREFIX = "arbi:annotations:";
155
- function createLocalStorageStore(storage = safeLocalStorage(), now = () => (/* @__PURE__ */ new Date()).toISOString()) {
156
- return {
157
- async load(documentId) {
158
- try {
159
- const raw = storage?.getItem(STORAGE_PREFIX + documentId);
160
- if (raw) return parseLayer(JSON.parse(raw));
161
- } catch {
162
- }
163
- return emptyLayer(documentId, now());
164
- },
165
- async save(layer) {
166
- if (!storage) throw new Error("storage is not available");
167
- storage.setItem(STORAGE_PREFIX + layer.documentId, JSON.stringify(parseLayer(layer)));
168
- }
169
- };
170
- }
171
- function safeLocalStorage() {
172
- try {
173
- return typeof localStorage === "undefined" ? void 0 : localStorage;
174
- } catch {
175
- return void 0;
176
- }
177
- }
178
-
179
- // src/annotations/merge.ts
180
- var time = (iso) => {
181
- const t = Date.parse(iso);
182
- return Number.isNaN(t) ? 0 : t;
183
- };
184
- function mergeReplies(a, b) {
185
- const byId = /* @__PURE__ */ new Map();
186
- for (const r of [...a, ...b]) if (!byId.has(r.id)) byId.set(r.id, r);
187
- return [...byId.values()].sort((x, y) => time(x.createdAt) - time(y.createdAt));
188
- }
189
- function newer(mine, theirs) {
190
- const winner = time(theirs.updatedAt) > time(mine.updatedAt) ? theirs : mine;
191
- if (mine.kind === "comment" && theirs.kind === "comment" && winner.kind === "comment") {
192
- const replies = mergeReplies(mine.replies, theirs.replies);
193
- if (replies.length !== winner.replies.length) return { ...winner, replies };
194
- }
195
- return winner;
196
- }
197
- function mergeLayers({ base, mine, theirs, deleted }) {
198
- const baseById = new Map((base?.annotations ?? []).map((a) => [a.id, a]));
199
- const theirsById = new Map(theirs.annotations.map((a) => [a.id, a]));
200
- const mineIds = new Set(mine.annotations.map((a) => a.id));
201
- const out = [];
202
- for (const m of mine.annotations) {
203
- if (deleted?.has(m.id)) continue;
204
- const t = theirsById.get(m.id);
205
- if (t) {
206
- out.push(newer(m, t));
207
- continue;
208
- }
209
- const b = baseById.get(m.id);
210
- if (b && time(m.updatedAt) <= time(b.updatedAt)) continue;
211
- out.push(m);
212
- }
213
- for (const t of theirs.annotations) {
214
- if (mineIds.has(t.id) || deleted?.has(t.id)) continue;
215
- if (baseById.has(t.id)) continue;
216
- out.push(t);
217
- }
218
- const updatedAt = time(theirs.updatedAt) > time(mine.updatedAt) ? theirs.updatedAt : mine.updatedAt;
219
- return { ...mine, annotations: out, updatedAt };
220
- }
221
- function sameMarks(a, b) {
222
- if (a.annotations.length !== b.annotations.length) return false;
223
- const byId = new Map(a.annotations.map((m) => [m.id, m.updatedAt]));
224
- return b.annotations.every(
225
- (m) => byId.get(m.id) === m.updatedAt && (m.kind !== "comment" || a.annotations.find((x) => x.id === m.id).replies.length === m.replies.length)
226
- );
227
- }
228
-
229
- // src/annotations/redaction-log.ts
230
- var REDACTION_LOG_COLUMNS = ["page", "reason", "status", "approved_by", "time"];
231
- var STATUS = {
232
- approved: "redacted (approved)",
233
- pending: "redacted (not reviewed)",
234
- rejected: "not redacted (rejected)"
235
- };
236
- var top = (a) => Math.min(...a.rects.map((r) => r.y));
237
- var left = (a) => Math.min(...a.rects.map((r) => r.x));
238
- function redactionLogRows(layer) {
239
- return layer.annotations.filter((a) => a.kind === "redaction").sort((a, b) => a.page - b.page || top(a) - top(b) || left(a) - left(b)).map((a) => ({
240
- page: a.page,
241
- reason: a.reason,
242
- status: STATUS[a.status],
243
- approvedBy: a.status === "approved" ? a.reviewedBy ?? "" : "",
244
- time: a.reviewedAt ?? a.createdAt
245
- }));
246
- }
247
- var cell = (value) => {
248
- const text = String(value);
249
- return `"${(/^[=+\-@]/.test(text) ? `'${text}` : text).replace(/"/g, '""')}"`;
250
- };
251
- function redactionLogCsv(layer) {
252
- const rows = redactionLogRows(layer).map(
253
- (r) => [r.page, r.reason, r.status, r.approvedBy, r.time].map(cell).join(",")
254
- );
255
- return [REDACTION_LOG_COLUMNS.join(","), ...rows].join("\r\n") + "\r\n";
256
- }
257
-
258
- // src/annotations/geometry.ts
259
- var MIN_MARK_FRACTION = 4e-3;
260
- function toNorm(r, page) {
261
- if (!(page.width > 0) || !(page.height > 0)) throw new RangeError("page size must be positive");
262
- const x1 = Math.min(r.x, r.x + r.width);
263
- const y1 = Math.min(r.y, r.y + r.height);
264
- const x2 = Math.max(r.x, r.x + r.width);
265
- const y2 = Math.max(r.y, r.y + r.height);
266
- const cx1 = Math.min(Math.max(x1, 0), page.width);
267
- const cy1 = Math.min(Math.max(y1, 0), page.height);
268
- const cx2 = Math.min(Math.max(x2, 0), page.width);
269
- const cy2 = Math.min(Math.max(y2, 0), page.height);
270
- return clampRect({
271
- x: cx1 / page.width,
272
- y: cy1 / page.height,
273
- w: (cx2 - cx1) / page.width,
274
- h: (cy2 - cy1) / page.height
275
- });
276
- }
277
- function toPixels(r, page) {
278
- return {
279
- x: r.x * page.width,
280
- y: r.y * page.height,
281
- width: r.w * page.width,
282
- height: r.h * page.height
283
- };
284
- }
285
- function dragToNorm(a, b, page) {
286
- return toNorm({ x: a.x, y: a.y, width: b.x - a.x, height: b.y - a.y }, page);
287
- }
288
- function isTooSmall(r) {
289
- return r.w < MIN_MARK_FRACTION || r.h < MIN_MARK_FRACTION;
290
- }
291
- function containsPoint(r, x, y) {
292
- return x >= r.x && x <= r.x + r.w && y >= r.y && y <= r.y + r.h;
293
- }
294
- var EPS = 1e-9;
295
- function intersects(a, b) {
296
- return a.x + EPS < b.x + b.w && b.x + EPS < a.x + a.w && a.y + EPS < b.y + b.h && b.y + EPS < a.y + a.h;
297
- }
298
- function mergeLineRects(input, gap = 2) {
299
- const rects = input.filter((r) => r.width > 0 && r.height > 0).map((r) => ({ ...r })).sort((a, b) => a.y - b.y || a.x - b.x);
300
- const lines = [];
301
- for (const r of rects) {
302
- const mid = r.y + r.height / 2;
303
- const line = lines.find((l) => {
304
- const ref = l[0];
305
- return mid >= ref.y && mid <= ref.y + ref.height;
306
- });
307
- if (line) line.push(r);
308
- else lines.push([r]);
309
- }
310
- const out = [];
311
- for (const line of lines) {
312
- line.sort((a, b) => a.x - b.x);
313
- let cur = { ...line[0] };
314
- for (const r of line.slice(1)) {
315
- if (r.x <= cur.x + cur.width + gap) {
316
- const right = Math.max(cur.x + cur.width, r.x + r.width);
317
- const top2 = Math.min(cur.y, r.y);
318
- const bottom = Math.max(cur.y + cur.height, r.y + r.height);
319
- cur = { x: cur.x, y: top2, width: right - cur.x, height: bottom - top2 };
320
- } else {
321
- out.push(cur);
322
- cur = { ...r };
323
- }
324
- }
325
- out.push(cur);
326
- }
327
- return out.sort((a, b) => a.y - b.y || a.x - b.x);
328
- }
329
-
330
- // src/annotations/controller.ts
331
- var DRAW_TOOLS = ["box", "comment", "stamp", "redact-area"];
332
- var TEXT_TOOLS = ["highlight", "redact-text"];
333
- var DEFAULT_SETTINGS = {
334
- colors: { highlight: "#ffe066", box: "#e03131", stamp: "#c92a2a" },
335
- stampLabel: "[REDACTED]",
336
- stampImage: null,
337
- redactionReason: "Privileged",
338
- strokeWidth: 2
339
- };
340
- var HIGHLIGHT_COLORS = ["#ffe066", "#8ce99a", "#74c0fc", "#ffa8a8", "#eebefa"];
341
- var MARK_COLORS = ["#e03131", "#1c7ed6", "#2f9e44", "#f08c00", "#000000"];
342
- var STAMP_PRESETS = [
343
- "[REDACTED]",
344
- "CONFIDENTIAL",
345
- "DRAFT",
346
- "APPROVED",
347
- "FILED",
348
- "PRIVILEGED",
349
- "COPY"
350
- ];
351
- var REDACTION_REASONS = [
352
- "Privileged",
353
- "Confidential",
354
- "Personal data",
355
- "Commercial",
356
- "Irrelevant"
357
- ];
358
- function layerStatusText(controller) {
359
- if (controller.status === "error") return "Could not be loaded";
360
- if (controller.readOnly) return "View only";
361
- if (controller.offline) {
362
- return controller.dirty ? "Offline \u2014 will save when back online" : "Offline";
363
- }
364
- if (controller.error) return "Not saved \u2014 retrying";
365
- if (controller.saving) return "Saving\u2026";
366
- if (controller.dirty) return "Unsaved changes";
367
- return "Saved";
368
- }
369
- var AUTOSAVE_MS = 600;
370
- var RETRY_MS = 1e4;
371
- var defaultNow = () => (/* @__PURE__ */ new Date()).toISOString();
372
- var defaultId = () => globalThis.crypto.randomUUID();
373
- function rebaseHistory(history, sent, remote) {
374
- const onto = (layer) => layer === sent ? remote : mergeLayers({ base: sent, mine: layer, theirs: remote });
375
- return {
376
- present: onto(history.present),
377
- past: history.past.map(onto),
378
- future: history.future.map(onto)
379
- };
380
- }
381
- function useAnnotationLayer({
382
- documentId,
383
- store,
384
- author,
385
- autosaveMs = AUTOSAVE_MS,
386
- readOnly: readOnlyProp = false,
387
- online = true,
388
- pullMs = 0,
389
- now = defaultNow,
390
- makeId = defaultId
391
- }) {
392
- const [history, setHistory] = useState(
393
- () => createHistory(emptyLayer(documentId, now()))
394
- );
395
- const [savedLayer, setSavedLayer] = useState(null);
396
- const [status, setStatus] = useState("loading");
397
- const [error, setError] = useState(null);
398
- const [saving, setSaving] = useState(false);
399
- const [offlineFailure, setOfflineFailure] = useState(false);
400
- const [storeReadOnly, setStoreReadOnly] = useState(false);
401
- const [tool, setToolState] = useState("select");
402
- const [settings, setSettingsState] = useState(DEFAULT_SETTINGS);
403
- const [selectedId, setSelectedId] = useState(null);
404
- const readOnly = readOnlyProp || storeReadOnly;
405
- const historyRef = useRef(history);
406
- const savedRef = useRef(null);
407
- const timerRef = useRef(void 0);
408
- const retryRef = useRef(void 0);
409
- const savingRef = useRef(false);
410
- const docRef = useRef(documentId);
411
- const storeRef = useRef(store);
412
- storeRef.current = store;
413
- const nowRef = useRef(now);
414
- nowRef.current = now;
415
- const idRef = useRef(makeId);
416
- idRef.current = makeId;
417
- const readOnlyRef = useRef(readOnly);
418
- readOnlyRef.current = readOnly;
419
- const onlineRef = useRef(online);
420
- onlineRef.current = online;
421
- const autosaveMsRef = useRef(autosaveMs);
422
- autosaveMsRef.current = autosaveMs;
423
- const commit = useCallback((next) => {
424
- historyRef.current = next;
425
- setHistory(next);
426
- }, []);
427
- const adoptRemote = useCallback(
428
- (sent, remote) => {
429
- commit(rebaseHistory(historyRef.current, sent, remote));
430
- savedRef.current = remote;
431
- setSavedLayer(remote);
432
- },
433
- [commit]
434
- );
435
- useEffect(() => {
436
- docRef.current = documentId;
437
- let cancelled = false;
438
- setStatus("loading");
439
- setError(null);
440
- setSelectedId(null);
441
- setSavedLayer(null);
442
- setStoreReadOnly(false);
443
- savedRef.current = null;
444
- commit(createHistory(emptyLayer(documentId, nowRef.current())));
445
- storeRef.current.load(documentId).then((layer) => {
446
- if (cancelled) return;
447
- savedRef.current = layer;
448
- setSavedLayer(layer);
449
- setStoreReadOnly(storeRef.current.canEdit?.(documentId) === false);
450
- commit(createHistory(layer));
451
- setStatus("ready");
452
- }).catch((e) => {
453
- if (cancelled) return;
454
- setError(e instanceof Error ? e.message : "The annotations could not be loaded");
455
- setStatus("error");
456
- });
457
- return () => {
458
- cancelled = true;
459
- clearTimeout(timerRef.current);
460
- clearTimeout(retryRef.current);
461
- const layer = historyRef.current.present;
462
- if (savedRef.current !== null && layer !== savedRef.current && layer.documentId === documentId && !readOnlyRef.current) {
463
- storeRef.current.save(layer).catch((e) => console.error("Annotations could not be saved", e));
464
- }
465
- };
466
- }, [documentId, commit]);
467
- const save = useCallback(async () => {
468
- clearTimeout(timerRef.current);
469
- clearTimeout(retryRef.current);
470
- const layer = historyRef.current.present;
471
- if (layer === savedRef.current || savedRef.current === null) return;
472
- if (readOnlyRef.current || savingRef.current) return;
473
- if (!onlineRef.current) return;
474
- savingRef.current = true;
475
- setSaving(true);
476
- let failed = false;
477
- try {
478
- const stored = await storeRef.current.save(layer);
479
- if (layer.documentId === docRef.current) {
480
- setError(null);
481
- setOfflineFailure(false);
482
- if (stored && stored !== layer) {
483
- adoptRemote(layer, stored);
484
- } else {
485
- savedRef.current = layer;
486
- setSavedLayer(layer);
487
- }
488
- }
489
- } catch (e) {
490
- failed = true;
491
- if (e instanceof AnnotationStoreOfflineError) {
492
- setOfflineFailure(true);
493
- } else {
494
- setError(e instanceof Error ? e.message : "The annotations could not be saved");
495
- }
496
- retryRef.current = setTimeout(() => void saveRef.current(), RETRY_MS);
497
- } finally {
498
- savingRef.current = false;
499
- setSaving(false);
500
- if (!failed && historyRef.current.present !== savedRef.current) {
501
- timerRef.current = setTimeout(() => void saveRef.current(), autosaveMsRef.current);
502
- }
503
- }
504
- }, [adoptRemote]);
505
- const saveRef = useRef(save);
506
- saveRef.current = save;
507
- const present = history.present;
508
- const dirty = status === "ready" && present !== savedLayer;
509
- useEffect(() => {
510
- if (!dirty || !online || readOnly) return;
511
- timerRef.current = setTimeout(() => void save(), autosaveMs);
512
- return () => clearTimeout(timerRef.current);
513
- }, [dirty, present, autosaveMs, save, online, readOnly]);
514
- useEffect(() => {
515
- if (online) setOfflineFailure(false);
516
- if (online && savedRef.current !== null && historyRef.current.present !== savedRef.current) {
517
- void save();
518
- }
519
- }, [online, save]);
520
- const pull = useCallback(async () => {
521
- const s = storeRef.current;
522
- const base = savedRef.current;
523
- if (!s.pull || !base || savingRef.current || !onlineRef.current) return;
524
- if (historyRef.current.present !== base) return;
525
- try {
526
- const remote = await s.pull(docRef.current);
527
- if (!remote || remote.documentId !== docRef.current || savedRef.current !== base) return;
528
- adoptRemote(base, remote);
529
- } catch {
530
- }
531
- }, [adoptRemote]);
532
- useEffect(() => {
533
- if (!pullMs || status !== "ready") return;
534
- const timer = setInterval(() => void pull(), pullMs);
535
- const onFocus = () => void pull();
536
- window.addEventListener("focus", onFocus);
537
- return () => {
538
- clearInterval(timer);
539
- window.removeEventListener("focus", onFocus);
540
- };
541
- }, [pullMs, status, pull]);
542
- useEffect(() => {
543
- const flush = () => void save();
544
- const onVisibility = () => {
545
- if (document.visibilityState === "hidden") flush();
546
- };
547
- window.addEventListener("pagehide", flush);
548
- document.addEventListener("visibilitychange", onVisibility);
549
- return () => {
550
- window.removeEventListener("pagehide", flush);
551
- document.removeEventListener("visibilitychange", onVisibility);
552
- };
553
- }, [save]);
554
- const dispatch = useCallback(
555
- (action) => {
556
- if (readOnlyRef.current) return false;
557
- try {
558
- commit(applyAction(historyRef.current, action));
559
- setError(null);
560
- return true;
561
- } catch (e) {
562
- setError(e instanceof Error ? e.message : "The change was rejected");
563
- return false;
564
- }
565
- },
566
- [commit]
567
- );
568
- const stamp = useCallback(
569
- (mark) => {
570
- const t = nowRef.current();
571
- return { ...mark, id: idRef.current(), author, createdAt: t, updatedAt: t };
572
- },
573
- [author]
574
- );
575
- const offline = !online || offlineFailure;
576
- const controller = useMemo(() => {
577
- const exists = (id) => id !== null && present.annotations.some((a) => a.id === id) ? id : null;
578
- return {
579
- layer: present,
580
- status,
581
- error,
582
- saving,
583
- dirty,
584
- offline,
585
- readOnly,
586
- author,
587
- tool: readOnly ? "select" : tool,
588
- setTool: (next) => {
589
- if (readOnly && next !== "select") return;
590
- setToolState(next);
591
- if (next !== "select") setSelectedId(null);
592
- },
593
- settings,
594
- setSettings: (patch) => setSettingsState((s) => ({ ...s, ...patch, colors: { ...s.colors, ...patch.colors } })),
595
- selectedId: exists(selectedId),
596
- select: setSelectedId,
597
- add: (mark) => {
598
- const annotation = stamp(mark);
599
- return dispatch({ type: "add", annotation }) ? annotation.id : null;
600
- },
601
- addMany: (marks) => {
602
- const annotations = marks.map(stamp);
603
- return dispatch({ type: "addMany", annotations }) ? annotations.map((a) => a.id) : [];
604
- },
605
- update: (id, patch) => void dispatch({ type: "update", id, patch, now: nowRef.current() }),
606
- remove: (id) => void dispatch({ type: "remove", id, now: nowRef.current() }),
607
- setRedactionStatus: (ids, next) => void dispatch({
608
- type: "setRedactionStatus",
609
- ids,
610
- status: next,
611
- now: nowRef.current(),
612
- by: author
613
- }),
614
- reply: (id, body) => {
615
- const t = nowRef.current();
616
- void dispatch({
617
- type: "reply",
618
- id,
619
- reply: { id: idRef.current(), author, createdAt: t, body },
620
- now: t
621
- });
622
- },
623
- resolve: (id, resolved) => void dispatch({ type: "resolve", id, resolved, now: nowRef.current() }),
624
- undo: () => {
625
- if (!readOnly) commit(undo(historyRef.current));
626
- },
627
- redo: () => {
628
- if (!readOnly) commit(redo(historyRef.current));
629
- },
630
- canUndo: !readOnly && canUndo(history),
631
- canRedo: !readOnly && canRedo(history),
632
- flush: save
633
- };
634
- }, [
635
- present,
636
- history,
637
- status,
638
- error,
639
- saving,
640
- dirty,
641
- offline,
642
- readOnly,
643
- author,
644
- tool,
645
- settings,
646
- selectedId,
647
- stamp,
648
- dispatch,
649
- commit,
650
- save
651
- ]);
652
- return controller;
653
- }
654
-
655
- // src/annotations/selection-marks.ts
656
- var MIN_RECT_PX = 1;
657
- function selectionToPageMarks(pages) {
658
- const out = [];
659
- for (const p of pages) {
660
- if (!(p.box.width > 0) || !(p.box.height > 0)) continue;
661
- const local = p.rects.filter((r) => r.width >= MIN_RECT_PX && r.height >= MIN_RECT_PX).map((r) => ({ x: r.x - p.box.x, y: r.y - p.box.y, width: r.width, height: r.height })).filter(
662
- (r) => r.x + r.width > 0 && r.y + r.height > 0 && r.x < p.box.width && r.y < p.box.height
663
- );
664
- const lines = mergeLineRects(local);
665
- if (lines.length === 0) continue;
666
- out.push({
667
- page: p.page,
668
- rects: lines.map((r) => toNorm(r, { width: p.box.width, height: p.box.height })),
669
- text: p.text.replace(/\s+/g, " ").trim()
670
- });
671
- }
672
- return out;
673
- }
674
- var PAGE_ATTRIBUTE = "data-annotation-page";
675
- var ownerDocument = (node) => node.ownerDocument ?? document;
676
- var toPixelRect = (r) => ({
677
- x: r.left,
678
- y: r.top,
679
- width: r.width,
680
- height: r.height
681
- });
682
- function clipRange(range, container) {
683
- if (!range.intersectsNode(container)) return null;
684
- const bounds = ownerDocument(container).createRange();
685
- bounds.selectNodeContents(container);
686
- const clipped = range.cloneRange();
687
- if (clipped.compareBoundaryPoints(Range.START_TO_START, bounds) < 0) {
688
- clipped.setStart(bounds.startContainer, bounds.startOffset);
689
- }
690
- if (clipped.compareBoundaryPoints(Range.END_TO_END, bounds) > 0) {
691
- clipped.setEnd(bounds.endContainer, bounds.endOffset);
692
- }
693
- return clipped;
694
- }
695
- function textClientRects(range, container) {
696
- const doc = ownerDocument(container);
697
- const walker = doc.createTreeWalker(container, NodeFilter.SHOW_TEXT);
698
- const rects = [];
699
- for (let node = walker.nextNode(); node; node = walker.nextNode()) {
700
- if (!node.textContent?.trim() || !range.intersectsNode(node)) continue;
701
- const part = doc.createRange();
702
- part.selectNodeContents(node);
703
- if (node === range.startContainer) part.setStart(node, range.startOffset);
704
- if (node === range.endContainer) part.setEnd(node, range.endOffset);
705
- rects.push(...Array.from(part.getClientRects()));
706
- }
707
- return rects;
708
- }
709
- function firstTextAt(container, offset) {
710
- if (container.nodeType === Node.TEXT_NODE) return { node: container, offset };
711
- const child = container.childNodes[offset];
712
- if (!child) return null;
713
- if (child.nodeType === Node.TEXT_NODE) return { node: child, offset: 0 };
714
- const first = ownerDocument(child).createTreeWalker(child, NodeFilter.SHOW_TEXT).nextNode();
715
- return first ? { node: first, offset: 0 } : null;
716
- }
717
- function extendFocusToPointer(selection, point) {
718
- if (selection.rangeCount === 0 || selection.isCollapsed) return;
719
- const range = selection.getRangeAt(0);
720
- if (selection.focusNode !== range.endContainer || selection.focusOffset !== range.endOffset)
721
- return;
722
- const start = firstTextAt(range.endContainer, range.endOffset);
723
- if (!start) return;
724
- const doc = ownerDocument(start.node);
725
- const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
726
- walker.currentNode = start.node;
727
- const glyph = doc.createRange();
728
- let end = null;
729
- let node = start.node;
730
- let offset = start.offset;
731
- let passed = false;
732
- while (node && !passed) {
733
- const text = node.textContent ?? "";
734
- for (let i = offset; i < text.length && !passed; i++) {
735
- glyph.setStart(node, i);
736
- glyph.setEnd(node, i + 1);
737
- const r = glyph.getBoundingClientRect();
738
- if (r.height === 0) continue;
739
- const mid = r.top + r.height / 2;
740
- if (mid > point.y + r.height / 2) passed = true;
741
- else if (Math.abs(mid - point.y) > r.height / 2) continue;
742
- else if (r.right > point.x + 0.5) passed = true;
743
- else end = { node, offset: i + 1 };
744
- }
745
- node = walker.nextNode();
746
- offset = 0;
747
- }
748
- if (end) selection.extend(end.node, end.offset);
749
- }
750
- function readSelection(selection, root = document) {
751
- if (selection.rangeCount === 0 || selection.isCollapsed) return [];
752
- const range = selection.getRangeAt(0);
753
- const pages = [];
754
- root.querySelectorAll(`[${PAGE_ATTRIBUTE}]`).forEach((overlay) => {
755
- const page = Number(overlay.getAttribute(PAGE_ATTRIBUTE));
756
- const container = overlay.parentElement;
757
- if (!container || !Number.isInteger(page)) return;
758
- const clipped = clipRange(range, container);
759
- if (!clipped) return;
760
- pages.push({
761
- page,
762
- box: toPixelRect(overlay.getBoundingClientRect()),
763
- rects: textClientRects(clipped, container).map(toPixelRect),
764
- text: clipped.toString()
765
- });
766
- });
767
- return pages;
768
- }
769
-
770
- // src/annotations/useTextSelectionMarks.ts
771
- var PAGE_SELECTOR = "[data-page-number]";
772
- var TOUCH_SETTLE_MS = 700;
773
- var MOUSE_SETTLE_MS = 80;
774
- var STABLE_CHECKS = 3;
775
- var MAX_SETTLE_ROUNDS = 12;
776
- function useTextSelectionMarks(controller) {
777
- const latest = useRef(controller);
778
- latest.current = controller;
779
- const pagesDoc = usePortalContainer()?.ownerDocument ?? document;
780
- useEffect(() => {
781
- let startedOnPage = false;
782
- let touchSelecting = false;
783
- let settleTimer;
784
- const settleTimers = /* @__PURE__ */ new Set();
785
- const markSelection = () => {
786
- const c = latest.current;
787
- const selection = pagesDoc.getSelection();
788
- if (!selection || !TEXT_TOOLS.includes(c.tool)) return false;
789
- const pages = selectionToPageMarks(readSelection(selection, pagesDoc));
790
- if (pages.length === 0) return false;
791
- const marks = pages.map(
792
- (p) => c.tool === "highlight" ? {
793
- kind: "highlight",
794
- page: p.page,
795
- rects: p.rects,
796
- color: c.settings.colors.highlight,
797
- text: p.text
798
- } : {
799
- kind: "redaction",
800
- page: p.page,
801
- rects: p.rects,
802
- reason: c.settings.redactionReason,
803
- text: p.text,
804
- status: "pending"
805
- }
806
- );
807
- if (c.addMany(marks).length === 0) return false;
808
- selection.removeAllRanges();
809
- return true;
810
- };
811
- const onDown = (e) => {
812
- startedOnPage = e.target instanceof Element && e.target.closest(PAGE_SELECTOR) !== null;
813
- touchSelecting = startedOnPage && e.pointerType === "touch";
814
- };
815
- const onUp = (e) => {
816
- if (!startedOnPage || !TEXT_TOOLS.includes(latest.current.tool)) return;
817
- startedOnPage = false;
818
- const selection = pagesDoc.getSelection();
819
- if (selection && e.pointerType === "mouse") {
820
- extendFocusToPointer(selection, { x: e.clientX, y: e.clientY });
821
- }
822
- let last = selection?.toString() ?? "";
823
- let stable = 0;
824
- let rounds = 0;
825
- const check = () => {
826
- const now = pagesDoc.getSelection()?.toString() ?? "";
827
- if (now === last) stable++;
828
- else {
829
- last = now;
830
- stable = 0;
831
- }
832
- if (stable >= STABLE_CHECKS || ++rounds >= MAX_SETTLE_ROUNDS) {
833
- if (markSelection()) touchSelecting = false;
834
- return;
835
- }
836
- settleTimers.add(setTimeout(check, MOUSE_SETTLE_MS));
837
- };
838
- settleTimers.add(setTimeout(check, MOUSE_SETTLE_MS));
839
- };
840
- const onSelectionChange = () => {
841
- if (!touchSelecting || !TEXT_TOOLS.includes(latest.current.tool)) return;
842
- clearTimeout(settleTimer);
843
- settleTimer = setTimeout(() => {
844
- if (markSelection()) touchSelecting = false;
845
- }, TOUCH_SETTLE_MS);
846
- };
847
- pagesDoc.addEventListener("pointerdown", onDown, true);
848
- pagesDoc.addEventListener("pointerup", onUp, true);
849
- pagesDoc.addEventListener("selectionchange", onSelectionChange);
850
- return () => {
851
- clearTimeout(settleTimer);
852
- settleTimers.forEach(clearTimeout);
853
- pagesDoc.removeEventListener("pointerdown", onDown, true);
854
- pagesDoc.removeEventListener("pointerup", onUp, true);
855
- pagesDoc.removeEventListener("selectionchange", onSelectionChange);
856
- };
857
- }, [pagesDoc]);
858
- }
859
-
860
- // src/annotations/overlay-geometry.ts
861
- var MIN_MARK = 0.01;
862
- function singleRect(a) {
863
- if (a.kind === "box" || a.kind === "stamp" || a.kind === "comment") return a.rect;
864
- if (a.kind === "redaction" && a.rects.length === 1) return a.rects[0];
865
- return null;
866
- }
867
- var patchForRect = (a, rect) => a.kind === "redaction" ? { rects: [rect] } : { rect };
868
- function dragRect(origin, mode, dx, dy) {
869
- if (mode === "move") {
870
- return {
871
- ...origin,
872
- x: Math.min(Math.max(origin.x + dx, 0), 1 - origin.w),
873
- y: Math.min(Math.max(origin.y + dy, 0), 1 - origin.h)
874
- };
875
- }
876
- let left2 = origin.x;
877
- let right = origin.x + origin.w;
878
- let top2 = origin.y;
879
- let bottom = origin.y + origin.h;
880
- if (mode.includes("w")) left2 += dx;
881
- else right += dx;
882
- if (mode.includes("n")) top2 += dy;
883
- else bottom += dy;
884
- const x1 = Math.min(Math.max(Math.min(left2, right), 0), 1);
885
- const x2 = Math.min(Math.max(Math.max(left2, right), 0), 1);
886
- const y1 = Math.min(Math.max(Math.min(top2, bottom), 0), 1);
887
- const y2 = Math.min(Math.max(Math.max(top2, bottom), 0), 1);
888
- return clampRect({
889
- x: x1,
890
- y: y1,
891
- w: Math.max(x2 - x1, MIN_MARK),
892
- h: Math.max(y2 - y1, MIN_MARK)
893
- });
894
- }
895
- var FALLBACK_PAGE_WIDTH_PT = 612;
896
- var COMMENT_ICON_PX = 24;
897
- var DEFAULT_STAMP = { w: 0.32, h: 0.06 };
898
- var MOVE_THRESHOLD_PX = 3;
899
- function useElementSize(ref) {
900
- const [size, setSize] = useState({ width: 0, height: 0 });
901
- useLayoutEffect(() => {
902
- const el = ref.current;
903
- if (!el) return;
904
- const measure = () => {
905
- const r = el.getBoundingClientRect();
906
- setSize(
907
- (prev) => prev.width === r.width && prev.height === r.height ? prev : { width: r.width, height: r.height }
908
- );
909
- };
910
- measure();
911
- const observer = new ResizeObserver(measure);
912
- observer.observe(el);
913
- return () => observer.disconnect();
914
- }, [ref]);
915
- return size;
916
- }
917
- function useHasTextLayer(ref) {
918
- const [hasText, setHasText] = useState(false);
919
- useLayoutEffect(() => {
920
- const container = ref.current?.parentElement;
921
- if (!container) return;
922
- const check = () => setHasText(container.querySelector(".textLayer span") !== null);
923
- check();
924
- const observer = new MutationObserver(check);
925
- observer.observe(container, { childList: true, subtree: true });
926
- return () => observer.disconnect();
927
- }, [ref]);
928
- return hasText;
929
- }
930
- var pct = (n) => `${n * 100}%`;
931
- var rectStyle = (r) => ({
932
- left: pct(r.x),
933
- top: pct(r.y),
934
- width: pct(r.w),
935
- height: pct(r.h)
936
- });
937
- function AnnotationPageOverlay({
938
- controller,
939
- pageNumber,
940
- pageWidthPt
941
- }) {
942
- const rootRef = useRef(null);
943
- const size = useElementSize(rootRef);
944
- const pxPerPt = size.width / (pageWidthPt ?? FALLBACK_PAGE_WIDTH_PT);
945
- const { tool, selectedId, settings } = controller;
946
- const [draft, setDraft] = useState(null);
947
- const [drag, setDrag] = useState(null);
948
- const [openComment, setOpenComment] = useState(null);
949
- const marks = controller.layer.annotations.filter((a) => a.page === pageNumber);
950
- const hasText = useHasTextLayer(rootRef);
951
- const readOnly = controller.readOnly;
952
- const drawing = !readOnly && (DRAW_TOOLS.includes(tool) || TEXT_TOOLS.includes(tool) && !hasText);
953
- useEffect(() => {
954
- if (openComment && selectedId !== openComment) setOpenComment(null);
955
- }, [selectedId, openComment]);
956
- const local = useCallback((e) => {
957
- const r = rootRef.current.getBoundingClientRect();
958
- return { x: e.clientX - r.left, y: e.clientY - r.top };
959
- }, []);
960
- const pageSize = () => {
961
- const r = rootRef.current.getBoundingClientRect();
962
- return { width: r.width, height: r.height };
963
- };
964
- const finishDraft = useCallback(
965
- (a, b) => {
966
- const page = pageSize();
967
- const rect = dragToNorm(a, b, page);
968
- if (tool === "box") {
969
- if (isTooSmall(rect)) return;
970
- controller.add({
971
- kind: "box",
972
- page: pageNumber,
973
- rect,
974
- color: settings.colors.box,
975
- strokeWidth: settings.strokeWidth
976
- });
977
- } else if (tool === "highlight") {
978
- if (isTooSmall(rect)) return;
979
- controller.add({
980
- kind: "highlight",
981
- page: pageNumber,
982
- rects: [rect],
983
- color: settings.colors.highlight
984
- });
985
- } else if (tool === "redact-area" || tool === "redact-text") {
986
- if (isTooSmall(rect)) return;
987
- controller.add({
988
- kind: "redaction",
989
- page: pageNumber,
990
- rects: [rect],
991
- reason: settings.redactionReason,
992
- status: "pending"
993
- });
994
- } else if (tool === "stamp" && settings.stampImage) {
995
- const { image, label } = settings.stampImage;
996
- const size2 = pngPixelSize(image);
997
- const h = 0.06;
998
- const w = Math.min(
999
- 0.5,
1000
- h * page.height * (size2.width / Math.max(1, size2.height)) / page.width
1001
- );
1002
- const id = controller.add({
1003
- kind: "stamp",
1004
- page: pageNumber,
1005
- rect: clampRect({ x: a.x / page.width - w / 2, y: a.y / page.height - h / 2, w, h }),
1006
- label,
1007
- color: "#0d1a59",
1008
- image
1009
- });
1010
- controller.setSettings({ stampImage: null });
1011
- controller.setTool("select");
1012
- if (id) controller.select(id);
1013
- } else if (tool === "stamp") {
1014
- const placed = isTooSmall(rect) ? clampRect({
1015
- x: a.x / page.width - DEFAULT_STAMP.w / 2,
1016
- y: a.y / page.height - DEFAULT_STAMP.h / 2,
1017
- ...DEFAULT_STAMP
1018
- }) : rect;
1019
- controller.add({
1020
- kind: "stamp",
1021
- page: pageNumber,
1022
- rect: placed,
1023
- label: settings.stampLabel,
1024
- color: settings.colors.stamp
1025
- });
1026
- } else if (tool === "comment") {
1027
- const anchor = clampRect({
1028
- x: a.x / page.width,
1029
- y: a.y / page.height,
1030
- w: COMMENT_ICON_PX / page.width,
1031
- h: COMMENT_ICON_PX / page.height
1032
- });
1033
- const id = controller.add({
1034
- kind: "comment",
1035
- page: pageNumber,
1036
- rect: anchor,
1037
- body: "",
1038
- replies: [],
1039
- resolved: false
1040
- });
1041
- if (id) {
1042
- controller.setTool("select");
1043
- controller.select(id);
1044
- setOpenComment(id);
1045
- }
1046
- }
1047
- },
1048
- [controller, tool, settings, pageNumber]
1049
- );
1050
- const onRootPointerDown = (e) => {
1051
- if (!drawing || e.button !== 0 || e.target !== e.currentTarget) return;
1052
- e.currentTarget.setPointerCapture(e.pointerId);
1053
- const p = local(e);
1054
- setDraft({ a: p, b: p });
1055
- };
1056
- const onRootPointerMove = (e) => {
1057
- if (draft) setDraft({ a: draft.a, b: local(e) });
1058
- };
1059
- const onRootPointerUp = (e) => {
1060
- if (!draft) return;
1061
- const b = local(e);
1062
- const a = draft.a;
1063
- setDraft(null);
1064
- finishDraft(a, b);
1065
- };
1066
- const beginDrag = (e, a, mode) => {
1067
- const origin = singleRect(a);
1068
- if (!origin || e.button !== 0 || readOnly) return;
1069
- e.stopPropagation();
1070
- e.currentTarget.setPointerCapture(e.pointerId);
1071
- setDrag({
1072
- id: a.id,
1073
- mode,
1074
- startX: e.clientX,
1075
- startY: e.clientY,
1076
- origin,
1077
- rect: origin,
1078
- moved: false
1079
- });
1080
- };
1081
- const moveDrag = (e) => {
1082
- if (!drag) return;
1083
- const page = pageSize();
1084
- const dxPx = e.clientX - drag.startX;
1085
- const dyPx = e.clientY - drag.startY;
1086
- const moved = drag.moved || Math.hypot(dxPx, dyPx) > MOVE_THRESHOLD_PX;
1087
- if (!moved) return;
1088
- setDrag({
1089
- ...drag,
1090
- moved: true,
1091
- rect: dragRect(drag.origin, drag.mode, dxPx / page.width, dyPx / page.height)
1092
- });
1093
- };
1094
- const endDrag = (a) => {
1095
- if (!drag) return;
1096
- if (drag.moved) controller.update(a.id, patchForRect(a, drag.rect));
1097
- setDrag(null);
1098
- };
1099
- const interactive = (a) => readOnly ? a.kind === "comment" : tool === "select" || tool === "comment" && a.kind === "comment";
1100
- const selected = marks.find((a) => a.id === selectedId);
1101
- return /* @__PURE__ */ jsxs(
1102
- "div",
1103
- {
1104
- ref: rootRef,
1105
- ...{ [PAGE_ATTRIBUTE]: pageNumber },
1106
- "data-testid": `annotation-overlay-${pageNumber}`,
1107
- className: cn(
1108
- "absolute inset-0 z-10 select-none overflow-hidden",
1109
- drawing && "cursor-crosshair"
1110
- ),
1111
- style: {
1112
- pointerEvents: drawing ? "auto" : "none",
1113
- touchAction: drawing ? "none" : void 0
1114
- },
1115
- onPointerDown: onRootPointerDown,
1116
- onPointerMove: onRootPointerMove,
1117
- onPointerUp: onRootPointerUp,
1118
- onPointerCancel: () => setDraft(null),
1119
- children: [
1120
- marks.map((a) => /* @__PURE__ */ jsx(
1121
- MarkView,
1122
- {
1123
- annotation: a,
1124
- rectOverride: drag?.id === a.id ? drag.rect : void 0,
1125
- pxPerPt,
1126
- width: size.width,
1127
- height: size.height,
1128
- selected: a.id === selectedId,
1129
- interactive: interactive(a),
1130
- onPointerDown: (e) => {
1131
- if (!interactive(a)) return;
1132
- e.stopPropagation();
1133
- controller.select(a.id);
1134
- if (a.kind === "comment") setOpenComment(a.id);
1135
- beginDrag(e, a, "move");
1136
- },
1137
- onPointerMove: moveDrag,
1138
- onPointerUp: () => endDrag(a),
1139
- onActivate: () => {
1140
- controller.select(a.id);
1141
- if (a.kind === "comment") setOpenComment(a.id);
1142
- },
1143
- onDelete: () => controller.remove(a.id)
1144
- },
1145
- a.id
1146
- )),
1147
- selected && tool === "select" && !readOnly && singleRect(selected) && /* @__PURE__ */ jsx(
1148
- Handles,
1149
- {
1150
- rect: drag?.id === selected.id ? drag.rect : singleRect(selected),
1151
- onPointerDown: (e, mode) => beginDrag(e, selected, mode),
1152
- onPointerMove: moveDrag,
1153
- onPointerUp: () => endDrag(selected)
1154
- }
1155
- ),
1156
- selected && tool === "select" && !readOnly && /* @__PURE__ */ jsx(
1157
- ActionBar,
1158
- {
1159
- annotation: selected,
1160
- controller,
1161
- rect: drag?.id === selected.id ? drag.rect : firstRect(selected)
1162
- }
1163
- ),
1164
- draft && /* @__PURE__ */ jsx(Draft, { draft, tool }),
1165
- openComment && selected?.kind === "comment" && selected.id === openComment && /* @__PURE__ */ jsx(
1166
- CommentPopover,
1167
- {
1168
- annotation: selected,
1169
- controller,
1170
- pageHeight: size.height,
1171
- onClose: () => {
1172
- setOpenComment(null);
1173
- controller.select(null);
1174
- }
1175
- },
1176
- selected.id
1177
- )
1178
- ]
1179
- }
1180
- );
1181
- }
1182
- var firstRect = (a) => a.kind === "highlight" || a.kind === "redaction" ? a.rects[0] : a.rect;
1183
- function MarkView(props) {
1184
- const { annotation: a, rectOverride, pxPerPt, width, height, selected, interactive } = props;
1185
- const handlers = {
1186
- onPointerDown: props.onPointerDown,
1187
- onPointerMove: props.onPointerMove,
1188
- onPointerUp: props.onPointerUp,
1189
- onPointerCancel: props.onPointerUp,
1190
- onKeyDown: (e) => {
1191
- if (e.key === "Enter") props.onActivate();
1192
- if (e.key === "Delete" || e.key === "Backspace") {
1193
- e.preventDefault();
1194
- props.onDelete();
1195
- }
1196
- }
1197
- };
1198
- const base = (label) => ({
1199
- "data-testid": `annotation-mark-${a.id}`,
1200
- "data-kind": a.kind,
1201
- "data-selected": selected ? "true" : void 0,
1202
- role: "button",
1203
- tabIndex: interactive ? 0 : -1,
1204
- "aria-label": label,
1205
- ...handlers
1206
- });
1207
- const ring = selected ? "outline outline-2 outline-offset-2 outline-primary" : "";
1208
- const events = interactive ? "auto" : "none";
1209
- const dragsByTouch = selected && singleRect(a) !== null;
1210
- const cursor = interactive ? singleRect(a) ? "move" : "pointer" : void 0;
1211
- if (a.kind === "highlight") {
1212
- return /* @__PURE__ */ jsx(Fragment, { children: a.rects.map((r, i) => /* @__PURE__ */ jsx(
1213
- "div",
1214
- {
1215
- ...i === 0 ? base(`Highlight: ${a.text ?? ""}`) : {},
1216
- className: cn("absolute rounded-sm", i === 0 && ring),
1217
- style: {
1218
- ...rectStyle(r),
1219
- background: a.color,
1220
- mixBlendMode: "multiply",
1221
- opacity: 0.7,
1222
- pointerEvents: events,
1223
- touchAction: dragsByTouch ? "none" : void 0,
1224
- cursor
1225
- }
1226
- },
1227
- i
1228
- )) });
1229
- }
1230
- if (a.kind === "box") {
1231
- const r = rectOverride ?? a.rect;
1232
- return /* @__PURE__ */ jsx(
1233
- "div",
1234
- {
1235
- ...base("Box"),
1236
- className: cn("absolute", ring),
1237
- style: {
1238
- ...rectStyle(r),
1239
- border: `${a.strokeWidth * pxPerPt}px solid ${a.color}`,
1240
- pointerEvents: events,
1241
- touchAction: dragsByTouch ? "none" : void 0,
1242
- cursor,
1243
- boxSizing: "border-box"
1244
- }
1245
- }
1246
- );
1247
- }
1248
- if (a.kind === "stamp" && a.image) {
1249
- const r = rectOverride ?? a.rect;
1250
- return /* @__PURE__ */ jsx(
1251
- "div",
1252
- {
1253
- ...base(`Stamp: ${a.label}`),
1254
- className: cn("absolute", ring),
1255
- style: {
1256
- ...rectStyle(r),
1257
- pointerEvents: events,
1258
- touchAction: dragsByTouch ? "none" : void 0,
1259
- cursor
1260
- },
1261
- children: /* @__PURE__ */ jsx(
1262
- "img",
1263
- {
1264
- src: `data:image/png;base64,${a.image}`,
1265
- alt: a.label,
1266
- draggable: false,
1267
- className: "pointer-events-none h-full w-full object-contain select-none"
1268
- }
1269
- )
1270
- }
1271
- );
1272
- }
1273
- if (a.kind === "stamp") {
1274
- const r = rectOverride ?? a.rect;
1275
- const fontPx = Math.max(
1276
- 6,
1277
- Math.min(r.h * height * 0.6, r.w * width * 0.9 / Math.max(1, a.label.length * 0.7))
1278
- );
1279
- return /* @__PURE__ */ jsx(
1280
- "div",
1281
- {
1282
- ...base(`Stamp: ${a.label}`),
1283
- className: cn("absolute flex items-center justify-center font-bold uppercase", ring),
1284
- style: {
1285
- ...rectStyle(r),
1286
- border: `${2 * pxPerPt}px solid ${a.color}`,
1287
- color: a.color,
1288
- fontSize: fontPx,
1289
- lineHeight: 1,
1290
- pointerEvents: events,
1291
- touchAction: dragsByTouch ? "none" : void 0,
1292
- cursor,
1293
- boxSizing: "border-box",
1294
- fontFamily: "Helvetica, Arial, sans-serif"
1295
- },
1296
- children: a.label
1297
- }
1298
- );
1299
- }
1300
- if (a.kind === "comment") {
1301
- const r = rectOverride ?? a.rect;
1302
- return /* @__PURE__ */ jsxs(
1303
- "button",
1304
- {
1305
- type: "button",
1306
- ...base(`Comment: ${a.body || "empty"}`),
1307
- onMouseDown: (e) => e.preventDefault(),
1308
- className: cn(
1309
- "absolute flex items-center justify-center rounded-md border border-amber-700/60 bg-amber-300 text-amber-900 shadow-sm",
1310
- a.resolved && "opacity-50",
1311
- ring
1312
- ),
1313
- style: {
1314
- left: pct(r.x),
1315
- top: pct(r.y),
1316
- width: COMMENT_ICON_PX,
1317
- height: COMMENT_ICON_PX,
1318
- pointerEvents: events,
1319
- touchAction: dragsByTouch ? "none" : void 0,
1320
- cursor
1321
- },
1322
- children: [
1323
- /* @__PURE__ */ jsx(MessageSquare, { size: 14 }),
1324
- a.replies.length > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -right-1 -top-1 rounded-full bg-amber-900 px-1 text-[9px] leading-3 text-white", children: a.replies.length })
1325
- ]
1326
- }
1327
- );
1328
- }
1329
- return /* @__PURE__ */ jsx(RedactionView, { ...props, annotation: a, ring, cursor, base });
1330
- }
1331
- function RedactionView({
1332
- annotation: a,
1333
- rectOverride,
1334
- interactive,
1335
- selected,
1336
- ring,
1337
- cursor,
1338
- base
1339
- }) {
1340
- const events = interactive ? "auto" : "none";
1341
- const dragsByTouch = selected && singleRect(a) !== null;
1342
- const rects = rectOverride ? [rectOverride] : a.rects;
1343
- const approved = a.status === "approved";
1344
- const rejected = a.status === "rejected";
1345
- const label = `Redaction (${a.status}, not applied): ${a.reason}`;
1346
- return /* @__PURE__ */ jsx(Fragment, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
1347
- "div",
1348
- {
1349
- ...i === 0 ? { ...base(label), title: label } : {},
1350
- "data-status": i === 0 ? a.status : void 0,
1351
- className: cn(
1352
- "absolute flex items-center justify-center overflow-hidden text-[10px] leading-none",
1353
- i === 0 && ring
1354
- ),
1355
- style: {
1356
- ...rectStyle(r),
1357
- pointerEvents: events,
1358
- touchAction: dragsByTouch ? "none" : void 0,
1359
- cursor,
1360
- boxSizing: "border-box",
1361
- ...approved ? { background: "#000", color: "#fff" } : rejected ? { border: "1px dotted #868e96", opacity: 0.6 } : {
1362
- background: "rgba(224,49,49,0.18)",
1363
- border: "2px dashed #e03131",
1364
- color: "#c92a2a"
1365
- }
1366
- },
1367
- children: i === 0 && !rejected && /* @__PURE__ */ jsx("span", { className: "truncate px-1", children: "[REDACTED]" })
1368
- },
1369
- i
1370
- )) });
1371
- }
1372
- function Draft({ draft, tool }) {
1373
- const x = Math.min(draft.a.x, draft.b.x);
1374
- const y = Math.min(draft.a.y, draft.b.y);
1375
- const w = Math.abs(draft.b.x - draft.a.x);
1376
- const h = Math.abs(draft.b.y - draft.a.y);
1377
- const redact = tool === "redact-area" || tool === "redact-text";
1378
- return /* @__PURE__ */ jsx(
1379
- "div",
1380
- {
1381
- "data-testid": "annotation-draft",
1382
- className: "pointer-events-none absolute",
1383
- style: {
1384
- left: x,
1385
- top: y,
1386
- width: w,
1387
- height: h,
1388
- border: redact ? "2px dashed #e03131" : "2px solid #1c7ed6",
1389
- background: redact ? "rgba(224,49,49,0.18)" : "rgba(28,126,214,0.08)"
1390
- }
1391
- }
1392
- );
1393
- }
1394
- var HANDLES = [
1395
- { mode: "nw", style: { left: 0, top: 0 }, cursor: "nwse-resize" },
1396
- { mode: "ne", style: { left: "100%", top: 0 }, cursor: "nesw-resize" },
1397
- { mode: "sw", style: { left: 0, top: "100%" }, cursor: "nesw-resize" },
1398
- { mode: "se", style: { left: "100%", top: "100%" }, cursor: "nwse-resize" }
1399
- ];
1400
- function Handles({
1401
- rect,
1402
- onPointerDown,
1403
- onPointerMove,
1404
- onPointerUp
1405
- }) {
1406
- return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute", style: rectStyle(rect), children: HANDLES.map((h) => (
1407
- // The visible dot is small; the element a finger or pointer hits is a larger transparent
1408
- // square around it (44px on touch screens, the usual minimum target).
1409
- /* @__PURE__ */ jsx(
1410
- "div",
1411
- {
1412
- "data-testid": `annotation-handle-${h.mode}`,
1413
- className: "pointer-events-auto absolute flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:h-11 pointer-coarse:w-11",
1414
- style: { ...h.style, cursor: h.cursor, touchAction: "none" },
1415
- onPointerDown: (e) => onPointerDown(e, h.mode),
1416
- onPointerMove,
1417
- onPointerUp,
1418
- onPointerCancel: onPointerUp,
1419
- children: /* @__PURE__ */ jsx("span", { className: "pointer-events-none h-3 w-3 rounded-full border-2 border-primary bg-background" })
1420
- },
1421
- h.mode
1422
- )
1423
- )) });
1424
- }
1425
- var ACTION = "inline-flex h-7 w-7 items-center justify-center rounded text-foreground hover:bg-muted";
1426
- function ActionBar({
1427
- annotation: a,
1428
- controller,
1429
- rect
1430
- }) {
1431
- const above = rect.y > 0.05;
1432
- return /* @__PURE__ */ jsxs(
1433
- "div",
1434
- {
1435
- "data-testid": "annotation-actions",
1436
- className: "pointer-events-auto absolute z-20 flex gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
1437
- style: {
1438
- left: pct(rect.x),
1439
- top: above ? `calc(${pct(rect.y)} - 36px)` : `calc(${pct(rect.y + rect.h)} + 6px)`
1440
- },
1441
- onPointerDown: (e) => e.stopPropagation(),
1442
- children: [
1443
- a.kind === "redaction" && /* @__PURE__ */ jsx(
1444
- "span",
1445
- {
1446
- className: "max-w-44 truncate self-center px-1.5 text-xs text-muted-foreground",
1447
- title: a.reason,
1448
- "data-testid": "annotation-action-reason",
1449
- children: a.reason
1450
- }
1451
- ),
1452
- a.kind === "redaction" && a.status !== "approved" && /* @__PURE__ */ jsx(
1453
- "button",
1454
- {
1455
- type: "button",
1456
- className: ACTION,
1457
- title: "Approve redaction",
1458
- "aria-label": "Approve redaction",
1459
- "data-testid": "annotation-action-approve",
1460
- onClick: () => controller.setRedactionStatus([a.id], "approved"),
1461
- children: /* @__PURE__ */ jsx(Check, { size: 15 })
1462
- }
1463
- ),
1464
- a.kind === "redaction" && a.status !== "rejected" && /* @__PURE__ */ jsx(
1465
- "button",
1466
- {
1467
- type: "button",
1468
- className: ACTION,
1469
- title: "Reject redaction (leave visible)",
1470
- "aria-label": "Reject redaction",
1471
- "data-testid": "annotation-action-reject",
1472
- onClick: () => controller.setRedactionStatus([a.id], "rejected"),
1473
- children: /* @__PURE__ */ jsx(X, { size: 15 })
1474
- }
1475
- ),
1476
- a.kind === "redaction" && a.status !== "pending" && /* @__PURE__ */ jsx(
1477
- "button",
1478
- {
1479
- type: "button",
1480
- className: ACTION,
1481
- title: "Back to pending",
1482
- "aria-label": "Mark pending",
1483
- "data-testid": "annotation-action-pending",
1484
- onClick: () => controller.setRedactionStatus([a.id], "pending"),
1485
- children: /* @__PURE__ */ jsx(RotateCcw, { size: 15 })
1486
- }
1487
- ),
1488
- /* @__PURE__ */ jsx(
1489
- "button",
1490
- {
1491
- type: "button",
1492
- className: ACTION,
1493
- title: "Delete",
1494
- "aria-label": "Delete annotation",
1495
- "data-testid": "annotation-action-delete",
1496
- onClick: () => controller.remove(a.id),
1497
- children: /* @__PURE__ */ jsx(Trash2, { size: 15 })
1498
- }
1499
- )
1500
- ]
1501
- }
1502
- );
1503
- }
1504
- function CommentPopover({
1505
- annotation: a,
1506
- controller,
1507
- pageHeight,
1508
- onClose
1509
- }) {
1510
- const [body, setBody] = useState(a.body);
1511
- const [reply, setReply] = useState("");
1512
- const [lift, setLift] = useState(0);
1513
- const popRef = useRef(null);
1514
- const unsaved = useRef(null);
1515
- const readOnly = controller.readOnly;
1516
- const mine = a.author === controller.author && !readOnly;
1517
- useEffect(() => setBody(a.body), [a.body]);
1518
- useLayoutEffect(() => {
1519
- const el = popRef.current;
1520
- if (!el) return;
1521
- const top2 = a.rect.y * pageHeight;
1522
- const fit = () => setLift(Math.min(top2, Math.max(0, top2 + el.offsetHeight - pageHeight)));
1523
- fit();
1524
- const observer = new ResizeObserver(fit);
1525
- observer.observe(el);
1526
- return () => observer.disconnect();
1527
- }, [a.rect.y, pageHeight]);
1528
- const commitBody = () => {
1529
- if (mine && body !== a.body) controller.update(a.id, { body });
1530
- unsaved.current = null;
1531
- };
1532
- useEffect(
1533
- () => () => {
1534
- if (unsaved.current !== null) controller.update(a.id, { body: unsaved.current });
1535
- unsaved.current = null;
1536
- },
1537
- // eslint-disable-next-line react-hooks/exhaustive-deps -- runs once, when this comment's box unmounts
1538
- [a.id]
1539
- );
1540
- const close = () => {
1541
- commitBody();
1542
- if (!readOnly && body.trim() === "" && a.replies.length === 0) controller.remove(a.id);
1543
- onClose();
1544
- };
1545
- const sendReply = () => {
1546
- const text = reply.trim();
1547
- if (!text) return;
1548
- commitBody();
1549
- controller.reply(a.id, text);
1550
- setReply("");
1551
- };
1552
- const onRight = a.rect.x > 0.6;
1553
- return /* @__PURE__ */ jsxs(
1554
- "div",
1555
- {
1556
- ref: popRef,
1557
- "data-testid": "annotation-comment-popover",
1558
- className: "pointer-events-auto absolute z-30 w-64 rounded-lg border border-border bg-background p-3 text-sm shadow-lg",
1559
- style: {
1560
- top: pct(a.rect.y),
1561
- marginTop: -lift,
1562
- ...onRight ? { right: `calc(${pct(1 - a.rect.x)} + 8px)` } : { left: `calc(${pct(a.rect.x)} + ${COMMENT_ICON_PX + 8}px)` }
1563
- },
1564
- onPointerDown: (e) => e.stopPropagation(),
1565
- children: [
1566
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2 text-xs text-muted-foreground", children: [
1567
- /* @__PURE__ */ jsxs("span", { className: "truncate", children: [
1568
- a.author,
1569
- " \xB7 ",
1570
- new Date(a.createdAt).toLocaleString()
1571
- ] }),
1572
- /* @__PURE__ */ jsx(
1573
- "button",
1574
- {
1575
- type: "button",
1576
- "aria-label": "Close comment",
1577
- "data-testid": "annotation-comment-close",
1578
- className: ACTION,
1579
- onClick: close,
1580
- children: /* @__PURE__ */ jsx(X, { size: 14 })
1581
- }
1582
- )
1583
- ] }),
1584
- /* @__PURE__ */ jsx(
1585
- "textarea",
1586
- {
1587
- autoFocus: a.body === "",
1588
- "data-testid": "annotation-comment-body",
1589
- className: "field-sizing-content max-h-60 min-h-24 w-full resize-y rounded-md border border-input bg-background p-2 text-sm",
1590
- placeholder: "Add a comment",
1591
- value: body,
1592
- readOnly: !mine,
1593
- onChange: (e) => {
1594
- setBody(e.target.value);
1595
- unsaved.current = e.target.value;
1596
- },
1597
- onBlur: commitBody,
1598
- onKeyDown: (e) => {
1599
- if (e.key === "Escape") close();
1600
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
1601
- commitBody();
1602
- onClose();
1603
- }
1604
- }
1605
- }
1606
- ),
1607
- a.replies.length > 0 && /* @__PURE__ */ jsx(
1608
- "ul",
1609
- {
1610
- className: "mt-2 max-h-40 space-y-2 overflow-y-auto",
1611
- "data-testid": "annotation-comment-replies",
1612
- children: a.replies.map((r) => /* @__PURE__ */ jsxs("li", { className: "rounded-md bg-muted p-2", children: [
1613
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: r.author }),
1614
- /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap break-words", children: r.body })
1615
- ] }, r.id))
1616
- }
1617
- ),
1618
- !readOnly && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-1", children: [
1619
- /* @__PURE__ */ jsx(
1620
- "input",
1621
- {
1622
- "data-testid": "annotation-comment-reply",
1623
- className: "h-8 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-sm",
1624
- placeholder: "Reply",
1625
- value: reply,
1626
- onChange: (e) => setReply(e.target.value),
1627
- onKeyDown: (e) => {
1628
- if (e.key === "Enter") {
1629
- e.preventDefault();
1630
- sendReply();
1631
- }
1632
- }
1633
- }
1634
- ),
1635
- /* @__PURE__ */ jsx(
1636
- "button",
1637
- {
1638
- type: "button",
1639
- "aria-label": "Send reply",
1640
- "data-testid": "annotation-comment-send",
1641
- className: ACTION,
1642
- onClick: sendReply,
1643
- children: /* @__PURE__ */ jsx(Send, { size: 14 })
1644
- }
1645
- )
1646
- ] }),
1647
- readOnly ? /* @__PURE__ */ jsx("div", { className: "mt-2 text-xs text-muted-foreground", "data-testid": "annotation-comment-status", children: a.resolved ? "Resolved" : "Open" }) : /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between", children: [
1648
- /* @__PURE__ */ jsx(
1649
- "button",
1650
- {
1651
- type: "button",
1652
- "data-testid": "annotation-comment-resolve",
1653
- className: "text-xs text-primary hover:underline",
1654
- onClick: () => controller.resolve(a.id, !a.resolved),
1655
- children: a.resolved ? "Reopen" : "Resolve"
1656
- }
1657
- ),
1658
- /* @__PURE__ */ jsx(
1659
- "button",
1660
- {
1661
- type: "button",
1662
- "data-testid": "annotation-comment-delete",
1663
- className: "text-xs text-destructive hover:underline",
1664
- onClick: () => {
1665
- controller.remove(a.id);
1666
- onClose();
1667
- },
1668
- children: "Delete"
1669
- }
1670
- )
1671
- ] })
1672
- ]
1673
- }
1674
- );
1675
- }
1676
- function pngPixelSize(base64) {
1677
- const raw = atob(base64.slice(0, 64));
1678
- const at = (i) => (raw.charCodeAt(i) << 24 | raw.charCodeAt(i + 1) << 16 | raw.charCodeAt(i + 2) << 8 | raw.charCodeAt(i + 3)) >>> 0;
1679
- return { width: at(16), height: at(20) };
1680
- }
1681
- var isEditable = (el) => el instanceof HTMLElement && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName));
1682
- function useAnnotationShortcuts(controller, enabled = true) {
1683
- useEffect(() => {
1684
- if (!enabled) return;
1685
- const onKey = (e) => {
1686
- if (isEditable(e.target)) return;
1687
- const mod = e.metaKey || e.ctrlKey;
1688
- if (mod && e.key.toLowerCase() === "z") {
1689
- e.preventDefault();
1690
- if (e.shiftKey) controller.redo();
1691
- else controller.undo();
1692
- } else if (mod && e.key.toLowerCase() === "y") {
1693
- e.preventDefault();
1694
- controller.redo();
1695
- } else if ((e.key === "Delete" || e.key === "Backspace") && controller.selectedId) {
1696
- e.preventDefault();
1697
- controller.remove(controller.selectedId);
1698
- } else if (e.key === "Escape") {
1699
- controller.select(null);
1700
- controller.setTool("select");
1701
- }
1702
- };
1703
- document.addEventListener("keydown", onKey);
1704
- return () => document.removeEventListener("keydown", onKey);
1705
- }, [controller, enabled]);
1706
- }
1707
- var TOOLS = [
1708
- { tool: "select", label: "Select", icon: /* @__PURE__ */ jsx(MousePointer2, { size: 16 }) },
1709
- { tool: "highlight", label: "Highlight", icon: /* @__PURE__ */ jsx(Highlighter, { size: 16 }) },
1710
- { tool: "box", label: "Box", icon: /* @__PURE__ */ jsx(Square, { size: 16 }) },
1711
- { tool: "comment", label: "Comment", icon: /* @__PURE__ */ jsx(MessageSquare, { size: 16 }) },
1712
- { tool: "stamp", label: "Stamp", icon: /* @__PURE__ */ jsx(Stamp, { size: 16 }) },
1713
- { tool: "redact-text", label: "Redact text", icon: /* @__PURE__ */ jsx(ScanText, { size: 16 }) },
1714
- { tool: "redact-area", label: "Redact area", icon: /* @__PURE__ */ jsx(EyeOff, { size: 16 }) }
1715
- ];
1716
- function Swatches({
1717
- colors,
1718
- value,
1719
- onChange,
1720
- label
1721
- }) {
1722
- return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", role: "group", "aria-label": label, children: colors.map((c) => /* @__PURE__ */ jsx(
1723
- "button",
1724
- {
1725
- type: "button",
1726
- "aria-label": `${label} ${c}`,
1727
- "aria-pressed": c === value,
1728
- "data-testid": `annotation-color-${c.slice(1)}`,
1729
- className: cn(
1730
- "h-5 w-5 rounded-full border border-border",
1731
- c === value && "ring-2 ring-primary ring-offset-1"
1732
- ),
1733
- style: { background: c },
1734
- onClick: () => onChange(c)
1735
- },
1736
- c
1737
- )) });
1738
- }
1739
- function PresetField({
1740
- label,
1741
- testId,
1742
- value,
1743
- presets,
1744
- maxLength,
1745
- className,
1746
- onChange
1747
- }) {
1748
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1749
- /* @__PURE__ */ jsx(
1750
- "input",
1751
- {
1752
- "aria-label": label,
1753
- "data-testid": testId,
1754
- className: cn("h-8 rounded-l-md border border-input bg-background px-2 text-sm", className),
1755
- value,
1756
- maxLength,
1757
- onFocus: (e) => e.currentTarget.select(),
1758
- onChange: (e) => onChange(e.target.value)
1759
- }
1760
- ),
1761
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1762
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1763
- "button",
1764
- {
1765
- type: "button",
1766
- "aria-label": `Choose ${label.toLowerCase()}`,
1767
- title: `Choose ${label.toLowerCase()}`,
1768
- "data-testid": `${testId}-presets`,
1769
- className: "flex h-8 items-center rounded-r-md border border-l-0 border-input bg-background px-1.5 text-muted-foreground hover:bg-accent",
1770
- children: /* @__PURE__ */ jsx(ChevronDown, { size: 14 })
1771
- }
1772
- ) }),
1773
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: presets.map((p) => /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: () => onChange(p), children: p }, p)) })
1774
- ] })
1775
- ] });
1776
- }
1777
- function AnnotationToolbar({
1778
- controller,
1779
- onFreeze,
1780
- actions,
1781
- className
1782
- }) {
1783
- useTextSelectionMarks(controller);
1784
- useAnnotationShortcuts(controller);
1785
- const [reviewing, setReviewing] = useState(false);
1786
- const { tool, settings } = controller;
1787
- const pending = pendingRedactions(controller.layer);
1788
- const redactions = controller.layer.annotations.filter((a) => a.kind === "redaction");
1789
- const redactionCount = redactions.length;
1790
- const approved = redactions.filter((a) => a.status === "approved").length;
1791
- const rejected = redactions.filter((a) => a.status === "rejected").length;
1792
- const colored = tool === "highlight" || tool === "box" || tool === "stamp";
1793
- const redacting = tool === "redact-text" || tool === "redact-area";
1794
- const status = layerStatusText(controller);
1795
- const editable = !controller.readOnly;
1796
- const redactionControls = /* @__PURE__ */ jsxs(Fragment, { children: [
1797
- editable && redacting && /* @__PURE__ */ jsx(
1798
- PresetField,
1799
- {
1800
- label: "Redaction reason",
1801
- testId: "annotation-redaction-reason",
1802
- className: "w-44",
1803
- value: settings.redactionReason,
1804
- presets: REDACTION_REASONS,
1805
- maxLength: 80,
1806
- onChange: (redactionReason) => controller.setSettings({ redactionReason })
1807
- }
1808
- ),
1809
- redactionCount > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", "data-testid": "annotation-review", children: [
1810
- /* @__PURE__ */ jsxs("span", { className: "rounded-md bg-muted px-2 py-1", "data-testid": "annotation-pending-count", children: [
1811
- pending.length,
1812
- " pending \xB7 ",
1813
- approved,
1814
- " approved, not applied \xB7 ",
1815
- rejected,
1816
- " rejected"
1817
- ] }),
1818
- editable && /* @__PURE__ */ jsxs(Fragment, { children: [
1819
- /* @__PURE__ */ jsx(
1820
- Button,
1821
- {
1822
- type: "button",
1823
- size: "sm",
1824
- variant: "outline",
1825
- disabled: pending.length === 0,
1826
- "data-testid": "annotation-approve-all",
1827
- onClick: () => controller.setRedactionStatus(
1828
- pending.map((a) => a.id),
1829
- "approved"
1830
- ),
1831
- children: "Approve all"
1832
- }
1833
- ),
1834
- /* @__PURE__ */ jsx(
1835
- Button,
1836
- {
1837
- type: "button",
1838
- size: "sm",
1839
- variant: "outline",
1840
- disabled: pending.length === 0,
1841
- "data-testid": "annotation-reject-all",
1842
- onClick: () => controller.setRedactionStatus(
1843
- pending.map((a) => a.id),
1844
- "rejected"
1845
- ),
1846
- children: "Reject all"
1847
- }
1848
- )
1849
- ] })
1850
- ] })
1851
- ] });
1852
- return /* @__PURE__ */ jsxs(
1853
- "div",
1854
- {
1855
- role: "toolbar",
1856
- "aria-label": "Annotation tools",
1857
- "data-testid": "annotation-toolbar",
1858
- className: cn(
1859
- "flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-border bg-background px-3 py-2",
1860
- className
1861
- ),
1862
- children: [
1863
- editable && /* @__PURE__ */ jsxs(
1864
- "div",
1865
- {
1866
- className: "flex items-center gap-1 border-r border-border pr-3",
1867
- role: "group",
1868
- "aria-label": "History",
1869
- children: [
1870
- /* @__PURE__ */ jsx(
1871
- Button,
1872
- {
1873
- type: "button",
1874
- size: "icon",
1875
- variant: "ghost",
1876
- title: "Undo",
1877
- "aria-label": "Undo",
1878
- "data-testid": "annotation-undo",
1879
- disabled: !controller.canUndo,
1880
- onClick: controller.undo,
1881
- children: /* @__PURE__ */ jsx(Undo2, { size: 16 })
1882
- }
1883
- ),
1884
- /* @__PURE__ */ jsx(
1885
- Button,
1886
- {
1887
- type: "button",
1888
- size: "icon",
1889
- variant: "ghost",
1890
- title: "Redo",
1891
- "aria-label": "Redo",
1892
- "data-testid": "annotation-redo",
1893
- disabled: !controller.canRedo,
1894
- onClick: controller.redo,
1895
- children: /* @__PURE__ */ jsx(Redo2, { size: 16 })
1896
- }
1897
- )
1898
- ]
1899
- }
1900
- ),
1901
- editable && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tool", children: TOOLS.map(({ tool: t, label, icon }) => /* @__PURE__ */ jsx(
1902
- Button,
1903
- {
1904
- type: "button",
1905
- size: "icon",
1906
- variant: tool === t ? "default" : "ghost",
1907
- title: label,
1908
- "aria-label": label,
1909
- "aria-pressed": tool === t,
1910
- "data-testid": `annotation-tool-${t}`,
1911
- onClick: () => controller.setTool(t),
1912
- children: icon
1913
- },
1914
- t
1915
- )) }),
1916
- editable && colored && /* @__PURE__ */ jsx(
1917
- Swatches,
1918
- {
1919
- label: "Colour",
1920
- colors: tool === "highlight" ? HIGHLIGHT_COLORS : MARK_COLORS,
1921
- value: settings.colors[tool],
1922
- onChange: (c) => controller.setSettings({ colors: { ...settings.colors, [tool]: c } })
1923
- }
1924
- ),
1925
- editable && tool === "stamp" && settings.stampImage && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", "data-testid": "annotation-place-signature", children: [
1926
- "Click where your ",
1927
- settings.stampImage.label.toLowerCase(),
1928
- " goes."
1929
- ] }),
1930
- editable && tool === "stamp" && !settings.stampImage && /* @__PURE__ */ jsx(
1931
- PresetField,
1932
- {
1933
- label: "Stamp text",
1934
- testId: "annotation-stamp-label",
1935
- className: "w-40",
1936
- value: settings.stampLabel,
1937
- presets: STAMP_PRESETS,
1938
- maxLength: 40,
1939
- onChange: (stampLabel) => controller.setSettings({ stampLabel })
1940
- }
1941
- ),
1942
- (redacting || redactionCount > 0) && /* @__PURE__ */ jsxs(
1943
- "div",
1944
- {
1945
- className: "flex w-full flex-wrap items-center gap-x-3 gap-y-2",
1946
- "data-testid": "annotation-redaction-row",
1947
- children: [
1948
- redactionControls,
1949
- redactionCount > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1950
- /* @__PURE__ */ jsx(
1951
- Button,
1952
- {
1953
- type: "button",
1954
- size: "sm",
1955
- variant: "outline",
1956
- onClick: () => setReviewing((on) => !on),
1957
- "aria-expanded": reviewing,
1958
- "data-testid": "annotation-review-toggle",
1959
- children: "Review redactions"
1960
- }
1961
- ),
1962
- /* @__PURE__ */ jsx(
1963
- "p",
1964
- {
1965
- className: "w-full text-xs text-amber-700 dark:text-amber-400",
1966
- role: "status",
1967
- "data-testid": "annotation-preview-warning",
1968
- children: "Preview only: black boxes, including approved ones, have not removed the underlying content. Apply approved redactions to create a redacted copy."
1969
- }
1970
- )
1971
- ] })
1972
- ]
1973
- }
1974
- ),
1975
- reviewing && redactionCount > 0 && /* @__PURE__ */ jsx(
1976
- "div",
1977
- {
1978
- className: "max-h-64 w-full overflow-auto rounded border",
1979
- "data-testid": "annotation-redaction-review-list",
1980
- children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
1981
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1982
- /* @__PURE__ */ jsx("th", { className: "p-2", children: "Page" }),
1983
- /* @__PURE__ */ jsx("th", { children: "Reason" }),
1984
- /* @__PURE__ */ jsx("th", { children: "Review status" }),
1985
- /* @__PURE__ */ jsx("th", { children: "Decision" })
1986
- ] }) }),
1987
- /* @__PURE__ */ jsx("tbody", { children: redactions.map((a) => /* @__PURE__ */ jsxs("tr", { className: "border-t", "data-testid": `redaction-review-${a.id}`, children: [
1988
- /* @__PURE__ */ jsx("td", { className: "p-2", children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => controller.select(a.id), children: [
1989
- "Page ",
1990
- a.page
1991
- ] }) }),
1992
- /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(
1993
- "input",
1994
- {
1995
- "aria-label": `Reason for redaction ${a.id}`,
1996
- value: a.reason,
1997
- disabled: !editable,
1998
- className: "rounded border bg-background px-2 py-1",
1999
- onChange: (e) => controller.update(a.id, {
2000
- reason: e.target.value,
2001
- status: "pending",
2002
- reviewedBy: void 0,
2003
- reviewedAt: void 0
2004
- })
2005
- }
2006
- ) }),
2007
- /* @__PURE__ */ jsx("td", { children: a.status === "approved" ? "Approved \xB7 not applied" : a.status }),
2008
- /* @__PURE__ */ jsx("td", { className: "flex gap-1 p-2", children: editable && /* @__PURE__ */ jsxs(Fragment, { children: [
2009
- /* @__PURE__ */ jsx(
2010
- Button,
2011
- {
2012
- type: "button",
2013
- size: "sm",
2014
- variant: "outline",
2015
- disabled: a.status === "approved",
2016
- onClick: () => controller.setRedactionStatus([a.id], "approved"),
2017
- children: "Approve"
2018
- }
2019
- ),
2020
- /* @__PURE__ */ jsx(
2021
- Button,
2022
- {
2023
- type: "button",
2024
- size: "sm",
2025
- variant: "outline",
2026
- disabled: a.status === "rejected",
2027
- onClick: () => controller.setRedactionStatus([a.id], "rejected"),
2028
- children: "Reject"
2029
- }
2030
- )
2031
- ] }) })
2032
- ] }, a.id)) })
2033
- ] })
2034
- }
2035
- ),
2036
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-end gap-3 text-xs text-muted-foreground", children: [
2037
- /* @__PURE__ */ jsx(
2038
- "span",
2039
- {
2040
- "data-testid": "annotation-status",
2041
- role: "status",
2042
- "data-state": controller.readOnly ? "readonly" : controller.offline ? "offline" : controller.error ? "error" : controller.saving ? "saving" : controller.dirty ? "dirty" : "saved",
2043
- className: cn(controller.error && !controller.offline && "text-destructive"),
2044
- title: controller.error ?? void 0,
2045
- children: status
2046
- }
2047
- ),
2048
- actions,
2049
- onFreeze && /* @__PURE__ */ jsxs(
2050
- Button,
2051
- {
2052
- type: "button",
2053
- size: "sm",
2054
- "data-testid": "annotation-freeze",
2055
- onClick: onFreeze,
2056
- disabled: pending.length > 0,
2057
- title: pending.length ? "Approve or reject each proposed redaction first" : void 0,
2058
- children: [
2059
- /* @__PURE__ */ jsx(EyeOff, { size: 14 }),
2060
- redactionCount ? "Apply approved redactions" : "Create annotated copy"
2061
- ]
2062
- }
2063
- )
2064
- ] })
2065
- ]
2066
- }
2067
- );
2068
- }
2069
- var KIND_LABELS = {
2070
- highlight: "highlights",
2071
- box: "boxes",
2072
- comment: "comments",
2073
- stamp: "stamps",
2074
- redaction: "redactions"
2075
- };
2076
- function FreezeDialog({
2077
- open,
2078
- onOpenChange,
2079
- controller,
2080
- onConfirm,
2081
- busy,
2082
- progress,
2083
- error
2084
- }) {
2085
- const [mode, setMode] = useState("vector");
2086
- const [comments, setComments] = useState("omit");
2087
- const [redactionLog, setRedactionLog] = useState(true);
2088
- const marks = controller.layer.annotations;
2089
- const redactions = marks.filter(isEffectiveRedaction);
2090
- const pending = pendingRedactions(controller.layer);
2091
- const hasRedactionMarks = marks.some((a) => a.kind === "redaction");
2092
- const forced = redactions.length > 0;
2093
- const effectiveMode = forced ? "image" : mode;
2094
- const blocked = pending.length > 0;
2095
- const counts = Object.keys(KIND_LABELS).map(
2096
- (k) => [
2097
- k,
2098
- marks.filter((a) => a.kind === k && (k !== "redaction" || isEffectiveRedaction(a))).length
2099
- ]
2100
- ).filter(([, n]) => n > 0);
2101
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => !busy && onOpenChange(next), children: /* @__PURE__ */ jsxs(DialogContent, { "data-testid": "freeze-dialog", children: [
2102
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
2103
- /* @__PURE__ */ jsx(DialogTitle, { children: hasRedactionMarks ? "Apply approved redactions" : "Create annotated copy" }),
2104
- /* @__PURE__ */ jsx(DialogDescription, { children: "Approval records your review decision. Applying permanently removes the covered content from a new redacted copy. The original remains in your files." })
2105
- ] }),
2106
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": "freeze-summary", children: counts.length === 0 ? "No annotations yet." : counts.map(([k, n]) => `${n} ${KIND_LABELS[k]}`).join(", ") }),
2107
- /* @__PURE__ */ jsxs("fieldset", { className: "space-y-2 text-sm", disabled: busy, children: [
2108
- /* @__PURE__ */ jsx("legend", { className: "mb-1 font-medium", children: "Format" }),
2109
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2", children: [
2110
- /* @__PURE__ */ jsx(
2111
- "input",
2112
- {
2113
- type: "radio",
2114
- name: "freeze-mode",
2115
- "data-testid": "freeze-mode-vector",
2116
- checked: effectiveMode === "vector",
2117
- disabled: forced,
2118
- onChange: () => setMode("vector")
2119
- }
2120
- ),
2121
- /* @__PURE__ */ jsxs("span", { children: [
2122
- "Keep text",
2123
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Searchable, smaller. Not available when there are redactions." })
2124
- ] })
2125
- ] }),
2126
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2", children: [
2127
- /* @__PURE__ */ jsx(
2128
- "input",
2129
- {
2130
- type: "radio",
2131
- name: "freeze-mode",
2132
- "data-testid": "freeze-mode-image",
2133
- checked: effectiveMode === "image",
2134
- onChange: () => setMode("image")
2135
- }
2136
- ),
2137
- /* @__PURE__ */ jsxs("span", { children: [
2138
- "Image only",
2139
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Every page becomes a picture. Nothing is left behind a redaction." })
2140
- ] })
2141
- ] }),
2142
- forced && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", "data-testid": "freeze-forced-note", children: "Image only is required because this document has redactions." })
2143
- ] }),
2144
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
2145
- "Comments",
2146
- /* @__PURE__ */ jsxs(
2147
- "select",
2148
- {
2149
- "data-testid": "freeze-comments",
2150
- className: "h-8 rounded-md border border-input bg-background px-2",
2151
- value: comments,
2152
- disabled: busy,
2153
- onChange: (e) => setComments(e.target.value),
2154
- children: [
2155
- /* @__PURE__ */ jsx("option", { value: "omit", children: "Leave out" }),
2156
- /* @__PURE__ */ jsx("option", { value: "markers", children: "Numbered markers" }),
2157
- /* @__PURE__ */ jsx("option", { value: "appendix", children: "Markers and a listing" })
2158
- ]
2159
- }
2160
- )
2161
- ] }),
2162
- forced && comments !== "omit" && marks.some((a) => a.kind === "comment") && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", "data-testid": "freeze-comment-warning", children: "Comments are copied as written and may repeat text you have redacted." }),
2163
- pending.length > 0 && /* @__PURE__ */ jsxs("p", { className: "rounded border p-2 text-sm", "data-testid": "freeze-pending", children: [
2164
- pending.length,
2165
- " redaction",
2166
- pending.length === 1 ? " has" : "s have",
2167
- " not been reviewed. Approve or reject each one before applying redactions."
2168
- ] }),
2169
- hasRedactionMarks && /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
2170
- /* @__PURE__ */ jsx(
2171
- "input",
2172
- {
2173
- type: "checkbox",
2174
- "data-testid": "freeze-redaction-log",
2175
- checked: redactionLog,
2176
- disabled: busy,
2177
- onChange: (e) => setRedactionLog(e.target.checked)
2178
- }
2179
- ),
2180
- /* @__PURE__ */ jsxs("span", { children: [
2181
- "Download a redaction log (CSV)",
2182
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Page, reason, status, who approved it and when. Never the redacted text." })
2183
- ] })
2184
- ] }),
2185
- busy && progress && /* @__PURE__ */ jsxs("p", { className: "text-sm", role: "status", "data-testid": "freeze-progress", children: [
2186
- "Page ",
2187
- progress.done,
2188
- " of ",
2189
- progress.total,
2190
- "\u2026"
2191
- ] }),
2192
- error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", role: "alert", "data-testid": "freeze-error", children: error }),
2193
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
2194
- /* @__PURE__ */ jsx(
2195
- Button,
2196
- {
2197
- type: "button",
2198
- variant: "outline",
2199
- disabled: busy,
2200
- onClick: () => onOpenChange(false),
2201
- children: "Cancel"
2202
- }
2203
- ),
2204
- /* @__PURE__ */ jsx(
2205
- Button,
2206
- {
2207
- type: "button",
2208
- "data-testid": "freeze-confirm",
2209
- disabled: busy || blocked,
2210
- onClick: () => onConfirm({
2211
- mode: effectiveMode,
2212
- comments,
2213
- pendingRedactions: "error",
2214
- redactionLog: hasRedactionMarks && redactionLog
2215
- }),
2216
- children: busy ? "Creating copy\u2026" : hasRedactionMarks ? "Apply redactions and create copy" : "Create annotated copy"
2217
- }
2218
- )
2219
- ] })
2220
- ] }) });
2221
- }
2222
- var MAX_PREFIX = 24;
2223
- function previewLabel(choices) {
2224
- return `${choices.prefix}${String(choices.start).padStart(choices.digits, "0")}`;
2225
- }
2226
- function qrCornerFor(corner) {
2227
- return corner.endsWith("left") ? "bottom-right" : "bottom-left";
2228
- }
2229
- function moveItem(items, from, to) {
2230
- if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length)
2231
- return [...items];
2232
- const next = [...items];
2233
- const [moved] = next.splice(from, 1);
2234
- next.splice(to, 0, moved);
2235
- return next;
2236
- }
2237
- function ProductionDialog({
2238
- open,
2239
- onOpenChange,
2240
- documents,
2241
- leftOut = [],
2242
- onConfirm,
2243
- busy,
2244
- progress,
2245
- error
2246
- }) {
2247
- const [layout, setLayout] = useState("merged");
2248
- const [prefix, setPrefix] = useState("");
2249
- const [start, setStart] = useState(1);
2250
- const [digits, setDigits] = useState(6);
2251
- const [corner, setCorner] = useState("bottom-right");
2252
- const [qr, setQr] = useState(false);
2253
- const [indexPage, setIndexPage] = useState(false);
2254
- const [saveToWorkspace, setSaveToWorkspace] = useState(true);
2255
- const documentKey = documents.map((d) => d.id).join("|");
2256
- const [ordered, setOrdered] = useState(documents);
2257
- useEffect(() => setOrdered(documents), [documentKey]);
2258
- const listRef = useRef(null);
2259
- const [dragFrom, setDragFrom] = useState(null);
2260
- const focusAfterMove = useRef(null);
2261
- useEffect(() => {
2262
- const pending = focusAfterMove.current;
2263
- focusAfterMove.current = null;
2264
- if (!pending || !listRef.current) return;
2265
- const button = (arrow) => listRef.current?.querySelector(
2266
- `[data-testid="production-move-${arrow}-${pending.index}"]:not(:disabled)`
2267
- );
2268
- (button(pending.arrow) ?? button(pending.arrow === "up" ? "down" : "up"))?.focus();
2269
- }, [ordered]);
2270
- const move = (from, to, arrow) => {
2271
- if (arrow) focusAfterMove.current = { index: to, arrow };
2272
- setOrdered((items) => moveItem(items, from, to));
2273
- };
2274
- const onDrop = (to) => (e) => {
2275
- e.preventDefault();
2276
- if (dragFrom !== null) move(dragFrom, to);
2277
- setDragFrom(null);
2278
- };
2279
- const valid = Number.isInteger(start) && start >= 0 && Number.isInteger(digits) && digits >= 1 && digits <= 12;
2280
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => !busy && onOpenChange(next), children: /* @__PURE__ */ jsxs(DialogContent, { "data-testid": "production-dialog", className: "max-h-[90dvh] overflow-y-auto", children: [
2281
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
2282
- /* @__PURE__ */ jsx(DialogTitle, { children: "Production set" }),
2283
- /* @__PURE__ */ jsx(DialogDescription, { children: "Numbers every page with a Bates label, in the order shown. The originals are never changed; the result is downloaded and, if you choose, saved to the workspace." })
2284
- ] }),
2285
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", "data-testid": "production-summary", children: [
2286
- documents.length,
2287
- " document",
2288
- documents.length === 1 ? "" : "s",
2289
- ", numbered in this order.",
2290
- ordered.length > 1 ? " Drag a row or use its arrows to reorder." : ""
2291
- ] }),
2292
- /* @__PURE__ */ jsx(
2293
- "ol",
2294
- {
2295
- ref: listRef,
2296
- className: "max-h-48 space-y-1 overflow-y-auto text-sm",
2297
- "data-testid": "production-order",
2298
- "aria-label": "Numbering order",
2299
- children: ordered.map((doc, i) => /* @__PURE__ */ jsxs(
2300
- "li",
2301
- {
2302
- draggable: !busy,
2303
- onDragStart: () => setDragFrom(i),
2304
- onDragOver: (e) => e.preventDefault(),
2305
- onDrop: onDrop(i),
2306
- onDragEnd: () => setDragFrom(null),
2307
- className: `flex items-center gap-1 rounded-md border border-border px-2 py-1 ${dragFrom === i ? "opacity-50" : ""}`,
2308
- "data-testid": `production-order-item-${i}`,
2309
- "data-document-id": doc.id,
2310
- children: [
2311
- /* @__PURE__ */ jsx(
2312
- GripVertical,
2313
- {
2314
- className: "size-4 shrink-0 cursor-grab text-muted-foreground",
2315
- "aria-hidden": true
2316
- }
2317
- ),
2318
- /* @__PURE__ */ jsxs("span", { className: "w-6 shrink-0 text-right tabular-nums text-muted-foreground", children: [
2319
- i + 1,
2320
- "."
2321
- ] }),
2322
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", title: doc.name, children: doc.name }),
2323
- /* @__PURE__ */ jsx(
2324
- Button,
2325
- {
2326
- type: "button",
2327
- variant: "ghost",
2328
- size: "icon",
2329
- className: "size-7 pointer-coarse:size-11",
2330
- "aria-label": `Move ${doc.name} up`,
2331
- "data-testid": `production-move-up-${i}`,
2332
- disabled: busy || i === 0,
2333
- onClick: () => move(i, i - 1, "up"),
2334
- children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
2335
- }
2336
- ),
2337
- /* @__PURE__ */ jsx(
2338
- Button,
2339
- {
2340
- type: "button",
2341
- variant: "ghost",
2342
- size: "icon",
2343
- className: "size-7 pointer-coarse:size-11",
2344
- "aria-label": `Move ${doc.name} down`,
2345
- "data-testid": `production-move-down-${i}`,
2346
- disabled: busy || i === ordered.length - 1,
2347
- onClick: () => move(i, i + 1, "down"),
2348
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
2349
- }
2350
- )
2351
- ]
2352
- },
2353
- doc.id
2354
- ))
2355
- }
2356
- ),
2357
- leftOut.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", "data-testid": "production-left-out", children: [
2358
- "Left out, with no PDF version to number: ",
2359
- leftOut.join(", ")
2360
- ] }),
2361
- /* @__PURE__ */ jsxs("fieldset", { className: "space-y-2 text-sm", disabled: busy, children: [
2362
- /* @__PURE__ */ jsx("legend", { className: "mb-1 font-medium", children: "Files" }),
2363
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2", children: [
2364
- /* @__PURE__ */ jsx(
2365
- "input",
2366
- {
2367
- type: "radio",
2368
- name: "production-layout",
2369
- "data-testid": "production-layout-merged",
2370
- checked: layout === "merged",
2371
- onChange: () => setLayout("merged")
2372
- }
2373
- ),
2374
- /* @__PURE__ */ jsxs("span", { children: [
2375
- "One merged file",
2376
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "All documents joined, numbered consecutively." })
2377
- ] })
2378
- ] }),
2379
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2", children: [
2380
- /* @__PURE__ */ jsx(
2381
- "input",
2382
- {
2383
- type: "radio",
2384
- name: "production-layout",
2385
- "data-testid": "production-layout-per-document",
2386
- checked: layout === "per-document",
2387
- onChange: () => setLayout("per-document")
2388
- }
2389
- ),
2390
- /* @__PURE__ */ jsxs("span", { children: [
2391
- "One file per document",
2392
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Numbering carries on from one file to the next." })
2393
- ] })
2394
- ] })
2395
- ] }),
2396
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2 text-sm", children: [
2397
- /* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
2398
- "Prefix",
2399
- /* @__PURE__ */ jsx(
2400
- "input",
2401
- {
2402
- "data-testid": "production-prefix",
2403
- className: "h-8 w-full rounded-md border border-input bg-background px-2",
2404
- value: prefix,
2405
- maxLength: MAX_PREFIX,
2406
- disabled: busy,
2407
- onChange: (e) => setPrefix(e.target.value)
2408
- }
2409
- )
2410
- ] }),
2411
- /* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
2412
- "Start at",
2413
- /* @__PURE__ */ jsx(
2414
- "input",
2415
- {
2416
- "data-testid": "production-start",
2417
- type: "number",
2418
- min: 0,
2419
- className: "h-8 w-full rounded-md border border-input bg-background px-2",
2420
- value: start,
2421
- disabled: busy,
2422
- onChange: (e) => setStart(e.target.valueAsNumber)
2423
- }
2424
- )
2425
- ] }),
2426
- /* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
2427
- "Digits",
2428
- /* @__PURE__ */ jsx(
2429
- "input",
2430
- {
2431
- "data-testid": "production-digits",
2432
- type: "number",
2433
- min: 1,
2434
- max: 12,
2435
- className: "h-8 w-full rounded-md border border-input bg-background px-2",
2436
- value: digits,
2437
- disabled: busy,
2438
- onChange: (e) => setDigits(e.target.valueAsNumber)
2439
- }
2440
- )
2441
- ] })
2442
- ] }),
2443
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
2444
- "Label position",
2445
- /* @__PURE__ */ jsxs(
2446
- "select",
2447
- {
2448
- "data-testid": "production-corner",
2449
- className: "h-8 rounded-md border border-input bg-background px-2",
2450
- value: corner,
2451
- disabled: busy,
2452
- onChange: (e) => setCorner(e.target.value),
2453
- children: [
2454
- /* @__PURE__ */ jsx("option", { value: "bottom-right", children: "Bottom right" }),
2455
- /* @__PURE__ */ jsx("option", { value: "bottom-left", children: "Bottom left" }),
2456
- /* @__PURE__ */ jsx("option", { value: "top-right", children: "Top right" }),
2457
- /* @__PURE__ */ jsx("option", { value: "top-left", children: "Top left" })
2458
- ]
2459
- }
2460
- )
2461
- ] }),
2462
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
2463
- /* @__PURE__ */ jsx(
2464
- "input",
2465
- {
2466
- type: "checkbox",
2467
- "data-testid": "production-qr",
2468
- checked: qr,
2469
- disabled: busy,
2470
- onChange: (e) => setQr(e.target.checked)
2471
- }
2472
- ),
2473
- /* @__PURE__ */ jsxs("span", { children: [
2474
- "QR code on every page",
2475
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Opens the document in ARBI for anyone with access." })
2476
- ] })
2477
- ] }),
2478
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
2479
- /* @__PURE__ */ jsx(
2480
- "input",
2481
- {
2482
- type: "checkbox",
2483
- "data-testid": "production-index",
2484
- checked: indexPage,
2485
- disabled: busy,
2486
- onChange: (e) => setIndexPage(e.target.checked)
2487
- }
2488
- ),
2489
- /* @__PURE__ */ jsxs("span", { children: [
2490
- "Index page at the start",
2491
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Lists every document with its Bates range. The index itself is not numbered." })
2492
- ] })
2493
- ] }),
2494
- /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
2495
- /* @__PURE__ */ jsx(
2496
- "input",
2497
- {
2498
- type: "checkbox",
2499
- "data-testid": "production-save",
2500
- checked: saveToWorkspace,
2501
- disabled: busy,
2502
- onChange: (e) => setSaveToWorkspace(e.target.checked)
2503
- }
2504
- ),
2505
- /* @__PURE__ */ jsxs("span", { children: [
2506
- "Save to workspace",
2507
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: layout === "merged" ? "Adds the merged PDF to the Productions folder, so it can be shared or emailed." : "Adds each numbered file to a folder under Productions, so they can be shared or emailed." })
2508
- ] })
2509
- ] }),
2510
- valid && /* @__PURE__ */ jsxs("p", { className: "text-sm", "data-testid": "production-preview", children: [
2511
- "First label:",
2512
- " ",
2513
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: previewLabel({ prefix, start, digits }) })
2514
- ] }),
2515
- busy && progress && /* @__PURE__ */ jsxs("p", { className: "text-sm", role: "status", "data-testid": "production-progress", children: [
2516
- "Document ",
2517
- progress.done,
2518
- " of ",
2519
- progress.total,
2520
- "\u2026"
2521
- ] }),
2522
- error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", role: "alert", "data-testid": "production-error", children: error }),
2523
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
2524
- /* @__PURE__ */ jsx(
2525
- Button,
2526
- {
2527
- type: "button",
2528
- variant: "outline",
2529
- disabled: busy,
2530
- onClick: () => onOpenChange(false),
2531
- children: "Cancel"
2532
- }
2533
- ),
2534
- /* @__PURE__ */ jsx(
2535
- Button,
2536
- {
2537
- type: "button",
2538
- "data-testid": "production-confirm",
2539
- disabled: busy || !valid || ordered.length === 0,
2540
- onClick: () => onConfirm({
2541
- layout,
2542
- prefix,
2543
- start,
2544
- digits,
2545
- corner,
2546
- qr,
2547
- indexPage,
2548
- saveToWorkspace,
2549
- order: ordered.map((d) => d.id)
2550
- }),
2551
- children: busy ? "Working\u2026" : "Create production"
2552
- }
2553
- )
2554
- ] })
2555
- ] }) });
2556
- }
2557
-
2558
- export { AUTOSAVE_MS, AnnotationPageOverlay, AnnotationStoreOfflineError, AnnotationToolbar, DEFAULT_SETTINGS, FreezeDialog, HIGHLIGHT_COLORS, MARK_COLORS, ProductionDialog, REDACTION_LOG_COLUMNS, REDACTION_REASONS, RETRY_MS, STAMP_PRESETS, annotationsOnPage, applyAction, canRedo, canUndo, containsPoint, createHistory, createLocalStorageStore, createMemoryStore, dragRect, dragToNorm, intersects, isTooSmall, layerStatusText, mergeLayers, mergeLineRects, moveItem, patchForRect, pendingRedactions, qrCornerFor, readSelection, redactionLogCsv, redactionLogRows, redo, reduceLayer, sameMarks, selectionToPageMarks, singleRect, toNorm, toPixels, undo, useAnnotationLayer, useAnnotationShortcuts, useTextSelectionMarks };
2559
- //# sourceMappingURL=chunk-T4CLW3DN.js.map
2560
- //# sourceMappingURL=chunk-T4CLW3DN.js.map