@arbidocs/blocks 0.5.114 → 0.5.116

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 (166) hide show
  1. package/dist/{ConnectedCallDock-2KXEQENS.cjs → ConnectedCallDock-WER7R222.cjs} +21 -21
  2. package/dist/{ConnectedCallDock-2KXEQENS.cjs.map → ConnectedCallDock-WER7R222.cjs.map} +1 -1
  3. package/dist/{ConnectedCallRoom-MU3NPNXF.cjs → ConnectedCallRoom-T7OBQTYP.cjs} +14 -14
  4. package/dist/{ConnectedCallRoom-MU3NPNXF.cjs.map → ConnectedCallRoom-T7OBQTYP.cjs.map} +1 -1
  5. package/dist/{ConnectedNativeDocxComparison-VH3I65H6.cjs → ConnectedNativeDocxComparison-546ILGLW.cjs} +19 -19
  6. package/dist/{ConnectedNativeDocxComparison-VH3I65H6.cjs.map → ConnectedNativeDocxComparison-546ILGLW.cjs.map} +1 -1
  7. package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs → ConnectedProductionSetDialog-LHB4VQWC.cjs} +3 -3
  8. package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs.map → ConnectedProductionSetDialog-LHB4VQWC.cjs.map} +1 -1
  9. package/dist/{ConnectedStreamedWordArtifact-KQSHCA75.cjs → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs} +19 -19
  10. package/dist/{ConnectedStreamedWordArtifact-KQSHCA75.cjs.map → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs.map} +1 -1
  11. package/dist/{DocumentReviewCard-OCPFVMLD.cjs → DocumentReviewCard-ZSBZBGFK.cjs} +15 -15
  12. package/dist/{DocumentReviewCard-OCPFVMLD.cjs.map → DocumentReviewCard-ZSBZBGFK.cjs.map} +1 -1
  13. package/dist/{FilesViewerDialog-BAGOEMXW.cjs → FilesViewerDialog-6UKR5WEF.cjs} +44 -44
  14. package/dist/{FilesViewerDialog-BAGOEMXW.cjs.map → FilesViewerDialog-6UKR5WEF.cjs.map} +1 -1
  15. package/dist/{NativeDocxEditor-EJEIJDOC.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
  16. package/dist/{NativeDocxEditor-EJEIJDOC.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
  17. package/dist/{WorkspaceTableView-IMAZICIZ.cjs → WorkspaceTableView-J3C6VH4T.cjs} +8 -8
  18. package/dist/{WorkspaceTableView-IMAZICIZ.cjs.map → WorkspaceTableView-J3C6VH4T.cjs.map} +1 -1
  19. package/dist/agents/index.cjs +297 -297
  20. package/dist/{ai-7U4B4CVF.cjs → ai-IM4A23YT.cjs} +24 -24
  21. package/dist/ai-IM4A23YT.cjs.map +1 -0
  22. package/dist/calls/index.cjs +121 -121
  23. package/dist/chat/DraftingDocChip.d.ts +3 -1
  24. package/dist/chat/DraftingDocChip.js +7 -4
  25. package/dist/chat/DraftingDocChip.js.map +2 -2
  26. package/dist/chat/index.cjs +37 -37
  27. package/dist/{chunk-4ED7CNOX.cjs → chunk-2CSLFAGF.cjs} +430 -150
  28. package/dist/chunk-2CSLFAGF.cjs.map +1 -0
  29. package/dist/{chunk-Q6DQGGP4.cjs → chunk-325GVZE6.cjs} +3 -3
  30. package/dist/{chunk-Q6DQGGP4.cjs.map → chunk-325GVZE6.cjs.map} +1 -1
  31. package/dist/{chunk-LFRNBT2I.cjs → chunk-557MJ4IH.cjs} +20 -20
  32. package/dist/{chunk-LFRNBT2I.cjs.map → chunk-557MJ4IH.cjs.map} +1 -1
  33. package/dist/{chunk-JSQQV23D.cjs → chunk-6UTKM5AB.cjs} +3 -3
  34. package/dist/{chunk-JSQQV23D.cjs.map → chunk-6UTKM5AB.cjs.map} +1 -1
  35. package/dist/{chunk-H5OLHP2U.cjs → chunk-7OPOPYV6.cjs} +3 -3
  36. package/dist/{chunk-H5OLHP2U.cjs.map → chunk-7OPOPYV6.cjs.map} +1 -1
  37. package/dist/{chunk-AHT6DQNI.cjs → chunk-B2HNNG25.cjs} +50 -50
  38. package/dist/{chunk-AHT6DQNI.cjs.map → chunk-B2HNNG25.cjs.map} +1 -1
  39. package/dist/{chunk-WW6LXQY6.cjs → chunk-B3LZITVF.cjs} +12 -12
  40. package/dist/{chunk-WW6LXQY6.cjs.map → chunk-B3LZITVF.cjs.map} +1 -1
  41. package/dist/{chunk-V5IMYLYK.cjs → chunk-BQ5RIWWT.cjs} +3 -3
  42. package/dist/{chunk-V5IMYLYK.cjs.map → chunk-BQ5RIWWT.cjs.map} +1 -1
  43. package/dist/{chunk-INEPPS4H.cjs → chunk-COD5ENHK.cjs} +4 -4
  44. package/dist/{chunk-INEPPS4H.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
  45. package/dist/{chunk-MC4F2URI.cjs → chunk-CPG7II4E.cjs} +28 -28
  46. package/dist/{chunk-MC4F2URI.cjs.map → chunk-CPG7II4E.cjs.map} +1 -1
  47. package/dist/{chunk-7XT5B2DZ.cjs → chunk-CPR6EHG7.cjs} +47 -47
  48. package/dist/{chunk-7XT5B2DZ.cjs.map → chunk-CPR6EHG7.cjs.map} +1 -1
  49. package/dist/{chunk-3U36VYMD.cjs → chunk-DDIW4HLU.cjs} +27 -27
  50. package/dist/{chunk-3U36VYMD.cjs.map → chunk-DDIW4HLU.cjs.map} +1 -1
  51. package/dist/chunk-HB2O4THB.cjs +18 -0
  52. package/dist/{chunk-ZZA756I4.cjs.map → chunk-HB2O4THB.cjs.map} +1 -1
  53. package/dist/{chunk-IFOGBMAE.cjs → chunk-KLMNCBLY.cjs} +9 -6
  54. package/dist/chunk-KLMNCBLY.cjs.map +1 -0
  55. package/dist/{chunk-TDN33HSK.cjs → chunk-KTQOGT2L.cjs} +6 -6
  56. package/dist/{chunk-TDN33HSK.cjs.map → chunk-KTQOGT2L.cjs.map} +1 -1
  57. package/dist/{chunk-UUENH4BJ.cjs → chunk-KXIRVKCJ.cjs} +3 -3
  58. package/dist/{chunk-UUENH4BJ.cjs.map → chunk-KXIRVKCJ.cjs.map} +1 -1
  59. package/dist/{chunk-436I7PQL.cjs → chunk-NIE3N6OM.cjs} +9 -9
  60. package/dist/{chunk-436I7PQL.cjs.map → chunk-NIE3N6OM.cjs.map} +1 -1
  61. package/dist/{chunk-XKDUPU7B.cjs → chunk-NJCK6V6U.cjs} +4 -4
  62. package/dist/{chunk-XKDUPU7B.cjs.map → chunk-NJCK6V6U.cjs.map} +1 -1
  63. package/dist/{chunk-5QUL5BZO.cjs → chunk-NNUK5ZM7.cjs} +4 -4
  64. package/dist/{chunk-5QUL5BZO.cjs.map → chunk-NNUK5ZM7.cjs.map} +1 -1
  65. package/dist/{chunk-4NPCDS2X.cjs → chunk-NY3YUCOW.cjs} +3 -3
  66. package/dist/{chunk-4NPCDS2X.cjs.map → chunk-NY3YUCOW.cjs.map} +1 -1
  67. package/dist/{chunk-6DCIZA3X.cjs → chunk-OEREKAAP.cjs} +75 -75
  68. package/dist/{chunk-6DCIZA3X.cjs.map → chunk-OEREKAAP.cjs.map} +1 -1
  69. package/dist/{chunk-3ODEWSRO.cjs → chunk-P77YTTJ3.cjs} +4 -4
  70. package/dist/{chunk-3ODEWSRO.cjs.map → chunk-P77YTTJ3.cjs.map} +1 -1
  71. package/dist/{chunk-3R6YHJ3G.cjs → chunk-QHOHDNBU.cjs} +6 -6
  72. package/dist/{chunk-3R6YHJ3G.cjs.map → chunk-QHOHDNBU.cjs.map} +1 -1
  73. package/dist/{chunk-LYTIQQQ2.cjs → chunk-R7CJEIA5.cjs} +3 -3
  74. package/dist/{chunk-LYTIQQQ2.cjs.map → chunk-R7CJEIA5.cjs.map} +1 -1
  75. package/dist/{chunk-MGQSLMTC.cjs → chunk-SB4M3ITT.cjs} +239 -85
  76. package/dist/chunk-SB4M3ITT.cjs.map +1 -0
  77. package/dist/{chunk-2W5E62EY.cjs → chunk-SGYSDABK.cjs} +6 -6
  78. package/dist/{chunk-2W5E62EY.cjs.map → chunk-SGYSDABK.cjs.map} +1 -1
  79. package/dist/{chunk-UNDQYTRF.cjs → chunk-T23UTIRI.cjs} +6 -6
  80. package/dist/{chunk-UNDQYTRF.cjs.map → chunk-T23UTIRI.cjs.map} +1 -1
  81. package/dist/{chunk-E4BLRF2L.cjs → chunk-TDO5UWXF.cjs} +5 -5
  82. package/dist/{chunk-E4BLRF2L.cjs.map → chunk-TDO5UWXF.cjs.map} +1 -1
  83. package/dist/{chunk-4IOYQLKG.cjs → chunk-TP5PGWIO.cjs} +3 -3
  84. package/dist/{chunk-4IOYQLKG.cjs.map → chunk-TP5PGWIO.cjs.map} +1 -1
  85. package/dist/{chunk-7X3FS5HQ.cjs → chunk-TT4IF52H.cjs} +35 -35
  86. package/dist/{chunk-7X3FS5HQ.cjs.map → chunk-TT4IF52H.cjs.map} +1 -1
  87. package/dist/{chunk-NHHEMBXQ.cjs → chunk-VGCTYTEW.cjs} +22 -14
  88. package/dist/chunk-VGCTYTEW.cjs.map +1 -0
  89. package/dist/{chunk-HM5L4SBC.cjs → chunk-VKH3BEZE.cjs} +3 -3
  90. package/dist/{chunk-HM5L4SBC.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
  91. package/dist/{chunk-GQXPNIRE.cjs → chunk-WAV762GP.cjs} +6 -6
  92. package/dist/{chunk-GQXPNIRE.cjs.map → chunk-WAV762GP.cjs.map} +1 -1
  93. package/dist/{chunk-MZ2KZXNU.cjs → chunk-WXUU3COI.cjs} +3 -3
  94. package/dist/{chunk-MZ2KZXNU.cjs.map → chunk-WXUU3COI.cjs.map} +1 -1
  95. package/dist/{chunk-BW5MF464.cjs → chunk-XKVPSOKP.cjs} +4 -4
  96. package/dist/{chunk-BW5MF464.cjs.map → chunk-XKVPSOKP.cjs.map} +1 -1
  97. package/dist/{chunk-57EE6CMW.cjs → chunk-Y24V6HPR.cjs} +15 -15
  98. package/dist/{chunk-57EE6CMW.cjs.map → chunk-Y24V6HPR.cjs.map} +1 -1
  99. package/dist/{chunk-ET3NVY27.cjs → chunk-YGBHY67W.cjs} +5 -5
  100. package/dist/{chunk-ET3NVY27.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
  101. package/dist/{chunk-7TEUGFIL.cjs → chunk-YGXOKB5Z.cjs} +4 -4
  102. package/dist/{chunk-7TEUGFIL.cjs.map → chunk-YGXOKB5Z.cjs.map} +1 -1
  103. package/dist/connect/docx.cjs +23 -23
  104. package/dist/connect/index.cjs +1231 -1069
  105. package/dist/connect/index.cjs.map +1 -1
  106. package/dist/connect/viewer.cjs +33 -33
  107. package/dist/connection/conversation/ConnectedConversation.js +143 -55
  108. package/dist/connection/conversation/ConnectedConversation.js.map +2 -2
  109. package/dist/connection/conversation/ConversationSendButton.d.ts +1 -0
  110. package/dist/connection/conversation/ConversationSendButton.js +3 -2
  111. package/dist/connection/conversation/ConversationSendButton.js.map +2 -2
  112. package/dist/connection/conversation/DocumentTargetNotice.d.ts +7 -0
  113. package/dist/connection/conversation/DocumentTargetNotice.js +45 -0
  114. package/dist/connection/conversation/DocumentTargetNotice.js.map +7 -0
  115. package/dist/connection/conversation/documentSwitch.d.ts +9 -0
  116. package/dist/connection/conversation/documentSwitch.js +40 -0
  117. package/dist/connection/conversation/documentSwitch.js.map +7 -0
  118. package/dist/connection/docx/ConnectedNativeDocxEditor.js +10 -2
  119. package/dist/connection/docx/ConnectedNativeDocxEditor.js.map +2 -2
  120. package/dist/connection/viewer/ConnectedDocumentViewer.js +124 -21
  121. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  122. package/dist/connection/viewer/VersionDropdown.d.ts +9 -0
  123. package/dist/connection/viewer/VersionDropdown.js +39 -0
  124. package/dist/connection/viewer/VersionDropdown.js.map +7 -0
  125. package/dist/connection/viewer/ViewerPdfPane.js +4 -1
  126. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  127. package/dist/connection/viewer/useViewerBlobs.d.ts +3 -1
  128. package/dist/connection/viewer/useViewerBlobs.js +14 -8
  129. package/dist/connection/viewer/useViewerBlobs.js.map +2 -2
  130. package/dist/connection/viewer/useViewerTabs.js +10 -0
  131. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  132. package/dist/dashboards/index.cjs +1 -1
  133. package/dist/docx/DocxCommandMenu.d.ts +8 -0
  134. package/dist/docx/DocxCommandMenu.js +202 -0
  135. package/dist/docx/DocxCommandMenu.js.map +7 -0
  136. package/dist/docx/NativeDocxEditor.d.ts +4 -2
  137. package/dist/docx/NativeDocxEditor.js +54 -13
  138. package/dist/docx/NativeDocxEditor.js.map +2 -2
  139. package/dist/docx/RibbonMenu.d.ts +3 -1
  140. package/dist/docx/RibbonMenu.js +10 -3
  141. package/dist/docx/RibbonMenu.js.map +2 -2
  142. package/dist/docx/RibbonOverflow.d.ts +3 -0
  143. package/dist/docx/RibbonOverflow.js +24 -1
  144. package/dist/docx/RibbonOverflow.js.map +2 -2
  145. package/dist/docx/index.cjs +38 -38
  146. package/dist/docx/signatures/SignatureFields.d.ts +5 -1
  147. package/dist/docx/signatures/SignatureFields.js +57 -10
  148. package/dist/docx/signatures/SignatureFields.js.map +2 -2
  149. package/dist/embed/index.cjs +38 -38
  150. package/dist/files/index.cjs +224 -224
  151. package/dist/index.cjs +1731 -1731
  152. package/dist/settings/index.cjs +147 -147
  153. package/dist/shell/index.cjs +90 -90
  154. package/dist/site/index.cjs +5 -5
  155. package/dist/studio/index.cjs +27 -27
  156. package/dist/styles.css +1 -1
  157. package/dist/workflow-canvas/index.cjs +54 -54
  158. package/node_modules/@arbidocs/coedit/package.json +1 -1
  159. package/package.json +5 -5
  160. package/src/docx/styles.css +94 -0
  161. package/dist/ai-7U4B4CVF.cjs.map +0 -1
  162. package/dist/chunk-4ED7CNOX.cjs.map +0 -1
  163. package/dist/chunk-IFOGBMAE.cjs.map +0 -1
  164. package/dist/chunk-MGQSLMTC.cjs.map +0 -1
  165. package/dist/chunk-NHHEMBXQ.cjs.map +0 -1
  166. package/dist/chunk-ZZA756I4.cjs +0 -18
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/conversation/ConversationSendButton.tsx"],
4
- "sourcesContent": ["import { memo } from 'react'\nimport { assistantLabels, selectDraft, useArbiSessionState } from '@arbidocs/react'\nimport { hasMessageBody, useAssistantName } from '@arbidocs/react/shell'\nimport { ComposerSend } from '../../chat/Composer'\n\nexport interface ConversationSendButtonProps {\n onClick: () => void\n /** The thread ends in a question with no answer: an empty composer offers to retry it. */\n hasOrphanedMessage: boolean\n}\n\n/**\n * The composer's send button. It subscribes to the draft itself, so the conversation does not\n * re-render on every keystroke.\n *\n * Only an empty draft disables it. A failed send never does: the alert above the composer offers\n * Retry, and a new message must still go out (it replies past the failed turn).\n */\nexport const ConversationSendButton = memo(function ConversationSendButton({\n onClick,\n hasOrphanedMessage,\n}: ConversationSendButtonProps) {\n const draftMessage = useArbiSessionState(selectDraft)\n // The assistant's name alone (a shared thread's starting draft) is not a message.\n const assistantName = useAssistantName()\n const recipients = assistantLabels(assistantName)\n\n // Show retry icon when orphaned and no draft, send icon otherwise\n const showRetryIcon = hasOrphanedMessage && draftMessage === ''\n\n return (\n <ComposerSend\n onSend={onClick}\n isRetry={showRetryIcon}\n disabled={!showRetryIcon && !hasMessageBody(draftMessage, recipients)}\n />\n )\n})\n"],
5
- "mappings": ";AA+BI;AA/BJ,SAAS,YAAY;AACrB,SAAS,iBAAiB,aAAa,2BAA2B;AAClE,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,oBAAoB;AAetB,MAAM,yBAAyB,KAAK,SAASA,wBAAuB;AAAA,EACzE;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,eAAe,oBAAoB,WAAW;AAEpD,QAAM,gBAAgB,iBAAiB;AACvC,QAAM,aAAa,gBAAgB,aAAa;AAGhD,QAAM,gBAAgB,sBAAsB,iBAAiB;AAE7D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU,CAAC,iBAAiB,CAAC,eAAe,cAAc,UAAU;AAAA;AAAA,EACtE;AAEJ,CAAC;",
4
+ "sourcesContent": ["import { memo } from 'react'\nimport { assistantLabels, selectDraft, useArbiSessionState } from '@arbidocs/react'\nimport { hasMessageBody, useAssistantName } from '@arbidocs/react/shell'\nimport { ComposerSend } from '../../chat/Composer'\n\nexport interface ConversationSendButtonProps {\n onClick: () => void\n /** The thread ends in a question with no answer: an empty composer offers to retry it. */\n hasOrphanedMessage: boolean\n disabled?: boolean\n}\n\n/**\n * The composer's send button. It subscribes to the draft itself, so the conversation does not\n * re-render on every keystroke.\n *\n * Only an empty draft disables it. A failed send never does: the alert above the composer offers\n * Retry, and a new message must still go out (it replies past the failed turn).\n */\nexport const ConversationSendButton = memo(function ConversationSendButton({\n onClick,\n hasOrphanedMessage,\n disabled = false,\n}: ConversationSendButtonProps) {\n const draftMessage = useArbiSessionState(selectDraft)\n // The assistant's name alone (a shared thread's starting draft) is not a message.\n const assistantName = useAssistantName()\n const recipients = assistantLabels(assistantName)\n\n // Show retry icon when orphaned and no draft, send icon otherwise\n const showRetryIcon = hasOrphanedMessage && draftMessage === ''\n\n return (\n <ComposerSend\n onSend={onClick}\n isRetry={showRetryIcon}\n disabled={disabled || (!showRetryIcon && !hasMessageBody(draftMessage, recipients))}\n />\n )\n})\n"],
5
+ "mappings": ";AAiCI;AAjCJ,SAAS,YAAY;AACrB,SAAS,iBAAiB,aAAa,2BAA2B;AAClE,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,oBAAoB;AAgBtB,MAAM,yBAAyB,KAAK,SAASA,wBAAuB;AAAA,EACzE;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAAgC;AAC9B,QAAM,eAAe,oBAAoB,WAAW;AAEpD,QAAM,gBAAgB,iBAAiB;AACvC,QAAM,aAAa,gBAAgB,aAAa;AAGhD,QAAM,gBAAgB,sBAAsB,iBAAiB;AAE7D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU,YAAa,CAAC,iBAAiB,CAAC,eAAe,cAAc,UAAU;AAAA;AAAA,EACnF;AAEJ,CAAC;",
6
6
  "names": ["ConversationSendButton"]
7
7
  }
@@ -0,0 +1,7 @@
1
+ /** Clarify which document a turn will edit when the viewer shows another document. */
2
+ export declare function DocumentTargetNotice({ target, visible, onSwitch, disabled, }: {
3
+ target: string;
4
+ visible: string;
5
+ onSwitch?: () => void;
6
+ disabled?: boolean;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ function DocumentTargetNotice({
4
+ target,
5
+ visible,
6
+ onSwitch,
7
+ disabled = false
8
+ }) {
9
+ return /* @__PURE__ */ jsxs(
10
+ "div",
11
+ {
12
+ className: "mx-3 mb-2 rounded-md border border-amber-400/50 bg-amber-50 p-2 text-sm text-foreground dark:bg-amber-950",
13
+ role: "note",
14
+ children: [
15
+ /* @__PURE__ */ jsxs("p", { children: [
16
+ "This thread will edit ",
17
+ /* @__PURE__ */ jsx("strong", { children: target }),
18
+ ". The viewer shows ",
19
+ /* @__PURE__ */ jsx("strong", { children: visible }),
20
+ "."
21
+ ] }),
22
+ onSwitch ? /* @__PURE__ */ jsxs(Fragment, { children: [
23
+ /* @__PURE__ */ jsx("p", { children: "Switching changes the thread\u2019s document for everyone in the thread." }),
24
+ /* @__PURE__ */ jsxs(
25
+ "button",
26
+ {
27
+ type: "button",
28
+ className: "mt-1 underline disabled:opacity-50",
29
+ onClick: onSwitch,
30
+ disabled,
31
+ children: [
32
+ "Switch this thread to ",
33
+ visible
34
+ ]
35
+ }
36
+ )
37
+ ] }) : /* @__PURE__ */ jsx("p", { children: "The visible document is unavailable; it cannot be attached here." })
38
+ ]
39
+ }
40
+ );
41
+ }
42
+ export {
43
+ DocumentTargetNotice
44
+ };
45
+ //# sourceMappingURL=DocumentTargetNotice.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/connection/conversation/DocumentTargetNotice.tsx"],
4
+ "sourcesContent": ["/** Clarify which document a turn will edit when the viewer shows another document. */\nexport function DocumentTargetNotice({\n target,\n visible,\n onSwitch,\n disabled = false,\n}: {\n target: string\n visible: string\n onSwitch?: () => void\n disabled?: boolean\n}) {\n return (\n <div\n className=\"mx-3 mb-2 rounded-md border border-amber-400/50 bg-amber-50 p-2 text-sm text-foreground dark:bg-amber-950\"\n role=\"note\"\n >\n <p>\n This thread will edit <strong>{target}</strong>. The viewer shows <strong>{visible}</strong>\n .\n </p>\n {onSwitch ? (\n <>\n <p>Switching changes the thread\u2019s document for everyone in the thread.</p>\n <button\n type=\"button\"\n className=\"mt-1 underline disabled:opacity-50\"\n onClick={onSwitch}\n disabled={disabled}\n >\n Switch this thread to {visible}\n </button>\n </>\n ) : (\n <p>The visible document is unavailable; it cannot be attached here.</p>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAiBM,SAKE,UAJsB,KADxB;AAhBC,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAKG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAK;AAAA,MAEL;AAAA,6BAAC,OAAE;AAAA;AAAA,UACqB,oBAAC,YAAQ,kBAAO;AAAA,UAAS;AAAA,UAAmB,oBAAC,YAAQ,mBAAQ;AAAA,UAAS;AAAA,WAE9F;AAAA,QACC,WACC,iCACE;AAAA,8BAAC,OAAE,sFAAmE;AAAA,UACtE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cACT;AAAA,cACD;AAAA;AAAA,gBACwB;AAAA;AAAA;AAAA,UACzB;AAAA,WACF,IAEA,oBAAC,OAAE,8EAAgE;AAAA;AAAA;AAAA,EAEvE;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,9 @@
1
+ /** Guard a send until an explicit thread-document switch has settled. */
2
+ export declare function createDocumentSwitchGuard(): {
3
+ isPending: () => boolean;
4
+ hasFailed: () => boolean;
5
+ acknowledgeFailure: () => void;
6
+ switch(bind: () => Promise<boolean>, onPending: (pending: boolean) => void): Promise<boolean>;
7
+ };
8
+ /** Only the initiating conversation may receive the result of its pending switch. */
9
+ export declare function switchInScope(guard: ReturnType<typeof createDocumentSwitchGuard>, bind: () => Promise<boolean>, isCurrent: () => boolean, onPending: (pending: boolean) => void, onFailure: () => void): Promise<void>;
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ function createDocumentSwitchGuard() {
3
+ let pending = false;
4
+ let failed = false;
5
+ return {
6
+ isPending: () => pending,
7
+ hasFailed: () => failed,
8
+ acknowledgeFailure: () => {
9
+ failed = false;
10
+ },
11
+ async switch(bind, onPending) {
12
+ if (pending) return false;
13
+ pending = true;
14
+ failed = false;
15
+ onPending(true);
16
+ try {
17
+ const ok = await bind();
18
+ failed = !ok;
19
+ return ok;
20
+ } catch (error) {
21
+ failed = true;
22
+ throw error;
23
+ } finally {
24
+ pending = false;
25
+ onPending(false);
26
+ }
27
+ }
28
+ };
29
+ }
30
+ async function switchInScope(guard, bind, isCurrent, onPending, onFailure) {
31
+ const ok = await guard.switch(bind, (pending) => {
32
+ if (isCurrent()) onPending(pending);
33
+ });
34
+ if (!ok && isCurrent()) onFailure();
35
+ }
36
+ export {
37
+ createDocumentSwitchGuard,
38
+ switchInScope
39
+ };
40
+ //# sourceMappingURL=documentSwitch.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/connection/conversation/documentSwitch.ts"],
4
+ "sourcesContent": ["/** Guard a send until an explicit thread-document switch has settled. */\nexport function createDocumentSwitchGuard() {\n let pending = false\n let failed = false\n return {\n isPending: () => pending,\n hasFailed: () => failed,\n acknowledgeFailure: () => {\n failed = false\n },\n async switch(bind: () => Promise<boolean>, onPending: (pending: boolean) => void) {\n if (pending) return false\n pending = true\n failed = false\n onPending(true)\n try {\n const ok = await bind()\n failed = !ok\n return ok\n } catch (error) {\n failed = true\n throw error\n } finally {\n pending = false\n onPending(false)\n }\n },\n }\n}\n\n/** Only the initiating conversation may receive the result of its pending switch. */\nexport async function switchInScope(\n guard: ReturnType<typeof createDocumentSwitchGuard>,\n bind: () => Promise<boolean>,\n isCurrent: () => boolean,\n onPending: (pending: boolean) => void,\n onFailure: () => void\n) {\n const ok = await guard.switch(bind, (pending) => {\n if (isCurrent()) onPending(pending)\n })\n if (!ok && isCurrent()) onFailure()\n}\n"],
5
+ "mappings": ";AACO,SAAS,4BAA4B;AAC1C,MAAI,UAAU;AACd,MAAI,SAAS;AACb,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,IACjB,oBAAoB,MAAM;AACxB,eAAS;AAAA,IACX;AAAA,IACA,MAAM,OAAO,MAA8B,WAAuC;AAChF,UAAI,QAAS,QAAO;AACpB,gBAAU;AACV,eAAS;AACT,gBAAU,IAAI;AACd,UAAI;AACF,cAAM,KAAK,MAAM,KAAK;AACtB,iBAAS,CAAC;AACV,eAAO;AAAA,MACT,SAAS,OAAO;AACd,iBAAS;AACT,cAAM;AAAA,MACR,UAAE;AACA,kBAAU;AACV,kBAAU,KAAK;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACF;AAGA,eAAsB,cACpB,OACA,MACA,WACA,WACA,WACA;AACA,QAAM,KAAK,MAAM,MAAM,OAAO,MAAM,CAAC,YAAY;AAC/C,QAAI,UAAU,EAAG,WAAU,OAAO;AAAA,EACpC,CAAC;AACD,MAAI,CAAC,MAAM,UAAU,EAAG,WAAU;AACpC;",
6
+ "names": []
7
+ }
@@ -106,8 +106,16 @@ function useConnectedNativeDocxAdapter(fontBaseUrl = "/native-docx/fonts") {
106
106
  onDirtyChange: support.onDirtyChange,
107
107
  // The document's row moves to the saved version in place: through the host when it keeps
108
108
  // the lists (its document tools refresh them), else here.
109
- onVersionSaved: async (id) => {
110
- await (onDocumentsChanged ? onDocumentsChanged([id], "version") : refreshDocuments(queries, arbi, [id]));
109
+ onVersionSaved: async (id, version) => {
110
+ if (onDocumentsChanged) await onDocumentsChanged([id], "version");
111
+ if (version || !onDocumentsChanged) {
112
+ const fresh = await refreshDocuments(queries, arbi, [id]);
113
+ if (version && !fresh.some((doc) => doc.external_id === id && (doc.current_version ?? 0) >= version)) {
114
+ throw new Error(
115
+ "The version was saved, but its current status could not be confirmed. Please try again."
116
+ );
117
+ }
118
+ }
111
119
  },
112
120
  notify,
113
121
  mentions: members?.map(({ user: member }) => ({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/docx/ConnectedNativeDocxEditor.tsx"],
4
- "sourcesContent": ["import { useMemo, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { refreshDocuments, useArbi, useWorkspaceUsers } from '@arbidocs/react'\nimport {\n fetchSavedSignature,\n storeSavedSignature,\n useOptionalDocumentTools,\n} from '@arbidocs/react/document-tools'\nimport type { NativeDocxAdapter, NativeDocxEditorProps } from '../../docx/NativeDocxEditor'\nimport { NativeDocxEditor } from '../../docx/lazy'\nimport { useRegisterOpenDocument } from '@arbidocs/react/shell'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../ConnectionProvider'\nimport { useDocxCommentTarget, useNativeDocxSupport } from './support'\nimport { useConnectedDocxReferences } from './useConnectedDocxReferences'\nimport { useConnectedHouseTemplate } from './useConnectedHouseTemplate'\n\nexport type ConnectedNativeDocxEditorProps = Omit<NativeDocxEditorProps, 'adapter' | 'compact'> & {\n fontBaseUrl?: string\n}\n\n/**\n * The native Word editor on the signed-in ARBI session, under any host (`defaultHost`'s sign-in\n * layer, or the host's own `arbi` and session state). Until a live session has opened, a failure to\n * open one falls back to the saved copy, read-only, so the document is still readable; later token\n * refreshes are not guarded (switching modes would drop unsaved edits).\n */\nexport function ConnectedNativeDocxEditor({\n fontBaseUrl = '/native-docx/fonts',\n ...props\n}: ConnectedNativeDocxEditorProps) {\n const adapter = useConnectedNativeDocxAdapter(fontBaseUrl)\n const { workspaceId } = useConnectedWorkspace()\n const commentTarget = useDocxCommentTarget()\n const [openFailed, setOpenFailed] = useState(false)\n const hasOpened = useRef(false)\n const guardedAdapter = useMemo<NativeDocxAdapter>(\n () => ({\n ...adapter,\n open: async (documentId) => {\n try {\n const session = await adapter.open(documentId)\n hasOpened.current = true\n return session\n } catch (error) {\n if (!hasOpened.current) setOpenFailed(true)\n throw error\n }\n },\n }),\n [adapter]\n )\n // Drafting mode: the saved Word document being edited is what the chat is about. A history\n // snapshot, a streamed preview, an unsaved draft and an embedded body field are not.\n const live = !props.snapshot && !props.stream && !props.draftContent\n useRegisterOpenDocument({ documentId: live ? props.documentId : null, workspaceId })\n const initialCommentId =\n props.initialCommentId ??\n (commentTarget?.documentId === props.documentId ? commentTarget.commentId : undefined)\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {openFailed && (\n <p role=\"status\" className=\"text-muted-foreground border-b px-3 py-2 text-xs\">\n Co-editing isn&apos;t available for this document right now, so this is a read-only copy\n of the last saved version.\n </p>\n )}\n <div className=\"min-h-0 flex-1\">\n <NativeDocxEditor\n {...props}\n snapshot={props.snapshot || openFailed}\n initialCommentId={initialCommentId}\n adapter={guardedAdapter}\n />\n </div>\n </div>\n )\n}\n\n/** The access token changed (a refresh): the live room is told the new one. */\nfunction tokenChanges(arbi: ReturnType<typeof useArbi>) {\n return (listener: () => void) => {\n if (!arbi.isLoggedIn) return () => {}\n const session = arbi.getClient().session\n let token = session.getState().accessToken\n return session.subscribe((state) => {\n if (state.accessToken === token) return\n token = state.accessToken\n listener()\n })\n }\n}\n\n/**\n * The native Word adapter on the signed-in session: the editor transport, the people to mention,\n * cross-references, the house template, and the host's extras (its host config's `docx`).\n */\nexport function useConnectedNativeDocxAdapter(fontBaseUrl = '/native-docx/fonts') {\n const arbi = useArbi()\n const { workspaceId, live, user, ensureWorkspaceOpen } = useConnectedWorkspace()\n const queries = useQueryClient()\n const { notify } = useBlocksEnvironment()\n const tools = useOptionalDocumentTools()\n const support = useNativeDocxSupport()\n const references = useConnectedDocxReferences()\n const houseTemplate = useConnectedHouseTemplate()\n const { data: members } = useWorkspaceUsers(workspaceId ?? undefined, {\n enabled: live && !!workspaceId,\n beforeFetch: ensureWorkspaceOpen,\n })\n const onDocumentsChanged = tools?.onDocumentsChanged\n // Tracked changes and comments are authored by the user's first name.\n const author = (live && arbi.user.profile()?.givenName) || user?.name || 'You'\n const adapter = useMemo<NativeDocxAdapter>(\n () => ({\n request: async (path, options) => {\n await ensureWorkspaceOpen()\n return arbi.editor.request(path, options)\n },\n open: async (id) => {\n await ensureWorkspaceOpen()\n return (\n await arbi.editor.request(`/${encodeURIComponent(id)}/session`, { method: 'POST' })\n ).json()\n },\n save: async (id, state) =>\n (\n await arbi.editor.request(`/${encodeURIComponent(id)}/save`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ state }),\n })\n ).json(),\n loadFonts: () => import('../../docx/fonts').then((m) => m.loadDocxFonts(fontBaseUrl)),\n baseUrl: arbi.getConnectionInfo()?.baseUrl || window.location.origin,\n author,\n subscribeTokenChanges: tokenChanges(arbi),\n onDirtyChange: support.onDirtyChange,\n // The document's row moves to the saved version in place: through the host when it keeps\n // the lists (its document tools refresh them), else here.\n onVersionSaved: async (id) => {\n await (onDocumentsChanged\n ? onDocumentsChanged([id], 'version')\n : refreshDocuments(queries, arbi, [id]))\n },\n notify,\n mentions: members?.map(({ user: member }) => ({\n id: member.external_id,\n name: [member.given_name, member.family_name].filter(Boolean).join(' '),\n kind: member.external_id.startsWith('agt-') ? 'agent' : 'human',\n })),\n savedSignature: {\n load: () => fetchSavedSignature(arbi.getClient().fetch),\n save: (signature) => storeSavedSignature(arbi.getClient().fetch, signature),\n defaultName: user?.name ?? '',\n },\n signatureSigners: members\n ?.filter(({ user: member }) => member.external_id.startsWith('usr-'))\n .map(({ user: member }) => ({\n email: member.email,\n name: [member.given_name, member.family_name].filter(Boolean).join(' '),\n })),\n requestAgent: async (id, request) => {\n const response = await arbi.editor.request(`/${encodeURIComponent(id)}/mentions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n comment_id: request.commentId,\n instruction: request.instruction,\n request_id: request.requestId,\n recipient_ids: request.recipientIds,\n }),\n })\n const delivery = (await response.json()) as { response_ids: string[] }\n notify('Mention delivered.', 'success')\n return { responseIds: delivery.response_ids || [] }\n },\n getAgentStatus: async (responseId) => (await arbi.assistant.getResponse(responseId)).status,\n definitions: support.definitions,\n references,\n imageGeneration: support.imageGeneration,\n houseTemplate,\n }),\n [\n arbi,\n author,\n members,\n ensureWorkspaceOpen,\n fontBaseUrl,\n queries,\n notify,\n onDocumentsChanged,\n support,\n references,\n houseTemplate,\n user?.name,\n ]\n )\n return adapter\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { useMemo, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { refreshDocuments, useArbi, useWorkspaceUsers } from '@arbidocs/react'\nimport {\n fetchSavedSignature,\n storeSavedSignature,\n useOptionalDocumentTools,\n} from '@arbidocs/react/document-tools'\nimport type { NativeDocxAdapter, NativeDocxEditorProps } from '../../docx/NativeDocxEditor'\nimport { NativeDocxEditor } from '../../docx/lazy'\nimport { useRegisterOpenDocument } from '@arbidocs/react/shell'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../ConnectionProvider'\nimport { useDocxCommentTarget, useNativeDocxSupport } from './support'\nimport { useConnectedDocxReferences } from './useConnectedDocxReferences'\nimport { useConnectedHouseTemplate } from './useConnectedHouseTemplate'\n\nexport type ConnectedNativeDocxEditorProps = Omit<NativeDocxEditorProps, 'adapter' | 'compact'> & {\n fontBaseUrl?: string\n}\n\n/**\n * The native Word editor on the signed-in ARBI session, under any host (`defaultHost`'s sign-in\n * layer, or the host's own `arbi` and session state). Until a live session has opened, a failure to\n * open one falls back to the saved copy, read-only, so the document is still readable; later token\n * refreshes are not guarded (switching modes would drop unsaved edits).\n */\nexport function ConnectedNativeDocxEditor({\n fontBaseUrl = '/native-docx/fonts',\n ...props\n}: ConnectedNativeDocxEditorProps) {\n const adapter = useConnectedNativeDocxAdapter(fontBaseUrl)\n const { workspaceId } = useConnectedWorkspace()\n const commentTarget = useDocxCommentTarget()\n const [openFailed, setOpenFailed] = useState(false)\n const hasOpened = useRef(false)\n const guardedAdapter = useMemo<NativeDocxAdapter>(\n () => ({\n ...adapter,\n open: async (documentId) => {\n try {\n const session = await adapter.open(documentId)\n hasOpened.current = true\n return session\n } catch (error) {\n if (!hasOpened.current) setOpenFailed(true)\n throw error\n }\n },\n }),\n [adapter]\n )\n // Drafting mode: the saved Word document being edited is what the chat is about. A history\n // snapshot, a streamed preview, an unsaved draft and an embedded body field are not.\n const live = !props.snapshot && !props.stream && !props.draftContent\n useRegisterOpenDocument({ documentId: live ? props.documentId : null, workspaceId })\n const initialCommentId =\n props.initialCommentId ??\n (commentTarget?.documentId === props.documentId ? commentTarget.commentId : undefined)\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {openFailed && (\n <p role=\"status\" className=\"text-muted-foreground border-b px-3 py-2 text-xs\">\n Co-editing isn&apos;t available for this document right now, so this is a read-only copy\n of the last saved version.\n </p>\n )}\n <div className=\"min-h-0 flex-1\">\n <NativeDocxEditor\n {...props}\n snapshot={props.snapshot || openFailed}\n initialCommentId={initialCommentId}\n adapter={guardedAdapter}\n />\n </div>\n </div>\n )\n}\n\n/** The access token changed (a refresh): the live room is told the new one. */\nfunction tokenChanges(arbi: ReturnType<typeof useArbi>) {\n return (listener: () => void) => {\n if (!arbi.isLoggedIn) return () => {}\n const session = arbi.getClient().session\n let token = session.getState().accessToken\n return session.subscribe((state) => {\n if (state.accessToken === token) return\n token = state.accessToken\n listener()\n })\n }\n}\n\n/**\n * The native Word adapter on the signed-in session: the editor transport, the people to mention,\n * cross-references, the house template, and the host's extras (its host config's `docx`).\n */\nexport function useConnectedNativeDocxAdapter(fontBaseUrl = '/native-docx/fonts') {\n const arbi = useArbi()\n const { workspaceId, live, user, ensureWorkspaceOpen } = useConnectedWorkspace()\n const queries = useQueryClient()\n const { notify } = useBlocksEnvironment()\n const tools = useOptionalDocumentTools()\n const support = useNativeDocxSupport()\n const references = useConnectedDocxReferences()\n const houseTemplate = useConnectedHouseTemplate()\n const { data: members } = useWorkspaceUsers(workspaceId ?? undefined, {\n enabled: live && !!workspaceId,\n beforeFetch: ensureWorkspaceOpen,\n })\n const onDocumentsChanged = tools?.onDocumentsChanged\n // Tracked changes and comments are authored by the user's first name.\n const author = (live && arbi.user.profile()?.givenName) || user?.name || 'You'\n const adapter = useMemo<NativeDocxAdapter>(\n () => ({\n request: async (path, options) => {\n await ensureWorkspaceOpen()\n return arbi.editor.request(path, options)\n },\n open: async (id) => {\n await ensureWorkspaceOpen()\n return (\n await arbi.editor.request(`/${encodeURIComponent(id)}/session`, { method: 'POST' })\n ).json()\n },\n save: async (id, state) =>\n (\n await arbi.editor.request(`/${encodeURIComponent(id)}/save`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ state }),\n })\n ).json(),\n loadFonts: () => import('../../docx/fonts').then((m) => m.loadDocxFonts(fontBaseUrl)),\n baseUrl: arbi.getConnectionInfo()?.baseUrl || window.location.origin,\n author,\n subscribeTokenChanges: tokenChanges(arbi),\n onDirtyChange: support.onDirtyChange,\n // The document's row moves to the saved version in place: through the host when it keeps\n // the lists (its document tools refresh them), else here.\n onVersionSaved: async (id, version) => {\n if (onDocumentsChanged) await onDocumentsChanged([id], 'version')\n if (version || !onDocumentsChanged) {\n const fresh = await refreshDocuments(queries, arbi, [id])\n if (\n version &&\n !fresh.some((doc) => doc.external_id === id && (doc.current_version ?? 0) >= version)\n ) {\n throw new Error(\n 'The version was saved, but its current status could not be confirmed. Please try again.'\n )\n }\n }\n },\n notify,\n mentions: members?.map(({ user: member }) => ({\n id: member.external_id,\n name: [member.given_name, member.family_name].filter(Boolean).join(' '),\n kind: member.external_id.startsWith('agt-') ? 'agent' : 'human',\n })),\n savedSignature: {\n load: () => fetchSavedSignature(arbi.getClient().fetch),\n save: (signature) => storeSavedSignature(arbi.getClient().fetch, signature),\n defaultName: user?.name ?? '',\n },\n signatureSigners: members\n ?.filter(({ user: member }) => member.external_id.startsWith('usr-'))\n .map(({ user: member }) => ({\n email: member.email,\n name: [member.given_name, member.family_name].filter(Boolean).join(' '),\n })),\n requestAgent: async (id, request) => {\n const response = await arbi.editor.request(`/${encodeURIComponent(id)}/mentions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n comment_id: request.commentId,\n instruction: request.instruction,\n request_id: request.requestId,\n recipient_ids: request.recipientIds,\n }),\n })\n const delivery = (await response.json()) as { response_ids: string[] }\n notify('Mention delivered.', 'success')\n return { responseIds: delivery.response_ids || [] }\n },\n getAgentStatus: async (responseId) => (await arbi.assistant.getResponse(responseId)).status,\n definitions: support.definitions,\n references,\n imageGeneration: support.imageGeneration,\n houseTemplate,\n }),\n [\n arbi,\n author,\n members,\n ensureWorkspaceOpen,\n fontBaseUrl,\n queries,\n notify,\n onDocumentsChanged,\n support,\n references,\n houseTemplate,\n user?.name,\n ]\n )\n return adapter\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -92,6 +92,7 @@ import { useViewedDocument } from "./useViewedDocument.js";
92
92
  import { useViewerBlobs } from "./useViewerBlobs.js";
93
93
  import { useViewerTabs } from "./useViewerTabs.js";
94
94
  import { useViewerVersions } from "./useViewerVersions.js";
95
+ import { VersionDropdown } from "./VersionDropdown.js";
95
96
  import { ParsedTextView } from "./parsed/ParsedTextView.js";
96
97
  import { ViewerPdfPane } from "./ViewerPdfPane.js";
97
98
  import { ConnectedNativeDocxEditor as NativeDocxEditor } from "../docx/ConnectedNativeDocxEditor.js";
@@ -205,10 +206,15 @@ function DocumentViewerContent({
205
206
  const threadTitle = (id) => conversations.find((c) => c.external_id === id)?.title?.trim() || "Its thread";
206
207
  const madeInId = documentData?.conversation_ext_id ?? null;
207
208
  const madeIn = madeInId ? { id: madeInId, title: threadTitle(madeInId) } : null;
208
- const pdfSnapshotId = snapshotDocumentId && !isDocx && !isArtifact ? snapshotDocumentId : null;
209
+ const pdfSnapshotId = snapshotDocumentId && (!isArtifact || isDocx) ? snapshotDocumentId : null;
209
210
  const shownDocumentId = pdfSnapshotId || documentId;
210
211
  const blobs = useViewerBlobs(shownDocumentId, doc);
211
- const { pdfBlob, xlsxBlob, xlsxError, handleDirectDownload } = blobs;
212
+ const [minimumPdfVersion, setMinimumPdfVersion] = useState(null);
213
+ useEffect(() => setMinimumPdfVersion(null), [documentId]);
214
+ const versionReady = !!pdfSnapshotId || minimumPdfVersion === null || (documentData?.current_version ?? 0) >= minimumPdfVersion;
215
+ const { xlsxBlob, xlsxError, handleDirectDownload } = blobs;
216
+ const pdfBlob = versionReady ? blobs.pdfBlob : null;
217
+ const pdfVerified = !!pdfBlob && blobs.pdfVerified !== false;
212
218
  const [annotating, setAnnotating] = useState(false);
213
219
  const [sharingFile, setSharingFile] = useState(false);
214
220
  useEffect(() => setAnnotating(false), [documentId]);
@@ -216,7 +222,52 @@ function DocumentViewerContent({
216
222
  null
217
223
  );
218
224
  const hasHistory = versions.length > 1 || (documentData?.current_version ?? 1) > 1 || translations.length > 0;
219
- const { activeTab, handleTabChange, viewerTabs } = useViewerTabs(doc, isCompact, hasHistory);
225
+ const {
226
+ activeTab,
227
+ handleTabChange: changeTab,
228
+ viewerTabs
229
+ } = useViewerTabs(doc, isCompact, hasHistory);
230
+ const saveWordRef = useRef(null);
231
+ const transitionPending = useRef(false);
232
+ const transitionKey = JSON.stringify([openedId, doc.workspaceId]);
233
+ const transitionScope = useRef({ key: transitionKey, generation: 0 });
234
+ if (transitionScope.current.key !== transitionKey) {
235
+ transitionScope.current = {
236
+ key: transitionKey,
237
+ generation: transitionScope.current.generation + 1
238
+ };
239
+ }
240
+ useEffect(
241
+ () => () => {
242
+ transitionScope.current.generation += 1;
243
+ },
244
+ []
245
+ );
246
+ const requestViewerTransition = async (transition) => {
247
+ if (transitionPending.current) return false;
248
+ const leavingWord = isDocx && !isDraft && !isStreaming && !snapshotDocumentId && (activeTab === "docx" || isArtifact && !liveKind && activeTab === "edit");
249
+ if (leavingWord) {
250
+ transitionPending.current = true;
251
+ const generation = transitionScope.current.generation;
252
+ try {
253
+ const saved = saveWordRef.current && await saveWordRef.current();
254
+ if (!saved) {
255
+ notify("Could not save the current document. Stay in the editor and try again.", "error");
256
+ return false;
257
+ }
258
+ if (generation !== transitionScope.current.generation) return false;
259
+ if (typeof saved === "number") setMinimumPdfVersion(saved);
260
+ } finally {
261
+ transitionPending.current = false;
262
+ }
263
+ }
264
+ transition();
265
+ return true;
266
+ };
267
+ const handleTabChange = (tab) => {
268
+ if (tab === activeTab) return;
269
+ void requestViewerTransition(() => changeTab(tab));
270
+ };
220
271
  const crop = useImageCrop(
221
272
  documentId,
222
273
  documentData?.file_name,
@@ -226,15 +277,31 @@ function DocumentViewerContent({
226
277
  const [placingSignature, setPlacingSignature] = useState(false);
227
278
  const [signAppearance, setSignAppearance] = useState();
228
279
  const [isSignOpen, setIsSignOpen] = useState(false);
229
- useEffect(() => setPlacingSignature(false), [documentId, snapshotDocumentId]);
280
+ const signingScope = JSON.stringify([
281
+ documentId,
282
+ snapshotDocumentId,
283
+ documentData?.current_version
284
+ ]);
285
+ const signingScopeRef = useRef(signingScope);
286
+ const signingScopeMatches = signingScopeRef.current === signingScope;
287
+ useEffect(() => {
288
+ setPlacingSignature(false);
289
+ setIsSignOpen(false);
290
+ setSignAppearance(void 0);
291
+ signingScopeRef.current = signingScope;
292
+ }, [signingScope]);
230
293
  const [signatureFlow, setSignatureFlow] = useState(null);
231
- useEffect(() => setSignatureFlow(null), [documentId, snapshotDocumentId]);
232
- const { data: signatureStatus } = useDocumentSignatures(shownDocumentId, !isDraft && !liveKind);
294
+ useEffect(() => setSignatureFlow(null), [signingScope]);
295
+ const signatureDocumentId = pdfSnapshotId || (documentData?.current_version ? `${documentId}@v${documentData.current_version}` : documentId);
296
+ const { data: signatureStatus } = useDocumentSignatures(
297
+ signatureDocumentId,
298
+ !isDraft && !liveKind
299
+ );
233
300
  const isCoEditing = !snapshotDocumentId && !compareDocumentId && !isDraft && (activeTab === "docx" && isDocx || activeTab === "edit" && isArtifact && !liveKind && !isStreaming);
234
301
  const currentVersionLabel = isCoEditing ? void 0 : !snapshotDocumentId && !compareDocumentId && (isDocx || isArtifact && !liveKind) ? "Live" : versionLabel(versions, snapshotDocumentId || documentId);
235
302
  const compareVersionLabel = versionLabel(versions, compareDocumentId);
236
303
  const snapshotNumber = findVersion(versions, snapshotDocumentId)?.number;
237
- const pdfSnapshotNumber = pdfSnapshotId ? snapshotNumber : void 0;
304
+ const pdfSnapshotNumber = pdfSnapshotId ? parseVersionRef(pdfSnapshotId).version ?? void 0 : void 0;
238
305
  const isSigned = !!signatureStatus?.signed;
239
306
  const markup = useDocumentMarkup(documentData, pdfSnapshotNumber, isSigned);
240
307
  useEffect(() => {
@@ -314,12 +381,37 @@ function DocumentViewerContent({
314
381
  // A draft's kind replaces the tabs: neither Versions nor the text view means anything
315
382
  // before the first save.
316
383
  /* @__PURE__ */ jsx(ViewerDraftKind, { documentId })
317
- ) : /* @__PURE__ */ jsx(ViewerTabBar, { tabs: viewerTabs, activeId: activeTab, onChange: handleTabChange }),
384
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
385
+ /* @__PURE__ */ jsx(
386
+ ViewerTabBar,
387
+ {
388
+ tabs: viewerTabs.filter((tab) => tab.id !== "versions"),
389
+ activeId: activeTab,
390
+ onChange: handleTabChange
391
+ }
392
+ ),
393
+ (isArtifact || isDocx || hasHistory) && !liveKind && !isComparing && /* @__PURE__ */ jsx(
394
+ VersionDropdown,
395
+ {
396
+ versions,
397
+ activeId: snapshotDocumentId ?? (currentVersionId === documentId && documentData?.current_version ? `${documentId}@v${documentData.current_version}` : currentVersionId),
398
+ isSnapshot: !!snapshotDocumentId,
399
+ onOpen: (id) => {
400
+ void requestViewerTransition(() => {
401
+ setSnapshotDocumentId(id === currentVersionId ? null : id);
402
+ if (activeTab === "versions")
403
+ setActiveTab(isArtifact ? "edit" : isDocx ? "docx" : "pdf");
404
+ });
405
+ },
406
+ onHistory: () => handleTabChange("versions")
407
+ }
408
+ )
409
+ ] }),
318
410
  !isCompact && titleBlock
319
411
  ] });
320
412
  const annotatable = canAnnotate({
321
413
  activeTab,
322
- hasPdf: !!pdfBlob,
414
+ hasPdf: pdfVerified,
323
415
  isImage,
324
416
  isVideo,
325
417
  isAudio,
@@ -335,14 +427,18 @@ function DocumentViewerContent({
335
427
  documentId,
336
428
  hidden: !!signatureFlow,
337
429
  onSign: (request) => {
338
- setAnnotating(false);
339
- setPlacingSignature(false);
340
- if (activeTab !== "pdf") handleTabChange("pdf");
341
- setSignatureFlow({ kind: "sign", request });
430
+ void requestViewerTransition(() => {
431
+ setAnnotating(false);
432
+ setPlacingSignature(false);
433
+ if (activeTab !== "pdf") changeTab("pdf");
434
+ setSignatureFlow({ kind: "sign", request });
435
+ });
342
436
  },
343
437
  onEditDraft: (draft) => {
344
- if (activeTab !== "pdf") handleTabChange("pdf");
345
- setSignatureFlow({ kind: "prepare", draft });
438
+ void requestViewerTransition(() => {
439
+ if (activeTab !== "pdf") changeTab("pdf");
440
+ setSignatureFlow({ kind: "prepare", draft });
441
+ });
346
442
  }
347
443
  }
348
444
  );
@@ -579,7 +675,7 @@ function DocumentViewerContent({
579
675
  ] })
580
676
  ] })
581
677
  ] }),
582
- isSignOpen && pdfBlob && /* @__PURE__ */ jsx(
678
+ isSignOpen && pdfBlob && pdfVerified && signingScopeMatches && /* @__PURE__ */ jsx(
583
679
  SignDocumentDialog,
584
680
  {
585
681
  open: isSignOpen,
@@ -654,9 +750,14 @@ function DocumentViewerContent({
654
750
  }
655
751
  ) }),
656
752
  isCaptureDraft && /* @__PURE__ */ jsx(ViewerCaptureDraft, { documentId }),
657
- !isCaptureDraft && (activeTab === "pdf" || isMedia && activeTab === "html") && !isArtifact && !isComparing && /* @__PURE__ */ jsxs(ViewerPane, { hidden: activeTab !== "pdf", children: [
753
+ !isCaptureDraft && (activeTab === "pdf" || isMedia && activeTab === "html") && (!isArtifact || isDocx && !isDraft && !isStreaming && !liveKind) && !isComparing && /* @__PURE__ */ jsxs(ViewerPane, { hidden: activeTab !== "pdf", children: [
658
754
  /* @__PURE__ */ jsx(DocumentLabelBar, { summaries: labelSummaries }),
659
755
  !isMedia && !isImage && signatureBanner,
756
+ activeTab === "pdf" && pdfBlob && !pdfVerified && /* @__PURE__ */ jsxs(ViewerMessage, { children: [
757
+ "Offline copy: its version cannot be verified. Reconnect before signing.",
758
+ " ",
759
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void blobs.retryPdf(), className: "underline", children: "Retry loading the current PDF" })
760
+ ] }),
660
761
  activeTab === "pdf" && !isMedia && !isImage && /* @__PURE__ */ jsx(
661
762
  MarkupNotices,
662
763
  {
@@ -671,14 +772,14 @@ function DocumentViewerContent({
671
772
  documentId,
672
773
  doc,
673
774
  pdfBlob,
674
- isPdfLoading: blobs.isPdfLoading,
775
+ isPdfLoading: !versionReady || blobs.isPdfLoading,
675
776
  pdfError: blobs.pdfError,
676
777
  onDownload: () => void handleDirectDownload(),
677
778
  viewerProps,
678
- signatureFlow,
779
+ signatureFlow: pdfVerified && signingScopeMatches ? signatureFlow : null,
679
780
  onSignatureFlow: setSignatureFlow,
680
781
  currentUserId,
681
- placingSignature,
782
+ placingSignature: pdfVerified && signingScopeMatches && placingSignature,
682
783
  onPlacingDone: (appearance) => {
683
784
  setPlacingSignature(false);
684
785
  if (!appearance) return;
@@ -713,6 +814,7 @@ function DocumentViewerContent({
713
814
  title: documentTitle,
714
815
  draftContent: isDraft ? draftDoc?.content || "" : void 0,
715
816
  snapshot: !!snapshotDocumentId,
817
+ saveRef: saveWordRef,
716
818
  onSaved: (id) => {
717
819
  if (!isDraft) return;
718
820
  session.clearDraftDocument(documentId);
@@ -756,7 +858,8 @@ function DocumentViewerContent({
756
858
  {
757
859
  documentId: snapshotDocumentId || documentId,
758
860
  title: documentTitle,
759
- snapshot: !!snapshotDocumentId
861
+ snapshot: !!snapshotDocumentId,
862
+ saveRef: saveWordRef
760
863
  },
761
864
  `${snapshotDocumentId || documentId}-${snapshotDocumentId ? "snapshot" : "live"}`
762
865
  )