@arbidocs/blocks 0.5.121 → 0.5.122

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 (185) hide show
  1. package/dist/{ClippingMediaViewer-B6WG7Q64.cjs → ClippingMediaViewer-IEIBT74X.cjs} +8 -8
  2. package/dist/{ClippingMediaViewer-B6WG7Q64.cjs.map → ClippingMediaViewer-IEIBT74X.cjs.map} +1 -1
  3. package/dist/{ClippingPdfViewer-6GCVTV3V.cjs → ClippingPdfViewer-OGYLMVCE.cjs} +5 -5
  4. package/dist/{ClippingPdfViewer-6GCVTV3V.cjs.map → ClippingPdfViewer-OGYLMVCE.cjs.map} +1 -1
  5. package/dist/{ConnectedCallDock-DC5V5OUJ.cjs → ConnectedCallDock-XJOYVVAH.cjs} +21 -21
  6. package/dist/{ConnectedCallDock-DC5V5OUJ.cjs.map → ConnectedCallDock-XJOYVVAH.cjs.map} +1 -1
  7. package/dist/{ConnectedCallRoom-FQLXWTFB.cjs → ConnectedCallRoom-CUDYAPQK.cjs} +14 -14
  8. package/dist/{ConnectedCallRoom-FQLXWTFB.cjs.map → ConnectedCallRoom-CUDYAPQK.cjs.map} +1 -1
  9. package/dist/{ConnectedNativeDocxComparison-4Q5S7VLD.cjs → ConnectedNativeDocxComparison-QKHCYD6W.cjs} +16 -16
  10. package/dist/{ConnectedNativeDocxComparison-4Q5S7VLD.cjs.map → ConnectedNativeDocxComparison-QKHCYD6W.cjs.map} +1 -1
  11. package/dist/ConnectedPresentation-AU25OW25.cjs +321 -0
  12. package/dist/ConnectedPresentation-AU25OW25.cjs.map +1 -0
  13. package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs → ConnectedProductionSetDialog-LHB4VQWC.cjs} +3 -3
  14. package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs.map → ConnectedProductionSetDialog-LHB4VQWC.cjs.map} +1 -1
  15. package/dist/{ConnectedSlidesTab-7QDE2CZD.cjs → ConnectedSlidesTab-I75LKKN7.cjs} +40 -38
  16. package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +1 -0
  17. package/dist/{ConnectedStreamedWordArtifact-FFOQJBOI.cjs → ConnectedStreamedWordArtifact-AG62232A.cjs} +16 -16
  18. package/dist/{ConnectedStreamedWordArtifact-FFOQJBOI.cjs.map → ConnectedStreamedWordArtifact-AG62232A.cjs.map} +1 -1
  19. package/dist/{DocumentReviewCard-SNWVEZ7S.cjs → DocumentReviewCard-M53XFLI2.cjs} +15 -15
  20. package/dist/{DocumentReviewCard-SNWVEZ7S.cjs.map → DocumentReviewCard-M53XFLI2.cjs.map} +1 -1
  21. package/dist/{FilesViewerDialog-IZI63FOV.cjs → FilesViewerDialog-4352KIOG.cjs} +50 -49
  22. package/dist/FilesViewerDialog-4352KIOG.cjs.map +1 -0
  23. package/dist/{WorkspaceTableView-TEIRB6VJ.cjs → WorkspaceTableView-3XYAV4BV.cjs} +8 -8
  24. package/dist/{WorkspaceTableView-TEIRB6VJ.cjs.map → WorkspaceTableView-3XYAV4BV.cjs.map} +1 -1
  25. package/dist/agents/index.cjs +297 -297
  26. package/dist/{ai-KBYNRNZ6.cjs → ai-IEIR7SC2.cjs} +25 -25
  27. package/dist/ai-IEIR7SC2.cjs.map +1 -0
  28. package/dist/calls/index.cjs +121 -121
  29. package/dist/chat/index.cjs +1 -1
  30. package/dist/{chunk-NLOETJCB.cjs → chunk-2F57IO7S.cjs} +12 -12
  31. package/dist/{chunk-NLOETJCB.cjs.map → chunk-2F57IO7S.cjs.map} +1 -1
  32. package/dist/chunk-2RLA6QO2.cjs +174 -0
  33. package/dist/chunk-2RLA6QO2.cjs.map +1 -0
  34. package/dist/{chunk-Q6DQGGP4.cjs → chunk-325GVZE6.cjs} +3 -3
  35. package/dist/{chunk-Q6DQGGP4.cjs.map → chunk-325GVZE6.cjs.map} +1 -1
  36. package/dist/{chunk-XTR26TNE.cjs → chunk-4TTX6ZNS.cjs} +20 -4
  37. package/dist/chunk-4TTX6ZNS.cjs.map +1 -0
  38. package/dist/{chunk-BVAT4EVC.cjs → chunk-5QERK4PK.cjs} +35 -35
  39. package/dist/{chunk-BVAT4EVC.cjs.map → chunk-5QERK4PK.cjs.map} +1 -1
  40. package/dist/{chunk-GX2EBMJW.cjs → chunk-6OK7ESTL.cjs} +7 -6
  41. package/dist/chunk-6OK7ESTL.cjs.map +1 -0
  42. package/dist/{chunk-C2OICDMI.cjs → chunk-7557LDAN.cjs} +10 -10
  43. package/dist/{chunk-C2OICDMI.cjs.map → chunk-7557LDAN.cjs.map} +1 -1
  44. package/dist/{chunk-474GPLCM.cjs → chunk-7L4X6QN2.cjs} +6 -6
  45. package/dist/{chunk-474GPLCM.cjs.map → chunk-7L4X6QN2.cjs.map} +1 -1
  46. package/dist/{chunk-52KGMAO5.cjs → chunk-7NLO7ASW.cjs} +15 -15
  47. package/dist/{chunk-52KGMAO5.cjs.map → chunk-7NLO7ASW.cjs.map} +1 -1
  48. package/dist/{chunk-H5OLHP2U.cjs → chunk-7OPOPYV6.cjs} +3 -3
  49. package/dist/{chunk-H5OLHP2U.cjs.map → chunk-7OPOPYV6.cjs.map} +1 -1
  50. package/dist/{chunk-W6B3RYTX.cjs → chunk-7PN3YENO.cjs} +4 -4
  51. package/dist/{chunk-W6B3RYTX.cjs.map → chunk-7PN3YENO.cjs.map} +1 -1
  52. package/dist/{chunk-734NPQNR.cjs → chunk-ADDQKZ5I.cjs} +4 -4
  53. package/dist/{chunk-734NPQNR.cjs.map → chunk-ADDQKZ5I.cjs.map} +1 -1
  54. package/dist/{chunk-JQLWKNJO.cjs → chunk-ALK3PUUB.cjs} +4 -4
  55. package/dist/{chunk-JQLWKNJO.cjs.map → chunk-ALK3PUUB.cjs.map} +1 -1
  56. package/dist/{chunk-4VZZWYEC.cjs → chunk-BQ5RIWWT.cjs} +3 -3
  57. package/dist/{chunk-4VZZWYEC.cjs.map → chunk-BQ5RIWWT.cjs.map} +1 -1
  58. package/dist/{chunk-ENGL7P3I.cjs → chunk-CQQQIZU4.cjs} +27 -27
  59. package/dist/{chunk-ENGL7P3I.cjs.map → chunk-CQQQIZU4.cjs.map} +1 -1
  60. package/dist/{chunk-3SCNXNHI.cjs → chunk-E3L5DB5F.cjs} +5 -5
  61. package/dist/{chunk-3SCNXNHI.cjs.map → chunk-E3L5DB5F.cjs.map} +1 -1
  62. package/dist/{chunk-VJ5ZLRBD.cjs → chunk-GFUOCGY6.cjs} +8 -3
  63. package/dist/chunk-GFUOCGY6.cjs.map +1 -0
  64. package/dist/{chunk-RYVZDFVO.cjs → chunk-JJZOL5MG.cjs} +3 -3
  65. package/dist/{chunk-RYVZDFVO.cjs.map → chunk-JJZOL5MG.cjs.map} +1 -1
  66. package/dist/{chunk-QFXILJMJ.cjs → chunk-K4763GD5.cjs} +17 -174
  67. package/dist/chunk-K4763GD5.cjs.map +1 -0
  68. package/dist/{chunk-EHP6OH5D.cjs → chunk-KA3F6TIH.cjs} +11 -11
  69. package/dist/{chunk-EHP6OH5D.cjs.map → chunk-KA3F6TIH.cjs.map} +1 -1
  70. package/dist/{chunk-UUENH4BJ.cjs → chunk-KXIRVKCJ.cjs} +3 -3
  71. package/dist/{chunk-UUENH4BJ.cjs.map → chunk-KXIRVKCJ.cjs.map} +1 -1
  72. package/dist/{chunk-4RBQ44RY.cjs → chunk-MLA2BJ2Y.cjs} +28 -28
  73. package/dist/{chunk-4RBQ44RY.cjs.map → chunk-MLA2BJ2Y.cjs.map} +1 -1
  74. package/dist/{chunk-DR2AH7JL.cjs → chunk-NG2EE7HR.cjs} +48 -48
  75. package/dist/{chunk-DR2AH7JL.cjs.map → chunk-NG2EE7HR.cjs.map} +1 -1
  76. package/dist/{chunk-4NPCDS2X.cjs → chunk-NY3YUCOW.cjs} +3 -3
  77. package/dist/{chunk-4NPCDS2X.cjs.map → chunk-NY3YUCOW.cjs.map} +1 -1
  78. package/dist/{chunk-JZEYHDWJ.cjs → chunk-OHHKBURG.cjs} +76 -76
  79. package/dist/chunk-OHHKBURG.cjs.map +1 -0
  80. package/dist/{chunk-AY6EZSZB.cjs → chunk-QG2U2JGX.cjs} +4 -4
  81. package/dist/{chunk-AY6EZSZB.cjs.map → chunk-QG2U2JGX.cjs.map} +1 -1
  82. package/dist/{chunk-5534FYXP.cjs → chunk-SDRYSLOX.cjs} +4 -4
  83. package/dist/{chunk-5534FYXP.cjs.map → chunk-SDRYSLOX.cjs.map} +1 -1
  84. package/dist/{chunk-2W5E62EY.cjs → chunk-SGYSDABK.cjs} +6 -6
  85. package/dist/{chunk-2W5E62EY.cjs.map → chunk-SGYSDABK.cjs.map} +1 -1
  86. package/dist/{chunk-EATIFPKP.cjs → chunk-T73BHNQX.cjs} +4 -4
  87. package/dist/{chunk-EATIFPKP.cjs.map → chunk-T73BHNQX.cjs.map} +1 -1
  88. package/dist/{chunk-4IOYQLKG.cjs → chunk-TP5PGWIO.cjs} +3 -3
  89. package/dist/{chunk-4IOYQLKG.cjs.map → chunk-TP5PGWIO.cjs.map} +1 -1
  90. package/dist/{chunk-GKVE5JGB.cjs → chunk-UFT22LAB.cjs} +3 -3
  91. package/dist/{chunk-GKVE5JGB.cjs.map → chunk-UFT22LAB.cjs.map} +1 -1
  92. package/dist/{chunk-Q3XJUXID.cjs → chunk-USNTRL22.cjs} +215 -199
  93. package/dist/chunk-USNTRL22.cjs.map +1 -0
  94. package/dist/{chunk-7VUJGHMY.cjs → chunk-UTJ223TI.cjs} +178 -82
  95. package/dist/chunk-UTJ223TI.cjs.map +1 -0
  96. package/dist/{chunk-FKFQCK3C.cjs → chunk-V6MW7B4B.cjs} +4 -4
  97. package/dist/{chunk-FKFQCK3C.cjs.map → chunk-V6MW7B4B.cjs.map} +1 -1
  98. package/dist/{chunk-2PZT3J34.cjs → chunk-VWBYE3XY.cjs} +6 -6
  99. package/dist/{chunk-2PZT3J34.cjs.map → chunk-VWBYE3XY.cjs.map} +1 -1
  100. package/dist/{chunk-GQXPNIRE.cjs → chunk-WAV762GP.cjs} +6 -6
  101. package/dist/{chunk-GQXPNIRE.cjs.map → chunk-WAV762GP.cjs.map} +1 -1
  102. package/dist/{chunk-5LTIZ44D.cjs → chunk-WFMWKPGY.cjs} +14 -7
  103. package/dist/chunk-WFMWKPGY.cjs.map +1 -0
  104. package/dist/{chunk-KP5AITQ4.cjs → chunk-WRLGLZIA.cjs} +7 -7
  105. package/dist/{chunk-KP5AITQ4.cjs.map → chunk-WRLGLZIA.cjs.map} +1 -1
  106. package/dist/{chunk-MZ2KZXNU.cjs → chunk-WXUU3COI.cjs} +3 -3
  107. package/dist/{chunk-MZ2KZXNU.cjs.map → chunk-WXUU3COI.cjs.map} +1 -1
  108. package/dist/{chunk-NAJN32MF.cjs → chunk-XF355M7O.cjs} +13 -13
  109. package/dist/{chunk-NAJN32MF.cjs.map → chunk-XF355M7O.cjs.map} +1 -1
  110. package/dist/{chunk-GPX5VC57.cjs → chunk-XGM4VVNV.cjs} +50 -50
  111. package/dist/{chunk-GPX5VC57.cjs.map → chunk-XGM4VVNV.cjs.map} +1 -1
  112. package/dist/connect/docx.cjs +19 -19
  113. package/dist/connect/index.cjs +996 -995
  114. package/dist/connect/index.cjs.map +1 -1
  115. package/dist/connect/viewer.cjs +38 -37
  116. package/dist/connection/conversation/ConnectedMessage.js +1 -1
  117. package/dist/connection/conversation/ConnectedMessage.js.map +2 -2
  118. package/dist/connection/presentation/ConnectedSlidesTab.js +5 -3
  119. package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
  120. package/dist/connection/presentation/PresentationPill.js +3 -8
  121. package/dist/connection/presentation/PresentationPill.js.map +2 -2
  122. package/dist/connection/presentation/requests.d.ts +5 -0
  123. package/dist/connection/presentation/requests.js +8 -1
  124. package/dist/connection/presentation/requests.js.map +2 -2
  125. package/dist/connection/viewer/ViewerPdfPane.js +4 -1
  126. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  127. package/dist/connection/viewer/documentPlace.d.ts +5 -4
  128. package/dist/connection/viewer/documentPlace.js +2 -2
  129. package/dist/connection/viewer/documentPlace.js.map +2 -2
  130. package/dist/connection/viewer/pdf/PdfClipOutlines.d.ts +11 -0
  131. package/dist/connection/viewer/pdf/PdfClipOutlines.js +42 -0
  132. package/dist/connection/viewer/pdf/PdfClipOutlines.js.map +7 -0
  133. package/dist/connection/viewer/pdf/clipOutlines.d.ts +17 -0
  134. package/dist/connection/viewer/pdf/clipOutlines.js +24 -0
  135. package/dist/connection/viewer/pdf/clipOutlines.js.map +7 -0
  136. package/dist/connection/viewer/pdf/passageHighlights.d.ts +2 -0
  137. package/dist/connection/viewer/pdf/passageHighlights.js +12 -1
  138. package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
  139. package/dist/connection/viewer/pdf/usePdfClipOutlines.d.ts +7 -0
  140. package/dist/connection/viewer/pdf/usePdfClipOutlines.js +36 -0
  141. package/dist/connection/viewer/pdf/usePdfClipOutlines.js.map +7 -0
  142. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js +11 -2
  143. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js.map +2 -2
  144. package/dist/dashboards/index.cjs +1 -1
  145. package/dist/embed/index.cjs +39 -39
  146. package/dist/files/index.cjs +224 -224
  147. package/dist/index.cjs +1597 -1596
  148. package/dist/index.cjs.map +1 -1
  149. package/dist/presentation/PresentControls.d.ts +11 -0
  150. package/dist/presentation/PresentControls.js +117 -0
  151. package/dist/presentation/PresentControls.js.map +7 -0
  152. package/dist/presentation/PresenterView.js +36 -5
  153. package/dist/presentation/PresenterView.js.map +2 -2
  154. package/dist/presentation/SlidesEditor.js +17 -1
  155. package/dist/presentation/SlidesEditor.js.map +2 -2
  156. package/dist/presentation/panel-id.d.ts +12 -2
  157. package/dist/presentation/panel-id.js +6 -1
  158. package/dist/presentation/panel-id.js.map +2 -2
  159. package/dist/presentation/slide-layout.d.ts +5 -1
  160. package/dist/presentation/slide-layout.js +16 -0
  161. package/dist/presentation/slide-layout.js.map +2 -2
  162. package/dist/settings/index.cjs +146 -146
  163. package/dist/shell/PanelPortal.js +13 -4
  164. package/dist/shell/PanelPortal.js.map +2 -2
  165. package/dist/shell/index.cjs +92 -91
  166. package/dist/shell/panel-windows.js +1 -0
  167. package/dist/shell/panel-windows.js.map +2 -2
  168. package/dist/studio/index.cjs +28 -28
  169. package/dist/styles.css +1 -1
  170. package/dist/workflow-canvas/index.cjs +53 -53
  171. package/node_modules/@arbidocs/coedit/package.json +1 -1
  172. package/package.json +5 -5
  173. package/dist/ConnectedPresentation-4HLDZDWV.cjs +0 -183
  174. package/dist/ConnectedPresentation-4HLDZDWV.cjs.map +0 -1
  175. package/dist/ConnectedSlidesTab-7QDE2CZD.cjs.map +0 -1
  176. package/dist/FilesViewerDialog-IZI63FOV.cjs.map +0 -1
  177. package/dist/ai-KBYNRNZ6.cjs.map +0 -1
  178. package/dist/chunk-5LTIZ44D.cjs.map +0 -1
  179. package/dist/chunk-7VUJGHMY.cjs.map +0 -1
  180. package/dist/chunk-GX2EBMJW.cjs.map +0 -1
  181. package/dist/chunk-JZEYHDWJ.cjs.map +0 -1
  182. package/dist/chunk-Q3XJUXID.cjs.map +0 -1
  183. package/dist/chunk-QFXILJMJ.cjs.map +0 -1
  184. package/dist/chunk-VJ5ZLRBD.cjs.map +0 -1
  185. package/dist/chunk-XTR26TNE.cjs.map +0 -1
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Presentation } from "lucide-react";
4
- import { DOCUMENT_VIEWER_PANEL, useArbiSessionState, useArbiSessionStore } from "@arbidocs/react";
4
+ import { useArbiSessionState, useArbiSessionStore } from "@arbidocs/react";
5
5
  import { Button } from "@arbidocs/react/ui";
6
6
  import { usePresentation } from "../../presentation/store.js";
7
- import { editPresentation } from "./requests.js";
7
+ import { showPresentation } from "./requests.js";
8
8
  function PresentationPill({ compact }) {
9
9
  const session = useArbiSessionStore();
10
10
  const boundTo = usePresentation((s) => s.boundTo);
@@ -14,12 +14,7 @@ function PresentationPill({ compact }) {
14
14
  (s) => s.viewingDocument?.id === boundTo && s.documentViewer.tab === "slides"
15
15
  );
16
16
  if (onIt || boundTo === null && clips === 0) return null;
17
- const back = () => {
18
- if (boundTo === null) return editPresentation(session, { kind: "new" });
19
- session.setViewingDocument({ id: boundTo, page: null });
20
- session.setDocumentViewer({ tab: "slides" });
21
- session.openPanel(DOCUMENT_VIEWER_PANEL, "docked");
22
- };
17
+ const back = () => showPresentation(session, boundTo);
23
18
  return /* @__PURE__ */ jsxs(
24
19
  Button,
25
20
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/presentation/PresentationPill.tsx"],
4
- "sourcesContent": ["import { Presentation } from 'lucide-react'\nimport { DOCUMENT_VIEWER_PANEL, useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport { Button } from '@arbidocs/react/ui'\nimport { usePresentation } from '../../presentation/store'\nimport { editPresentation } from './requests'\n\n/**\n * Back to the presentation, from any document the viewer shows (clips are gathered while reading,\n * then arranged): its title and how many clips wait in its tray. Shown while a presentation is\n * being made and the viewer is elsewhere.\n */\nexport function PresentationPill({ compact }: { compact: boolean }) {\n const session = useArbiSessionStore()\n const boundTo = usePresentation((s) => s.boundTo)\n const clips = usePresentation((s) => s.clips.length)\n const title = usePresentation((s) => s.title)\n const onIt = useArbiSessionState(\n (s) => s.viewingDocument?.id === boundTo && s.documentViewer.tab === 'slides'\n )\n if (onIt || (boundTo === null && clips === 0)) return null\n const back = () => {\n if (boundTo === null) return editPresentation(session, { kind: 'new' })\n session.setViewingDocument({ id: boundTo, page: null })\n session.setDocumentViewer({ tab: 'slides' })\n session.openPanel(DOCUMENT_VIEWER_PANEL, 'docked')\n }\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 max-w-56 gap-1.5 rounded-full px-2.5 text-xs\"\n onClick={back}\n title={`Back to the presentation \"${title}\": ${clips} clip${clips === 1 ? '' : 's'} to arrange`}\n data-testid=\"presentation-pill\"\n >\n <Presentation className=\"size-3.5 shrink-0\" />\n {!compact && <span className=\"min-w-0 truncate\">{title}</span>}\n {clips > 0 && (\n <span className=\"rounded-full bg-primary px-1.5 text-[10px] font-semibold leading-4 text-primary-foreground\">\n {clips}\n </span>\n )}\n </Button>\n )\n}\n"],
5
- "mappings": ";AA2BI,SASE,KATF;AA3BJ,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB,qBAAqB,2BAA2B;AAChF,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAO1B,SAAS,iBAAiB,EAAE,QAAQ,GAAyB;AAClE,QAAM,UAAU,oBAAoB;AACpC,QAAM,UAAU,gBAAgB,CAAC,MAAM,EAAE,OAAO;AAChD,QAAM,QAAQ,gBAAgB,CAAC,MAAM,EAAE,MAAM,MAAM;AACnD,QAAM,QAAQ,gBAAgB,CAAC,MAAM,EAAE,KAAK;AAC5C,QAAM,OAAO;AAAA,IACX,CAAC,MAAM,EAAE,iBAAiB,OAAO,WAAW,EAAE,eAAe,QAAQ;AAAA,EACvE;AACA,MAAI,QAAS,YAAY,QAAQ,UAAU,EAAI,QAAO;AACtD,QAAM,OAAO,MAAM;AACjB,QAAI,YAAY,KAAM,QAAO,iBAAiB,SAAS,EAAE,MAAM,MAAM,CAAC;AACtE,YAAQ,mBAAmB,EAAE,IAAI,SAAS,MAAM,KAAK,CAAC;AACtD,YAAQ,kBAAkB,EAAE,KAAK,SAAS,CAAC;AAC3C,YAAQ,UAAU,uBAAuB,QAAQ;AAAA,EACnD;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,6BAA6B,KAAK,MAAM,KAAK,QAAQ,UAAU,IAAI,KAAK,GAAG;AAAA,MAClF,eAAY;AAAA,MAEZ;AAAA,4BAAC,gBAAa,WAAU,qBAAoB;AAAA,QAC3C,CAAC,WAAW,oBAAC,UAAK,WAAU,oBAAoB,iBAAM;AAAA,QACtD,QAAQ,KACP,oBAAC,UAAK,WAAU,8FACb,iBACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;",
4
+ "sourcesContent": ["import { Presentation } from 'lucide-react'\nimport { useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport { Button } from '@arbidocs/react/ui'\nimport { usePresentation } from '../../presentation/store'\nimport { showPresentation } from './requests'\n\n/**\n * Back to the presentation, from any document the viewer shows (clips are gathered while reading,\n * then arranged): its title and how many clips wait in its tray. Shown while a presentation is\n * being made and the viewer is elsewhere.\n */\nexport function PresentationPill({ compact }: { compact: boolean }) {\n const session = useArbiSessionStore()\n const boundTo = usePresentation((s) => s.boundTo)\n const clips = usePresentation((s) => s.clips.length)\n const title = usePresentation((s) => s.title)\n const onIt = useArbiSessionState(\n (s) => s.viewingDocument?.id === boundTo && s.documentViewer.tab === 'slides'\n )\n if (onIt || (boundTo === null && clips === 0)) return null\n const back = () => showPresentation(session, boundTo)\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 max-w-56 gap-1.5 rounded-full px-2.5 text-xs\"\n onClick={back}\n title={`Back to the presentation \"${title}\": ${clips} clip${clips === 1 ? '' : 's'} to arrange`}\n data-testid=\"presentation-pill\"\n >\n <Presentation className=\"size-3.5 shrink-0\" />\n {!compact && <span className=\"min-w-0 truncate\">{title}</span>}\n {clips > 0 && (\n <span className=\"rounded-full bg-primary px-1.5 text-[10px] font-semibold leading-4 text-primary-foreground\">\n {clips}\n </span>\n )}\n </Button>\n )\n}\n"],
5
+ "mappings": ";AAsBI,SASE,KATF;AAtBJ,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB,2BAA2B;AACzD,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAO1B,SAAS,iBAAiB,EAAE,QAAQ,GAAyB;AAClE,QAAM,UAAU,oBAAoB;AACpC,QAAM,UAAU,gBAAgB,CAAC,MAAM,EAAE,OAAO;AAChD,QAAM,QAAQ,gBAAgB,CAAC,MAAM,EAAE,MAAM,MAAM;AACnD,QAAM,QAAQ,gBAAgB,CAAC,MAAM,EAAE,KAAK;AAC5C,QAAM,OAAO;AAAA,IACX,CAAC,MAAM,EAAE,iBAAiB,OAAO,WAAW,EAAE,eAAe,QAAQ;AAAA,EACvE;AACA,MAAI,QAAS,YAAY,QAAQ,UAAU,EAAI,QAAO;AACtD,QAAM,OAAO,MAAM,iBAAiB,SAAS,OAAO;AACpD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,6BAA6B,KAAK,MAAM,KAAK,QAAQ,UAAU,IAAI,KAAK,GAAG;AAAA,MAClF,eAAY;AAAA,MAEZ;AAAA,4BAAC,gBAAa,WAAU,qBAAoB;AAAA,QAC3C,CAAC,WAAW,oBAAC,UAAK,WAAU,oBAAoB,iBAAM;AAAA,QACtD,QAAQ,KACP,oBAAC,UAAK,WAAU,8FACb,iBACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,11 @@ export type PresentationRequest = {
8
8
  documentId: string;
9
9
  version?: number;
10
10
  };
11
+ /**
12
+ * Back to the presentation being edited, on its slides tab (a new one when none is open yet): from
13
+ * any document the viewer shows.
14
+ */
15
+ export declare function showPresentation(session: Session, boundTo: string | null): void;
11
16
  /**
12
17
  * Edit a presentation in the viewer's slides tab: a saved one (its document, on that tab), or a
13
18
  * new one (a presentation draft, saved into Files › Presentations when it is first saved).
@@ -1,6 +1,12 @@
1
1
  "use client";
2
2
  import { DOCUMENT_VIEWER_PANEL } from "@arbidocs/react";
3
3
  import { versionRef } from "@arbidocs/react/artifacts";
4
+ function showPresentation(session, boundTo) {
5
+ if (boundTo === null) return editPresentation(session, { kind: "new" });
6
+ session.setViewingDocument({ id: boundTo, page: null });
7
+ session.setDocumentViewer({ tab: "slides" });
8
+ session.openPanel(DOCUMENT_VIEWER_PANEL, "docked");
9
+ }
4
10
  function editPresentation(session, request) {
5
11
  if (request.kind === "new") {
6
12
  session.startDraftDocument("presentation");
@@ -15,6 +21,7 @@ function editPresentation(session, request) {
15
21
  session.openPanel(DOCUMENT_VIEWER_PANEL, "docked");
16
22
  }
17
23
  export {
18
- editPresentation
24
+ editPresentation,
25
+ showPresentation
19
26
  };
20
27
  //# sourceMappingURL=requests.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/presentation/requests.ts"],
4
- "sourcesContent": ["import { DOCUMENT_VIEWER_PANEL, type ArbiSessionStore } from '@arbidocs/react'\nimport { versionRef } from '@arbidocs/react/artifacts'\n\ntype Session = Pick<\n ArbiSessionStore,\n 'setViewingDocument' | 'setDocumentViewer' | 'openPanel' | 'startDraftDocument'\n>\n\n/** A presentation to edit: a new one, or a saved one (as of `version`; default its current one). */\nexport type PresentationRequest =\n { kind: 'new' } | { kind: 'open'; documentId: string; version?: number }\n\n/**\n * Edit a presentation in the viewer's slides tab: a saved one (its document, on that tab), or a\n * new one (a presentation draft, saved into Files \u203A Presentations when it is first saved).\n */\nexport function editPresentation(session: Session, request: PresentationRequest): void {\n if (request.kind === 'new') {\n session.startDraftDocument('presentation')\n return\n }\n const { documentId, version } = request\n session.setViewingDocument({\n id: version ? versionRef(documentId, version) : documentId,\n page: null,\n })\n session.setDocumentViewer({ tab: 'slides' })\n session.openPanel(DOCUMENT_VIEWER_PANEL, 'docked')\n}\n"],
5
- "mappings": ";AAAA,SAAS,6BAAoD;AAC7D,SAAS,kBAAkB;AAepB,SAAS,iBAAiB,SAAkB,SAAoC;AACrF,MAAI,QAAQ,SAAS,OAAO;AAC1B,YAAQ,mBAAmB,cAAc;AACzC;AAAA,EACF;AACA,QAAM,EAAE,YAAY,QAAQ,IAAI;AAChC,UAAQ,mBAAmB;AAAA,IACzB,IAAI,UAAU,WAAW,YAAY,OAAO,IAAI;AAAA,IAChD,MAAM;AAAA,EACR,CAAC;AACD,UAAQ,kBAAkB,EAAE,KAAK,SAAS,CAAC;AAC3C,UAAQ,UAAU,uBAAuB,QAAQ;AACnD;",
4
+ "sourcesContent": ["import { DOCUMENT_VIEWER_PANEL, type ArbiSessionStore } from '@arbidocs/react'\nimport { versionRef } from '@arbidocs/react/artifacts'\n\ntype Session = Pick<\n ArbiSessionStore,\n 'setViewingDocument' | 'setDocumentViewer' | 'openPanel' | 'startDraftDocument'\n>\n\n/** A presentation to edit: a new one, or a saved one (as of `version`; default its current one). */\nexport type PresentationRequest =\n { kind: 'new' } | { kind: 'open'; documentId: string; version?: number }\n\n/**\n * Back to the presentation being edited, on its slides tab (a new one when none is open yet): from\n * any document the viewer shows.\n */\nexport function showPresentation(session: Session, boundTo: string | null): void {\n if (boundTo === null) return editPresentation(session, { kind: 'new' })\n session.setViewingDocument({ id: boundTo, page: null })\n session.setDocumentViewer({ tab: 'slides' })\n session.openPanel(DOCUMENT_VIEWER_PANEL, 'docked')\n}\n\n/**\n * Edit a presentation in the viewer's slides tab: a saved one (its document, on that tab), or a\n * new one (a presentation draft, saved into Files \u203A Presentations when it is first saved).\n */\nexport function editPresentation(session: Session, request: PresentationRequest): void {\n if (request.kind === 'new') {\n session.startDraftDocument('presentation')\n return\n }\n const { documentId, version } = request\n session.setViewingDocument({\n id: version ? versionRef(documentId, version) : documentId,\n page: null,\n })\n session.setDocumentViewer({ tab: 'slides' })\n session.openPanel(DOCUMENT_VIEWER_PANEL, 'docked')\n}\n"],
5
+ "mappings": ";AAAA,SAAS,6BAAoD;AAC7D,SAAS,kBAAkB;AAepB,SAAS,iBAAiB,SAAkB,SAA8B;AAC/E,MAAI,YAAY,KAAM,QAAO,iBAAiB,SAAS,EAAE,MAAM,MAAM,CAAC;AACtE,UAAQ,mBAAmB,EAAE,IAAI,SAAS,MAAM,KAAK,CAAC;AACtD,UAAQ,kBAAkB,EAAE,KAAK,SAAS,CAAC;AAC3C,UAAQ,UAAU,uBAAuB,QAAQ;AACnD;AAMO,SAAS,iBAAiB,SAAkB,SAAoC;AACrF,MAAI,QAAQ,SAAS,OAAO;AAC1B,YAAQ,mBAAmB,cAAc;AACzC;AAAA,EACF;AACA,QAAM,EAAE,YAAY,QAAQ,IAAI;AAChC,UAAQ,mBAAmB;AAAA,IACzB,IAAI,UAAU,WAAW,YAAY,OAAO,IAAI;AAAA,IAChD,MAAM;AAAA,EACR,CAAC;AACD,UAAQ,kBAAkB,EAAE,KAAK,SAAS,CAAC;AAC3C,UAAQ,UAAU,uBAAuB,QAAQ;AACnD;",
6
6
  "names": []
7
7
  }
@@ -10,6 +10,7 @@ import {
10
10
  } from "@arbidocs/react/viewers";
11
11
  import { friendlyFileType } from "@arbidocs/react/ui";
12
12
  import { ViewerLoadError, ViewerMessage, ViewerPreviewUnavailable } from "../../files/index.js";
13
+ import { usePdfClipOutlines } from "./pdf/usePdfClipOutlines.js";
13
14
  import { usePdfPassageHighlights } from "./pdf/usePdfPassageHighlights.js";
14
15
  import { useViewerIsDetached } from "./support.js";
15
16
  import { isLegacyPresentationFile } from "../../presentation/panel-id.js";
@@ -44,13 +45,15 @@ function SessionPdfViewer(props) {
44
45
  [session, viewingId]
45
46
  );
46
47
  const passageHighlights = usePdfPassageHighlights(viewingId);
48
+ const clipOutlines = usePdfClipOutlines(viewingId);
47
49
  const { renderPageOverlay: modeOverlay } = props;
48
50
  const renderPageOverlay = useCallback(
49
51
  (page) => /* @__PURE__ */ jsxs(Fragment, { children: [
50
52
  passageHighlights(page.pageNumber),
53
+ clipOutlines(page.pageNumber),
51
54
  modeOverlay?.(page)
52
55
  ] }),
53
- [passageHighlights, modeOverlay]
56
+ [passageHighlights, clipOutlines, modeOverlay]
54
57
  );
55
58
  return /* @__PURE__ */ jsx(
56
59
  KitPdfViewer,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/ViewerPdfPane.tsx"],
4
- "sourcesContent": ["/**\n * The PDF (or media) body of the document viewer: loading and failure states, the image, audio and\n * video players, and the PDF with its tools \u2014 the markup layer, signature placement, a signature\n * request being prepared or signed.\n */\n\nimport { lazy, Suspense, useCallback } from 'react'\nimport { useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport type {\n SignatureAppearance,\n SignatureRequest,\n useDocumentMarkup,\n} from '@arbidocs/react/document-tools'\nimport {\n AudioViewer,\n ImageViewer,\n PdfViewer as KitPdfViewer,\n VideoViewer,\n type PdfViewerProps,\n} from '@arbidocs/react/viewers'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport { ViewerLoadError, ViewerMessage, ViewerPreviewUnavailable } from '../../files'\nimport { usePdfPassageHighlights } from './pdf/usePdfPassageHighlights'\nimport { useViewerIsDetached } from './support'\nimport { isLegacyPresentationFile } from '../../presentation/panel-id'\nimport { PresentationFileCard } from '../presentation/PresentationFileCard'\nimport { fileExtension, type ViewedDocument } from './useViewedDocument'\n\n// The markup viewer brings in pdf-lib, which nothing else needs: load it only when it is shown.\nconst AnnotatedPdfViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.AnnotatedPdfViewer }))\n)\nconst SignaturePlacementViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.SignaturePlacementViewer }))\n)\n// Signature requests: placing fields for signers, and a signer's guided signing.\nconst SignatureRequestEditor = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.SignatureRequestEditor }))\n)\n// Clip mode for the presentation: its own chunk (the presentation module).\nconst ClippingPdfViewer = lazy(() =>\n import('../presentation/ClippingPdfViewer').then((m) => ({ default: m.ClippingPdfViewer }))\n)\nconst ClippingMediaViewer = lazy(() =>\n import('../presentation/ClippingMediaViewer').then((m) => ({ default: m.ClippingMediaViewer }))\n)\nconst GuidedSigningViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.GuidedSigningViewer }))\n)\n\n/** A signature request: the author placing fields, or a signer walked through theirs. */\nexport type SignatureFlow =\n | { kind: 'prepare'; draft?: SignatureRequest; self?: boolean }\n | { kind: 'sign'; request: SignatureRequest }\n | null\n\n/**\n * The kit PDF viewer, reporting the page read into the session state; in a detached window its\n * pages render without the opener's web fonts (canvas text in another document cannot use them).\n */\nfunction SessionPdfViewer(props: Omit<PdfViewerProps, 'onPageChange' | 'disableFontFace'>) {\n const session = useArbiSessionStore()\n const viewingId = useArbiSessionState((s) => s.viewingDocument?.id)\n const isDetached = useViewerIsDetached()\n const onPageChange = useCallback(\n (page: number) => {\n if (viewingId) session.setViewingDocument({ id: viewingId, page })\n },\n [session, viewingId]\n )\n // The passages a citation lights, over their pages, under whatever the mode draws (markup).\n const passageHighlights = usePdfPassageHighlights(viewingId)\n const { renderPageOverlay: modeOverlay } = props\n const renderPageOverlay = useCallback<NonNullable<PdfViewerProps['renderPageOverlay']>>(\n (page) => (\n <>\n {passageHighlights(page.pageNumber)}\n {modeOverlay?.(page)}\n </>\n ),\n [passageHighlights, modeOverlay]\n )\n return (\n <KitPdfViewer\n {...props}\n renderPageOverlay={renderPageOverlay}\n onPageChange={onPageChange}\n disableFontFace={!!isDetached}\n />\n )\n}\n\nexport interface ViewerPdfPaneProps {\n documentId: string\n doc: ViewedDocument\n pdfBlob: Blob | null\n isPdfLoading: boolean\n pdfError: unknown\n onDownload: () => void\n viewerProps: {\n currentPage: number | undefined\n onLoadSuccess: (pages: number) => void\n scrollTrigger: number\n zoom: number\n onZoomChange: (zoom: number) => void\n }\n signatureFlow: SignatureFlow\n onSignatureFlow: (flow: SignatureFlow) => void\n currentUserId: string | undefined\n placingSignature: boolean\n onPlacingDone: (appearance?: SignatureAppearance) => void\n annotating: boolean\n /** Clip mode: dragging over a page adds that area to the presentation. */\n clipping?: boolean\n markup: ReturnType<typeof useDocumentMarkup>\n pdfSnapshotNumber: number | undefined\n isSigned: boolean\n /** One's saved signature or initials to place as a picture stamp (PDF tab \u203A My signature). */\n placeMark?: { image: string; label: string; key: number } | null\n}\n\nexport function ViewerPdfPane({\n documentId,\n doc,\n pdfBlob,\n isPdfLoading,\n pdfError,\n onDownload,\n viewerProps,\n signatureFlow,\n onSignatureFlow,\n currentUserId,\n placingSignature,\n onPlacingDone,\n annotating,\n clipping = false,\n markup,\n pdfSnapshotNumber,\n isSigned,\n placeMark = null,\n}: ViewerPdfPaneProps) {\n const { documentData, isDownloadOnly, isVideo, isAudio, isImage, isDocx } = doc\n const showMarkup = markup.hasMarkup && !markup.showOriginal\n\n // A presentation saved before it was a PDF (its data alone): what it is, and Edit presentation.\n if (isLegacyPresentationFile(documentData?.file_name)) {\n return <PresentationFileCard documentId={documentId} fileName={documentData?.file_name ?? ''} />\n }\n\n // Files that cannot be previewed in the browser: the download, at once.\n if (isDownloadOnly) {\n return (\n <ViewerPreviewUnavailable\n extension={fileExtension(documentData?.file_name)}\n onDownload={onDownload}\n />\n )\n }\n\n // Text files are rendered to a PDF too, so name what the user opened, not the rendering.\n const loadingLabel = isVideo\n ? 'Loading video...'\n : isAudio\n ? 'Loading audio...'\n : isImage\n ? 'Loading image...'\n : !documentData\n ? 'Loading document...'\n : friendlyFileType(documentData.file_type, documentData.file_name) === 'Text'\n ? 'Loading text...'\n : 'Loading PDF...'\n const errorLabel = isVideo\n ? 'Failed to load video'\n : isAudio\n ? 'Failed to load audio'\n : isImage\n ? 'Failed to load image'\n : 'Failed to load PDF'\n\n if (\n isDocx &&\n !pdfSnapshotNumber &&\n documentData &&\n !['completed', 'low-content', 'failed'].includes(documentData.status || '')\n ) {\n return (\n <ViewerMessage>\n PDF and search indexing are processing. Open the DOCX tab to edit now.\n </ViewerMessage>\n )\n }\n if (isDocx && !pdfSnapshotNumber && documentData?.status === 'failed') {\n return (\n <ViewerMessage>\n PDF conversion failed. Open the Word editor or download the document.\n </ViewerMessage>\n )\n }\n if (isPdfLoading) return <ViewerMessage>{loadingLabel}</ViewerMessage>\n if (pdfError) {\n return (\n <ViewerLoadError\n message={\n isVideo || isAudio || isImage\n ? `${errorLabel} \u2014 download it instead.`\n : \"Couldn't display the PDF \u2014 download it instead.\"\n }\n onDownload={onDownload}\n />\n )\n }\n // Nothing is fetched yet: the PDF is read once the document record has loaded, so the viewer\n // would otherwise sit empty for that first stretch.\n if (!pdfBlob) return <ViewerMessage>{loadingLabel}</ViewerMessage>\n\n // Clip mode on an image or a video: drag over it for the presentation.\n if (clipping && (isImage || isVideo)) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <ClippingMediaViewer\n file={pdfBlob}\n kind={isVideo ? 'video' : 'image'}\n documentId={documentId}\n fileName={documentData?.file_name || (isVideo ? 'Video' : 'Image')}\n />\n </Suspense>\n )\n }\n if (isVideo) return <VideoViewer blob={pdfBlob} title={documentData?.file_name || 'Video'} />\n if (isAudio) return <AudioViewer blob={pdfBlob} title={documentData?.file_name || 'Audio'} />\n if (isImage) {\n return <ImageViewer blob={pdfBlob} alt={documentData?.file_name || 'Document image'} />\n }\n if (signatureFlow?.kind === 'prepare') {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <SignatureRequestEditor\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber ?? documentData?.current_version ?? undefined}\n selfSigning={signatureFlow.self}\n draft={signatureFlow.draft}\n shareFile={!signatureFlow.draft}\n viewer={SessionPdfViewer}\n onCancel={() => onSignatureFlow(null)}\n onSaved={() => onSignatureFlow(null)}\n />\n </Suspense>\n )\n }\n if (signatureFlow?.kind === 'sign' && currentUserId) {\n const { currentPage: _page, scrollTrigger: _trigger, ...guidedProps } = viewerProps\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <GuidedSigningViewer\n {...guidedProps}\n file={pdfBlob}\n request={signatureFlow.request}\n signer={currentUserId}\n viewer={SessionPdfViewer}\n onClose={() => onSignatureFlow(null)}\n onSigned={() => onSignatureFlow(null)}\n />\n </Suspense>\n )\n }\n if (placingSignature) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <SignaturePlacementViewer\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n viewer={SessionPdfViewer}\n onCancel={() => onPlacingDone()}\n onContinue={(appearance) => onPlacingDone(appearance)}\n />\n </Suspense>\n )\n }\n if (clipping) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <ClippingPdfViewer\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber}\n fileName={documentData?.file_name || 'Document'}\n hasMarkup={markup.hasMarkup}\n viewer={SessionPdfViewer}\n />\n </Suspense>\n )\n }\n // Annotate mode, or the markup as the reading view: one viewer, so leaving annotate mode keeps\n // (and saves) what was just drawn.\n if (annotating || showMarkup) {\n return (\n <Suspense\n fallback={\n <ViewerMessage>\n {annotating ? 'Loading annotation tools\u2026' : 'Loading markup\u2026'}\n </ViewerMessage>\n }\n >\n <AnnotatedPdfViewer\n key={`${documentId}@${pdfSnapshotNumber ?? 'current'}`}\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber}\n editing={annotating}\n onMarkupChange={markup.onMarkupChange}\n fileName={documentData?.file_name}\n shared={documentData?.shared ?? false}\n folder={documentData?.folder}\n workspaceId={documentData?.workspace_ext_id}\n viewer={SessionPdfViewer}\n signed={isSigned}\n placeStamp={placeMark}\n />\n </Suspense>\n )\n }\n return <SessionPdfViewer {...viewerProps} file={pdfBlob} />\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * The PDF (or media) body of the document viewer: loading and failure states, the image, audio and\n * video players, and the PDF with its tools \u2014 the markup layer, signature placement, a signature\n * request being prepared or signed.\n */\n\nimport { lazy, Suspense, useCallback } from 'react'\nimport { useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport type {\n SignatureAppearance,\n SignatureRequest,\n useDocumentMarkup,\n} from '@arbidocs/react/document-tools'\nimport {\n AudioViewer,\n ImageViewer,\n PdfViewer as KitPdfViewer,\n VideoViewer,\n type PdfViewerProps,\n} from '@arbidocs/react/viewers'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport { ViewerLoadError, ViewerMessage, ViewerPreviewUnavailable } from '../../files'\nimport { usePdfClipOutlines } from './pdf/usePdfClipOutlines'\nimport { usePdfPassageHighlights } from './pdf/usePdfPassageHighlights'\nimport { useViewerIsDetached } from './support'\nimport { isLegacyPresentationFile } from '../../presentation/panel-id'\nimport { PresentationFileCard } from '../presentation/PresentationFileCard'\nimport { fileExtension, type ViewedDocument } from './useViewedDocument'\n\n// The markup viewer brings in pdf-lib, which nothing else needs: load it only when it is shown.\nconst AnnotatedPdfViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.AnnotatedPdfViewer }))\n)\nconst SignaturePlacementViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.SignaturePlacementViewer }))\n)\n// Signature requests: placing fields for signers, and a signer's guided signing.\nconst SignatureRequestEditor = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.SignatureRequestEditor }))\n)\n// Clip mode for the presentation: its own chunk (the presentation module).\nconst ClippingPdfViewer = lazy(() =>\n import('../presentation/ClippingPdfViewer').then((m) => ({ default: m.ClippingPdfViewer }))\n)\nconst ClippingMediaViewer = lazy(() =>\n import('../presentation/ClippingMediaViewer').then((m) => ({ default: m.ClippingMediaViewer }))\n)\nconst GuidedSigningViewer = lazy(() =>\n import('../../document-tools/viewer').then((m) => ({ default: m.GuidedSigningViewer }))\n)\n\n/** A signature request: the author placing fields, or a signer walked through theirs. */\nexport type SignatureFlow =\n | { kind: 'prepare'; draft?: SignatureRequest; self?: boolean }\n | { kind: 'sign'; request: SignatureRequest }\n | null\n\n/**\n * The kit PDF viewer, reporting the page read into the session state; in a detached window its\n * pages render without the opener's web fonts (canvas text in another document cannot use them).\n */\nfunction SessionPdfViewer(props: Omit<PdfViewerProps, 'onPageChange' | 'disableFontFace'>) {\n const session = useArbiSessionStore()\n const viewingId = useArbiSessionState((s) => s.viewingDocument?.id)\n const isDetached = useViewerIsDetached()\n const onPageChange = useCallback(\n (page: number) => {\n if (viewingId) session.setViewingDocument({ id: viewingId, page })\n },\n [session, viewingId]\n )\n // The passages a citation lights, over their pages, under whatever the mode draws (markup).\n const passageHighlights = usePdfPassageHighlights(viewingId)\n // The open presentation's clips of this document, where they were cut.\n const clipOutlines = usePdfClipOutlines(viewingId)\n const { renderPageOverlay: modeOverlay } = props\n const renderPageOverlay = useCallback<NonNullable<PdfViewerProps['renderPageOverlay']>>(\n (page) => (\n <>\n {passageHighlights(page.pageNumber)}\n {clipOutlines(page.pageNumber)}\n {modeOverlay?.(page)}\n </>\n ),\n [passageHighlights, clipOutlines, modeOverlay]\n )\n return (\n <KitPdfViewer\n {...props}\n renderPageOverlay={renderPageOverlay}\n onPageChange={onPageChange}\n disableFontFace={!!isDetached}\n />\n )\n}\n\nexport interface ViewerPdfPaneProps {\n documentId: string\n doc: ViewedDocument\n pdfBlob: Blob | null\n isPdfLoading: boolean\n pdfError: unknown\n onDownload: () => void\n viewerProps: {\n currentPage: number | undefined\n onLoadSuccess: (pages: number) => void\n scrollTrigger: number\n zoom: number\n onZoomChange: (zoom: number) => void\n }\n signatureFlow: SignatureFlow\n onSignatureFlow: (flow: SignatureFlow) => void\n currentUserId: string | undefined\n placingSignature: boolean\n onPlacingDone: (appearance?: SignatureAppearance) => void\n annotating: boolean\n /** Clip mode: dragging over a page adds that area to the presentation. */\n clipping?: boolean\n markup: ReturnType<typeof useDocumentMarkup>\n pdfSnapshotNumber: number | undefined\n isSigned: boolean\n /** One's saved signature or initials to place as a picture stamp (PDF tab \u203A My signature). */\n placeMark?: { image: string; label: string; key: number } | null\n}\n\nexport function ViewerPdfPane({\n documentId,\n doc,\n pdfBlob,\n isPdfLoading,\n pdfError,\n onDownload,\n viewerProps,\n signatureFlow,\n onSignatureFlow,\n currentUserId,\n placingSignature,\n onPlacingDone,\n annotating,\n clipping = false,\n markup,\n pdfSnapshotNumber,\n isSigned,\n placeMark = null,\n}: ViewerPdfPaneProps) {\n const { documentData, isDownloadOnly, isVideo, isAudio, isImage, isDocx } = doc\n const showMarkup = markup.hasMarkup && !markup.showOriginal\n\n // A presentation saved before it was a PDF (its data alone): what it is, and Edit presentation.\n if (isLegacyPresentationFile(documentData?.file_name)) {\n return <PresentationFileCard documentId={documentId} fileName={documentData?.file_name ?? ''} />\n }\n\n // Files that cannot be previewed in the browser: the download, at once.\n if (isDownloadOnly) {\n return (\n <ViewerPreviewUnavailable\n extension={fileExtension(documentData?.file_name)}\n onDownload={onDownload}\n />\n )\n }\n\n // Text files are rendered to a PDF too, so name what the user opened, not the rendering.\n const loadingLabel = isVideo\n ? 'Loading video...'\n : isAudio\n ? 'Loading audio...'\n : isImage\n ? 'Loading image...'\n : !documentData\n ? 'Loading document...'\n : friendlyFileType(documentData.file_type, documentData.file_name) === 'Text'\n ? 'Loading text...'\n : 'Loading PDF...'\n const errorLabel = isVideo\n ? 'Failed to load video'\n : isAudio\n ? 'Failed to load audio'\n : isImage\n ? 'Failed to load image'\n : 'Failed to load PDF'\n\n if (\n isDocx &&\n !pdfSnapshotNumber &&\n documentData &&\n !['completed', 'low-content', 'failed'].includes(documentData.status || '')\n ) {\n return (\n <ViewerMessage>\n PDF and search indexing are processing. Open the DOCX tab to edit now.\n </ViewerMessage>\n )\n }\n if (isDocx && !pdfSnapshotNumber && documentData?.status === 'failed') {\n return (\n <ViewerMessage>\n PDF conversion failed. Open the Word editor or download the document.\n </ViewerMessage>\n )\n }\n if (isPdfLoading) return <ViewerMessage>{loadingLabel}</ViewerMessage>\n if (pdfError) {\n return (\n <ViewerLoadError\n message={\n isVideo || isAudio || isImage\n ? `${errorLabel} \u2014 download it instead.`\n : \"Couldn't display the PDF \u2014 download it instead.\"\n }\n onDownload={onDownload}\n />\n )\n }\n // Nothing is fetched yet: the PDF is read once the document record has loaded, so the viewer\n // would otherwise sit empty for that first stretch.\n if (!pdfBlob) return <ViewerMessage>{loadingLabel}</ViewerMessage>\n\n // Clip mode on an image or a video: drag over it for the presentation.\n if (clipping && (isImage || isVideo)) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <ClippingMediaViewer\n file={pdfBlob}\n kind={isVideo ? 'video' : 'image'}\n documentId={documentId}\n fileName={documentData?.file_name || (isVideo ? 'Video' : 'Image')}\n />\n </Suspense>\n )\n }\n if (isVideo) return <VideoViewer blob={pdfBlob} title={documentData?.file_name || 'Video'} />\n if (isAudio) return <AudioViewer blob={pdfBlob} title={documentData?.file_name || 'Audio'} />\n if (isImage) {\n return <ImageViewer blob={pdfBlob} alt={documentData?.file_name || 'Document image'} />\n }\n if (signatureFlow?.kind === 'prepare') {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <SignatureRequestEditor\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber ?? documentData?.current_version ?? undefined}\n selfSigning={signatureFlow.self}\n draft={signatureFlow.draft}\n shareFile={!signatureFlow.draft}\n viewer={SessionPdfViewer}\n onCancel={() => onSignatureFlow(null)}\n onSaved={() => onSignatureFlow(null)}\n />\n </Suspense>\n )\n }\n if (signatureFlow?.kind === 'sign' && currentUserId) {\n const { currentPage: _page, scrollTrigger: _trigger, ...guidedProps } = viewerProps\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <GuidedSigningViewer\n {...guidedProps}\n file={pdfBlob}\n request={signatureFlow.request}\n signer={currentUserId}\n viewer={SessionPdfViewer}\n onClose={() => onSignatureFlow(null)}\n onSigned={() => onSignatureFlow(null)}\n />\n </Suspense>\n )\n }\n if (placingSignature) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <SignaturePlacementViewer\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n viewer={SessionPdfViewer}\n onCancel={() => onPlacingDone()}\n onContinue={(appearance) => onPlacingDone(appearance)}\n />\n </Suspense>\n )\n }\n if (clipping) {\n return (\n <Suspense fallback={<ViewerMessage>Loading\u2026</ViewerMessage>}>\n <ClippingPdfViewer\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber}\n fileName={documentData?.file_name || 'Document'}\n hasMarkup={markup.hasMarkup}\n viewer={SessionPdfViewer}\n />\n </Suspense>\n )\n }\n // Annotate mode, or the markup as the reading view: one viewer, so leaving annotate mode keeps\n // (and saves) what was just drawn.\n if (annotating || showMarkup) {\n return (\n <Suspense\n fallback={\n <ViewerMessage>\n {annotating ? 'Loading annotation tools\u2026' : 'Loading markup\u2026'}\n </ViewerMessage>\n }\n >\n <AnnotatedPdfViewer\n key={`${documentId}@${pdfSnapshotNumber ?? 'current'}`}\n {...viewerProps}\n file={pdfBlob}\n documentId={documentId}\n version={pdfSnapshotNumber}\n editing={annotating}\n onMarkupChange={markup.onMarkupChange}\n fileName={documentData?.file_name}\n shared={documentData?.shared ?? false}\n folder={documentData?.folder}\n workspaceId={documentData?.workspace_ext_id}\n viewer={SessionPdfViewer}\n signed={isSigned}\n placeStamp={placeMark}\n />\n </Suspense>\n )\n }\n return <SessionPdfViewer {...viewerProps} file={pdfBlob} />\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -20,11 +20,12 @@ export interface DocumentPlace {
20
20
  }
21
21
  /**
22
22
  * Open a place in the session's viewer: the document at its page (else the first), its passage
23
- * marked (else none, so a passage of the document open before never carries over). A passage or a
24
- * page opens the text view, where passages are marked, unless the place asks for the PDF;
25
- * otherwise the PDF.
23
+ * marked (else none, so a passage of the document open before never carries over), on the PDF: a
24
+ * passage is lit there, in the box the parser found it in. A passage the parser could not place on
25
+ * its page (a document parsed before passages had boxes) is shown on the text view instead
26
+ * (`usePdfPassageHighlights`).
26
27
  */
27
- export declare function showDocumentPlace(session: Pick<ArbiSessionStore, 'setViewingDocument' | 'setDocumentViewer'>, { documentId, passageId, page, tab }: DocumentPlace): void;
28
+ export declare function showDocumentPlace(session: Pick<ArbiSessionStore, 'setViewingDocument' | 'setDocumentViewer'>, { documentId, passageId, page }: DocumentPlace): void;
28
29
  /** One key per place: two links to the same place are the same link. */
29
30
  export declare function documentPlaceKey(place: DocumentPlace | null | undefined): string | null;
30
31
  /**
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- function showDocumentPlace(session, { documentId, passageId, page, tab }) {
2
+ function showDocumentPlace(session, { documentId, passageId, page }) {
3
3
  session.setViewingDocument({ id: documentId, page: page ?? 1, passageId: passageId ?? null });
4
- session.setDocumentViewer({ tab: tab !== "pdf" && (passageId || page) ? "html" : "pdf" });
4
+ session.setDocumentViewer({ tab: "pdf" });
5
5
  }
6
6
  function documentPlaceKey(place) {
7
7
  if (!place?.documentId) return null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/documentPlace.ts"],
4
- "sourcesContent": ["/**\n * Where a link opens a document: the document (or one of its versions, `doc-\u2026@v{n}`), at a cited\n * passage or a page. Every way into a document goes through one rule, `showDocumentPlace`, so a\n * citation, a deep link, a production's QR code and a click in a list land the same way.\n */\n\nimport type { ArbiSessionStore } from '@arbidocs/react'\nimport type { DocumentViewerTab } from './documentViewerTabs'\n\nexport interface DocumentPlace {\n /** The document, or a version reference `doc-\u2026@v{n}` (that version opens read-only). */\n documentId: string\n /** A passage (`cnk-\u2026`) to scroll to and mark. */\n passageId?: string | null\n /** A page to open on. */\n page?: number | null\n /**\n * The document itself (`pdf`, as the environment's `openDocument` asks): a copy the document\n * tools just made, a signature request.\n */\n tab?: 'pdf' | null\n}\n\n/**\n * Open a place in the session's viewer: the document at its page (else the first), its passage\n * marked (else none, so a passage of the document open before never carries over). A passage or a\n * page opens the text view, where passages are marked, unless the place asks for the PDF;\n * otherwise the PDF.\n */\nexport function showDocumentPlace(\n session: Pick<ArbiSessionStore, 'setViewingDocument' | 'setDocumentViewer'>,\n { documentId, passageId, page, tab }: DocumentPlace\n): void {\n session.setViewingDocument({ id: documentId, page: page ?? 1, passageId: passageId ?? null })\n session.setDocumentViewer({ tab: tab !== 'pdf' && (passageId || page) ? 'html' : 'pdf' })\n}\n\n/** One key per place: two links to the same place are the same link. */\nexport function documentPlaceKey(place: DocumentPlace | null | undefined): string | null {\n if (!place?.documentId) return null\n return `${place.documentId}|${place.passageId ?? ''}|${place.page ?? ''}|${place.tab ?? ''}`\n}\n\n/**\n * The dialog's first tab for a place: the PDF asked for, or a page alone, on the document itself; a\n * cited passage in the review; anything else on the first tab offered.\n */\nexport function dialogTabForPlace(\n place: DocumentPlace,\n tabs: readonly DocumentViewerTab[]\n): DocumentViewerTab | undefined {\n if (place.tab === 'pdf' && tabs.includes('document')) return 'document'\n if (place.passageId && tabs.includes('review')) return 'review'\n if (place.page && !place.passageId && tabs.includes('document')) return 'document'\n return tabs[0]\n}\n"],
5
- "mappings": ";AA6BO,SAAS,kBACd,SACA,EAAE,YAAY,WAAW,MAAM,IAAI,GAC7B;AACN,UAAQ,mBAAmB,EAAE,IAAI,YAAY,MAAM,QAAQ,GAAG,WAAW,aAAa,KAAK,CAAC;AAC5F,UAAQ,kBAAkB,EAAE,KAAK,QAAQ,UAAU,aAAa,QAAQ,SAAS,MAAM,CAAC;AAC1F;AAGO,SAAS,iBAAiB,OAAwD;AACvF,MAAI,CAAC,OAAO,WAAY,QAAO;AAC/B,SAAO,GAAG,MAAM,UAAU,IAAI,MAAM,aAAa,EAAE,IAAI,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,EAAE;AAC5F;AAMO,SAAS,kBACd,OACA,MAC+B;AAC/B,MAAI,MAAM,QAAQ,SAAS,KAAK,SAAS,UAAU,EAAG,QAAO;AAC7D,MAAI,MAAM,aAAa,KAAK,SAAS,QAAQ,EAAG,QAAO;AACvD,MAAI,MAAM,QAAQ,CAAC,MAAM,aAAa,KAAK,SAAS,UAAU,EAAG,QAAO;AACxE,SAAO,KAAK,CAAC;AACf;",
4
+ "sourcesContent": ["/**\n * Where a link opens a document: the document (or one of its versions, `doc-\u2026@v{n}`), at a cited\n * passage or a page. Every way into a document goes through one rule, `showDocumentPlace`, so a\n * citation, a deep link, a production's QR code and a click in a list land the same way.\n */\n\nimport type { ArbiSessionStore } from '@arbidocs/react'\nimport type { DocumentViewerTab } from './documentViewerTabs'\n\nexport interface DocumentPlace {\n /** The document, or a version reference `doc-\u2026@v{n}` (that version opens read-only). */\n documentId: string\n /** A passage (`cnk-\u2026`) to scroll to and mark. */\n passageId?: string | null\n /** A page to open on. */\n page?: number | null\n /**\n * The document itself (`pdf`, as the environment's `openDocument` asks): a copy the document\n * tools just made, a signature request.\n */\n tab?: 'pdf' | null\n}\n\n/**\n * Open a place in the session's viewer: the document at its page (else the first), its passage\n * marked (else none, so a passage of the document open before never carries over), on the PDF: a\n * passage is lit there, in the box the parser found it in. A passage the parser could not place on\n * its page (a document parsed before passages had boxes) is shown on the text view instead\n * (`usePdfPassageHighlights`).\n */\nexport function showDocumentPlace(\n session: Pick<ArbiSessionStore, 'setViewingDocument' | 'setDocumentViewer'>,\n { documentId, passageId, page }: DocumentPlace\n): void {\n session.setViewingDocument({ id: documentId, page: page ?? 1, passageId: passageId ?? null })\n session.setDocumentViewer({ tab: 'pdf' })\n}\n\n/** One key per place: two links to the same place are the same link. */\nexport function documentPlaceKey(place: DocumentPlace | null | undefined): string | null {\n if (!place?.documentId) return null\n return `${place.documentId}|${place.passageId ?? ''}|${place.page ?? ''}|${place.tab ?? ''}`\n}\n\n/**\n * The dialog's first tab for a place: the PDF asked for, or a page alone, on the document itself; a\n * cited passage in the review; anything else on the first tab offered.\n */\nexport function dialogTabForPlace(\n place: DocumentPlace,\n tabs: readonly DocumentViewerTab[]\n): DocumentViewerTab | undefined {\n if (place.tab === 'pdf' && tabs.includes('document')) return 'document'\n if (place.passageId && tabs.includes('review')) return 'review'\n if (place.page && !place.passageId && tabs.includes('document')) return 'document'\n return tabs[0]\n}\n"],
5
+ "mappings": ";AA8BO,SAAS,kBACd,SACA,EAAE,YAAY,WAAW,KAAK,GACxB;AACN,UAAQ,mBAAmB,EAAE,IAAI,YAAY,MAAM,QAAQ,GAAG,WAAW,aAAa,KAAK,CAAC;AAC5F,UAAQ,kBAAkB,EAAE,KAAK,MAAM,CAAC;AAC1C;AAGO,SAAS,iBAAiB,OAAwD;AACvF,MAAI,CAAC,OAAO,WAAY,QAAO;AAC/B,SAAO,GAAG,MAAM,UAAU,IAAI,MAAM,aAAa,EAAE,IAAI,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,EAAE;AAC5F;AAMO,SAAS,kBACd,OACA,MAC+B;AAC/B,MAAI,MAAM,QAAQ,SAAS,KAAK,SAAS,UAAU,EAAG,QAAO;AAC7D,MAAI,MAAM,aAAa,KAAK,SAAS,QAAQ,EAAG,QAAO;AACvD,MAAI,MAAM,QAAQ,CAAC,MAAM,aAAa,KAAK,SAAS,UAAU,EAAG,QAAO;AACxE,SAAO,KAAK,CAAC;AACf;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The open presentation's clips of this document, outlined on its PDF pages: where each clip was
3
+ * cut, and the slide it is on. The outline takes no pointer events (the page stays selectable);
4
+ * its label goes to that slide in the presentation.
5
+ */
6
+ import type { PdfClipOutline } from './clipOutlines';
7
+ export interface PdfClipOutlinesProps {
8
+ outlines: readonly PdfClipOutline[];
9
+ onShow: (outline: PdfClipOutline) => void;
10
+ }
11
+ export declare function PdfClipOutlines({ outlines, onShow }: PdfClipOutlinesProps): import("react").JSX.Element;
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Presentation } from "lucide-react";
4
+ function PdfClipOutlines({ outlines, onShow }) {
5
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0", "data-testid": "pdf-clip-outlines", children: outlines.map((outline) => {
6
+ const { rect } = outline;
7
+ const label = outline.slides.length ? `Slide ${outline.slides.map((index) => index + 1).join(", ")}` : "In the tray";
8
+ return /* @__PURE__ */ jsx(
9
+ "div",
10
+ {
11
+ className: "absolute rounded-sm border-2 border-dashed border-primary/70",
12
+ style: {
13
+ left: `${rect.x * 100}%`,
14
+ top: `${rect.y * 100}%`,
15
+ width: `${rect.w * 100}%`,
16
+ height: `${rect.h * 100}%`
17
+ },
18
+ "data-testid": "pdf-clip-outline",
19
+ "data-clip-id": outline.clipId,
20
+ children: /* @__PURE__ */ jsxs(
21
+ "button",
22
+ {
23
+ type: "button",
24
+ className: "pointer-events-auto absolute -top-2.5 left-1 inline-flex items-center gap-1 rounded-full bg-primary px-1.5 text-[10px] font-medium leading-4 text-primary-foreground shadow-sm hover:bg-primary/90",
25
+ title: outline.slides.length ? `Clipped for the presentation: go to ${label.toLowerCase()}` : "Clipped for the presentation: not on a slide yet",
26
+ onClick: () => onShow(outline),
27
+ "data-testid": "pdf-clip-outline-label",
28
+ children: [
29
+ /* @__PURE__ */ jsx(Presentation, { className: "size-2.5" }),
30
+ label
31
+ ]
32
+ }
33
+ )
34
+ },
35
+ outline.clipId
36
+ );
37
+ }) });
38
+ }
39
+ export {
40
+ PdfClipOutlines
41
+ };
42
+ //# sourceMappingURL=PdfClipOutlines.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/connection/viewer/pdf/PdfClipOutlines.tsx"],
4
+ "sourcesContent": ["/**\n * The open presentation's clips of this document, outlined on its PDF pages: where each clip was\n * cut, and the slide it is on. The outline takes no pointer events (the page stays selectable);\n * its label goes to that slide in the presentation.\n */\n\nimport { Presentation } from 'lucide-react'\nimport type { PdfClipOutline } from './clipOutlines'\n\nexport interface PdfClipOutlinesProps {\n outlines: readonly PdfClipOutline[]\n onShow: (outline: PdfClipOutline) => void\n}\n\nexport function PdfClipOutlines({ outlines, onShow }: PdfClipOutlinesProps) {\n return (\n <div className=\"pointer-events-none absolute inset-0\" data-testid=\"pdf-clip-outlines\">\n {outlines.map((outline) => {\n const { rect } = outline\n const label = outline.slides.length\n ? `Slide ${outline.slides.map((index) => index + 1).join(', ')}`\n : 'In the tray'\n return (\n <div\n key={outline.clipId}\n className=\"absolute rounded-sm border-2 border-dashed border-primary/70\"\n style={{\n left: `${rect.x * 100}%`,\n top: `${rect.y * 100}%`,\n width: `${rect.w * 100}%`,\n height: `${rect.h * 100}%`,\n }}\n data-testid=\"pdf-clip-outline\"\n data-clip-id={outline.clipId}\n >\n <button\n type=\"button\"\n className=\"pointer-events-auto absolute -top-2.5 left-1 inline-flex items-center gap-1 rounded-full bg-primary px-1.5 text-[10px] font-medium leading-4 text-primary-foreground shadow-sm hover:bg-primary/90\"\n title={\n outline.slides.length\n ? `Clipped for the presentation: go to ${label.toLowerCase()}`\n : 'Clipped for the presentation: not on a slide yet'\n }\n onClick={() => onShow(outline)}\n data-testid=\"pdf-clip-outline-label\"\n >\n <Presentation className=\"size-2.5\" />\n {label}\n </button>\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAmCY,SAWE,KAXF;AA7BZ,SAAS,oBAAoB;AAQtB,SAAS,gBAAgB,EAAE,UAAU,OAAO,GAAyB;AAC1E,SACE,oBAAC,SAAI,WAAU,wCAAuC,eAAY,qBAC/D,mBAAS,IAAI,CAAC,YAAY;AACzB,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,QAAQ,QAAQ,OAAO,SACzB,SAAS,QAAQ,OAAO,IAAI,CAAC,UAAU,QAAQ,CAAC,EAAE,KAAK,IAAI,CAAC,KAC5D;AACJ,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,MAAM,GAAG,KAAK,IAAI,GAAG;AAAA,UACrB,KAAK,GAAG,KAAK,IAAI,GAAG;AAAA,UACpB,OAAO,GAAG,KAAK,IAAI,GAAG;AAAA,UACtB,QAAQ,GAAG,KAAK,IAAI,GAAG;AAAA,QACzB;AAAA,QACA,eAAY;AAAA,QACZ,gBAAc,QAAQ;AAAA,QAEtB;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,OACE,QAAQ,OAAO,SACX,uCAAuC,MAAM,YAAY,CAAC,KAC1D;AAAA,YAEN,SAAS,MAAM,OAAO,OAAO;AAAA,YAC7B,eAAY;AAAA,YAEZ;AAAA,kCAAC,gBAAa,WAAU,YAAW;AAAA,cAClC;AAAA;AAAA;AAAA,QACH;AAAA;AAAA,MAxBK,QAAQ;AAAA,IAyBf;AAAA,EAEJ,CAAC,GACH;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Which of the open presentation's clips were cut from a document's pages, and the slides each is
3
+ * on: what the PDF outlines (`PdfClipOutlines`).
4
+ */
5
+ import type { Clip, Rect, Slide } from '../../../presentation/model';
6
+ export interface PdfClipOutline {
7
+ clipId: string;
8
+ /** The clipped area, as fractions of the page. */
9
+ rect: Rect;
10
+ /** The slides (indexes) it is on; none while it waits in the tray. */
11
+ slides: number[];
12
+ }
13
+ /**
14
+ * The page clips of the document `viewingId` names, by page number. A clip of another version of
15
+ * it is left out when a version is viewed; the parts of a slide's design (`plain`) are left out.
16
+ */
17
+ export declare function clipOutlinesByPage(viewingId: string | null | undefined, clips: readonly Clip[], slides: readonly Pick<Slide, 'items'>[]): Map<number, PdfClipOutline[]>;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ function parseRef(id) {
3
+ const match = /^(.*)@v(\d+)$/.exec(id);
4
+ return match ? { documentId: match[1], version: Number(match[2]) } : { documentId: id, version: null };
5
+ }
6
+ function clipOutlinesByPage(viewingId, clips, slides) {
7
+ const byPage = /* @__PURE__ */ new Map();
8
+ if (!viewingId) return byPage;
9
+ const { documentId, version } = parseRef(viewingId);
10
+ for (const clip of clips) {
11
+ if (clip.kind !== "pdf" || clip.plain || clip.documentId !== documentId) continue;
12
+ if (version !== null && clip.version !== void 0 && clip.version !== version) continue;
13
+ const on = slides.flatMap(
14
+ (slide, index) => slide.items.some((item) => item.clipId === clip.id) ? [index] : []
15
+ );
16
+ const outline = { clipId: clip.id, rect: clip.rect, slides: on };
17
+ byPage.set(clip.page, [...byPage.get(clip.page) ?? [], outline]);
18
+ }
19
+ return byPage;
20
+ }
21
+ export {
22
+ clipOutlinesByPage
23
+ };
24
+ //# sourceMappingURL=clipOutlines.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/connection/viewer/pdf/clipOutlines.ts"],
4
+ "sourcesContent": ["/**\n * Which of the open presentation's clips were cut from a document's pages, and the slides each is\n * on: what the PDF outlines (`PdfClipOutlines`).\n */\n\nimport type { Clip, Rect, Slide } from '../../../presentation/model'\n\nexport interface PdfClipOutline {\n clipId: string\n /** The clipped area, as fractions of the page. */\n rect: Rect\n /** The slides (indexes) it is on; none while it waits in the tray. */\n slides: number[]\n}\n\n/** The document a viewer id names, and its version (`doc-\u2026@v{n}`), if one. */\nfunction parseRef(id: string): { documentId: string; version: number | null } {\n const match = /^(.*)@v(\\d+)$/.exec(id)\n return match\n ? { documentId: match[1], version: Number(match[2]) }\n : { documentId: id, version: null }\n}\n\n/**\n * The page clips of the document `viewingId` names, by page number. A clip of another version of\n * it is left out when a version is viewed; the parts of a slide's design (`plain`) are left out.\n */\nexport function clipOutlinesByPage(\n viewingId: string | null | undefined,\n clips: readonly Clip[],\n slides: readonly Pick<Slide, 'items'>[]\n): Map<number, PdfClipOutline[]> {\n const byPage = new Map<number, PdfClipOutline[]>()\n if (!viewingId) return byPage\n const { documentId, version } = parseRef(viewingId)\n for (const clip of clips) {\n if (clip.kind !== 'pdf' || clip.plain || clip.documentId !== documentId) continue\n if (version !== null && clip.version !== undefined && clip.version !== version) continue\n const on = slides.flatMap((slide, index) =>\n slide.items.some((item) => item.clipId === clip.id) ? [index] : []\n )\n const outline = { clipId: clip.id, rect: clip.rect, slides: on }\n byPage.set(clip.page, [...(byPage.get(clip.page) ?? []), outline])\n }\n return byPage\n}\n"],
5
+ "mappings": ";AAgBA,SAAS,SAAS,IAA4D;AAC5E,QAAM,QAAQ,gBAAgB,KAAK,EAAE;AACrC,SAAO,QACH,EAAE,YAAY,MAAM,CAAC,GAAG,SAAS,OAAO,MAAM,CAAC,CAAC,EAAE,IAClD,EAAE,YAAY,IAAI,SAAS,KAAK;AACtC;AAMO,SAAS,mBACd,WACA,OACA,QAC+B;AAC/B,QAAM,SAAS,oBAAI,IAA8B;AACjD,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,EAAE,YAAY,QAAQ,IAAI,SAAS,SAAS;AAClD,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,SAAS,KAAK,SAAS,KAAK,eAAe,WAAY;AACzE,QAAI,YAAY,QAAQ,KAAK,YAAY,UAAa,KAAK,YAAY,QAAS;AAChF,UAAM,KAAK,OAAO;AAAA,MAAQ,CAAC,OAAO,UAChC,MAAM,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC;AAAA,IACnE;AACA,UAAM,UAAU,EAAE,QAAQ,KAAK,IAAI,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC/D,WAAO,IAAI,KAAK,MAAM,CAAC,GAAI,OAAO,IAAI,KAAK,IAAI,KAAK,CAAC,GAAI,OAAO,CAAC;AAAA,EACnE;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -22,5 +22,7 @@ export interface PassageHighlightState {
22
22
  }
23
23
  /** How a passage is lit, or null when it is not. */
24
24
  export declare function passageHighlight(chunkId: string, { cited, active }: PassageHighlightState): PassageHighlight | null;
25
+ /** The passage has a box on its page to light (not none, nor the whole page). */
26
+ export declare function passagePlaced(pages: readonly ProcessedPage[], chunkId: string): boolean;
25
27
  /** The lit passages' boxes, by page number. Passages without a usable box are left out. */
26
28
  export declare function passageBoxesByPage(pages: readonly ProcessedPage[], state: PassageHighlightState): Map<number, PdfPassageBox[]>;
@@ -15,6 +15,16 @@ function asBox(bbox) {
15
15
  function isWholePage([x0, y0, x1, y1]) {
16
16
  return x0 <= 0 && y0 <= 0 && x1 >= 1 && y1 >= 1;
17
17
  }
18
+ function passagePlaced(pages, chunkId) {
19
+ for (const page of pages) {
20
+ const chunk = page.chunks.find((entry) => entry.chunkExtId === chunkId);
21
+ if (chunk) {
22
+ const box = asBox(chunk.pageBbox);
23
+ return !!box && !isWholePage(box);
24
+ }
25
+ }
26
+ return false;
27
+ }
18
28
  function passageBoxesByPage(pages, state) {
19
29
  const byPage = /* @__PURE__ */ new Map();
20
30
  if (state.cited.size === 0 && !state.active) return byPage;
@@ -35,6 +45,7 @@ function passageBoxesByPage(pages, state) {
35
45
  }
36
46
  export {
37
47
  passageBoxesByPage,
38
- passageHighlight
48
+ passageHighlight,
49
+ passagePlaced
39
50
  };
40
51
  //# sourceMappingURL=passageHighlights.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/connection/viewer/pdf/passageHighlights.ts"],
4
- "sourcesContent": ["/**\n * Which passages light up on the PDF, and where. The rules are the parsed view's (`ParsedPassage`):\n * while a fact's Citation popover is open its cited passages are light and the one being read is\n * strong; otherwise the passage a citation opened the document at is the one lit. A passage's box\n * is the parser's (`page_bbox`: fractions of its page, top-left origin), so it lands on the page\n * at any zoom.\n */\n\nimport type { ProcessedPage } from '@arbidocs/react/viewers'\nimport type { PassageHighlight } from '../../../files'\n\n/** [x0, y0, x1, y1] as fractions of the page. */\nexport type PageBox = readonly [number, number, number, number]\n\nexport interface PdfPassageBox {\n chunkId: string\n box: PageBox\n highlight: PassageHighlight\n}\n\nexport interface PassageHighlightState {\n /** A fact's cited passages (its Citation popover is open); empty when none is. */\n cited: ReadonlySet<string>\n /** The passage being read: the one a citation opened the document at. */\n active: string | null\n}\n\n/** How a passage is lit, or null when it is not. */\nexport function passageHighlight(\n chunkId: string,\n { cited, active }: PassageHighlightState\n): PassageHighlight | null {\n if (cited.size > 0) {\n if (!cited.has(chunkId)) return null\n return chunkId === active ? 'strong' : 'light'\n }\n return chunkId === active ? 'light' : null\n}\n\n/** A drawable box: four finite fractions with area. */\nfunction asBox(bbox: readonly number[] | undefined): PageBox | null {\n if (!bbox || bbox.length !== 4 || !bbox.every(Number.isFinite)) return null\n const [x0, y0, x1, y1] = bbox\n if (x1 <= x0 || y1 <= y0) return null\n return [x0, y0, x1, y1]\n}\n\n/**\n * The page's whole area: what the parser gives a chunk on a page where it recognized no block to\n * place it by. It says \"this page\", and a rectangle over the whole page would say nothing more.\n */\nfunction isWholePage([x0, y0, x1, y1]: PageBox): boolean {\n return x0 <= 0 && y0 <= 0 && x1 >= 1 && y1 >= 1\n}\n\n/** The lit passages' boxes, by page number. Passages without a usable box are left out. */\nexport function passageBoxesByPage(\n pages: readonly ProcessedPage[],\n state: PassageHighlightState\n): Map<number, PdfPassageBox[]> {\n const byPage = new Map<number, PdfPassageBox[]>()\n if (state.cited.size === 0 && !state.active) return byPage\n for (const page of pages) {\n if (page.pageNumber === null) continue\n for (const chunk of page.chunks) {\n const chunkId = chunk.chunkExtId\n if (!chunkId) continue\n const highlight = passageHighlight(chunkId, state)\n const box = highlight && asBox(chunk.pageBbox)\n if (!highlight || !box || isWholePage(box)) continue\n const boxes = byPage.get(page.pageNumber) ?? []\n boxes.push({ chunkId, box, highlight })\n byPage.set(page.pageNumber, boxes)\n }\n }\n return byPage\n}\n"],
5
- "mappings": ";AA4BO,SAAS,iBACd,SACA,EAAE,OAAO,OAAO,GACS;AACzB,MAAI,MAAM,OAAO,GAAG;AAClB,QAAI,CAAC,MAAM,IAAI,OAAO,EAAG,QAAO;AAChC,WAAO,YAAY,SAAS,WAAW;AAAA,EACzC;AACA,SAAO,YAAY,SAAS,UAAU;AACxC;AAGA,SAAS,MAAM,MAAqD;AAClE,MAAI,CAAC,QAAQ,KAAK,WAAW,KAAK,CAAC,KAAK,MAAM,OAAO,QAAQ,EAAG,QAAO;AACvE,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI;AACzB,MAAI,MAAM,MAAM,MAAM,GAAI,QAAO;AACjC,SAAO,CAAC,IAAI,IAAI,IAAI,EAAE;AACxB;AAMA,SAAS,YAAY,CAAC,IAAI,IAAI,IAAI,EAAE,GAAqB;AACvD,SAAO,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;AAChD;AAGO,SAAS,mBACd,OACA,OAC8B;AAC9B,QAAM,SAAS,oBAAI,IAA6B;AAChD,MAAI,MAAM,MAAM,SAAS,KAAK,CAAC,MAAM,OAAQ,QAAO;AACpD,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,eAAe,KAAM;AAC9B,eAAW,SAAS,KAAK,QAAQ;AAC/B,YAAM,UAAU,MAAM;AACtB,UAAI,CAAC,QAAS;AACd,YAAM,YAAY,iBAAiB,SAAS,KAAK;AACjD,YAAM,MAAM,aAAa,MAAM,MAAM,QAAQ;AAC7C,UAAI,CAAC,aAAa,CAAC,OAAO,YAAY,GAAG,EAAG;AAC5C,YAAM,QAAQ,OAAO,IAAI,KAAK,UAAU,KAAK,CAAC;AAC9C,YAAM,KAAK,EAAE,SAAS,KAAK,UAAU,CAAC;AACtC,aAAO,IAAI,KAAK,YAAY,KAAK;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["/**\n * Which passages light up on the PDF, and where. The rules are the parsed view's (`ParsedPassage`):\n * while a fact's Citation popover is open its cited passages are light and the one being read is\n * strong; otherwise the passage a citation opened the document at is the one lit. A passage's box\n * is the parser's (`page_bbox`: fractions of its page, top-left origin), so it lands on the page\n * at any zoom.\n */\n\nimport type { ProcessedPage } from '@arbidocs/react/viewers'\nimport type { PassageHighlight } from '../../../files'\n\n/** [x0, y0, x1, y1] as fractions of the page. */\nexport type PageBox = readonly [number, number, number, number]\n\nexport interface PdfPassageBox {\n chunkId: string\n box: PageBox\n highlight: PassageHighlight\n}\n\nexport interface PassageHighlightState {\n /** A fact's cited passages (its Citation popover is open); empty when none is. */\n cited: ReadonlySet<string>\n /** The passage being read: the one a citation opened the document at. */\n active: string | null\n}\n\n/** How a passage is lit, or null when it is not. */\nexport function passageHighlight(\n chunkId: string,\n { cited, active }: PassageHighlightState\n): PassageHighlight | null {\n if (cited.size > 0) {\n if (!cited.has(chunkId)) return null\n return chunkId === active ? 'strong' : 'light'\n }\n return chunkId === active ? 'light' : null\n}\n\n/** A drawable box: four finite fractions with area. */\nfunction asBox(bbox: readonly number[] | undefined): PageBox | null {\n if (!bbox || bbox.length !== 4 || !bbox.every(Number.isFinite)) return null\n const [x0, y0, x1, y1] = bbox\n if (x1 <= x0 || y1 <= y0) return null\n return [x0, y0, x1, y1]\n}\n\n/**\n * The page's whole area: what the parser gives a chunk on a page where it recognized no block to\n * place it by. It says \"this page\", and a rectangle over the whole page would say nothing more.\n */\nfunction isWholePage([x0, y0, x1, y1]: PageBox): boolean {\n return x0 <= 0 && y0 <= 0 && x1 >= 1 && y1 >= 1\n}\n\n/** The passage has a box on its page to light (not none, nor the whole page). */\nexport function passagePlaced(pages: readonly ProcessedPage[], chunkId: string): boolean {\n for (const page of pages) {\n const chunk = page.chunks.find((entry) => entry.chunkExtId === chunkId)\n if (chunk) {\n const box = asBox(chunk.pageBbox)\n return !!box && !isWholePage(box)\n }\n }\n return false\n}\n\n/** The lit passages' boxes, by page number. Passages without a usable box are left out. */\nexport function passageBoxesByPage(\n pages: readonly ProcessedPage[],\n state: PassageHighlightState\n): Map<number, PdfPassageBox[]> {\n const byPage = new Map<number, PdfPassageBox[]>()\n if (state.cited.size === 0 && !state.active) return byPage\n for (const page of pages) {\n if (page.pageNumber === null) continue\n for (const chunk of page.chunks) {\n const chunkId = chunk.chunkExtId\n if (!chunkId) continue\n const highlight = passageHighlight(chunkId, state)\n const box = highlight && asBox(chunk.pageBbox)\n if (!highlight || !box || isWholePage(box)) continue\n const boxes = byPage.get(page.pageNumber) ?? []\n boxes.push({ chunkId, box, highlight })\n byPage.set(page.pageNumber, boxes)\n }\n }\n return byPage\n}\n"],
5
+ "mappings": ";AA4BO,SAAS,iBACd,SACA,EAAE,OAAO,OAAO,GACS;AACzB,MAAI,MAAM,OAAO,GAAG;AAClB,QAAI,CAAC,MAAM,IAAI,OAAO,EAAG,QAAO;AAChC,WAAO,YAAY,SAAS,WAAW;AAAA,EACzC;AACA,SAAO,YAAY,SAAS,UAAU;AACxC;AAGA,SAAS,MAAM,MAAqD;AAClE,MAAI,CAAC,QAAQ,KAAK,WAAW,KAAK,CAAC,KAAK,MAAM,OAAO,QAAQ,EAAG,QAAO;AACvE,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI;AACzB,MAAI,MAAM,MAAM,MAAM,GAAI,QAAO;AACjC,SAAO,CAAC,IAAI,IAAI,IAAI,EAAE;AACxB;AAMA,SAAS,YAAY,CAAC,IAAI,IAAI,IAAI,EAAE,GAAqB;AACvD,SAAO,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;AAChD;AAGO,SAAS,cAAc,OAAiC,SAA0B;AACvF,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,eAAe,OAAO;AACtE,QAAI,OAAO;AACT,YAAM,MAAM,MAAM,MAAM,QAAQ;AAChC,aAAO,CAAC,CAAC,OAAO,CAAC,YAAY,GAAG;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,mBACd,OACA,OAC8B;AAC9B,QAAM,SAAS,oBAAI,IAA6B;AAChD,MAAI,MAAM,MAAM,SAAS,KAAK,CAAC,MAAM,OAAQ,QAAO;AACpD,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,eAAe,KAAM;AAC9B,eAAW,SAAS,KAAK,QAAQ;AAC/B,YAAM,UAAU,MAAM;AACtB,UAAI,CAAC,QAAS;AACd,YAAM,YAAY,iBAAiB,SAAS,KAAK;AACjD,YAAM,MAAM,aAAa,MAAM,MAAM,QAAQ;AAC7C,UAAI,CAAC,aAAa,CAAC,OAAO,YAAY,GAAG,EAAG;AAC5C,YAAM,QAAQ,OAAO,IAAI,KAAK,UAAU,KAAK,CAAC;AAC9C,YAAM,KAAK,EAAE,SAAS,KAAK,UAAU,CAAC;AACtC,aAAO,IAAI,KAAK,YAAY,KAAK;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The open presentation's clips of the viewed document, outlined over its PDF pages
3
+ * (`clipOutlinesByPage`); a label goes to the clip's slide in the presentation.
4
+ */
5
+ import { type ReactNode } from 'react';
6
+ /** A PDF viewer's page overlay: `(page) => outlines | null`. */
7
+ export declare function usePdfClipOutlines(viewingId: string | null | undefined): (pageNumber: number) => ReactNode;
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useCallback, useMemo } from "react";
4
+ import { useArbiSessionStore } from "@arbidocs/react";
5
+ import { usePresentation } from "../../../presentation/store.js";
6
+ import { showPresentation } from "../../presentation/requests.js";
7
+ import { PdfClipOutlines } from "./PdfClipOutlines.js";
8
+ import { clipOutlinesByPage } from "./clipOutlines.js";
9
+ function usePdfClipOutlines(viewingId) {
10
+ const session = useArbiSessionStore();
11
+ const clips = usePresentation((s) => s.clips);
12
+ const slides = usePresentation((s) => s.slides);
13
+ const byPage = useMemo(
14
+ () => clipOutlinesByPage(viewingId, clips, slides),
15
+ [viewingId, clips, slides]
16
+ );
17
+ const show = useCallback(
18
+ (outline) => {
19
+ const state = usePresentation.getState();
20
+ if (outline.slides.length) state.goTo(outline.slides[0]);
21
+ showPresentation(session, state.boundTo);
22
+ },
23
+ [session]
24
+ );
25
+ return useCallback(
26
+ (pageNumber) => {
27
+ const outlines = byPage.get(pageNumber);
28
+ return outlines ? /* @__PURE__ */ jsx(PdfClipOutlines, { outlines, onShow: show }) : null;
29
+ },
30
+ [byPage, show]
31
+ );
32
+ }
33
+ export {
34
+ usePdfClipOutlines
35
+ };
36
+ //# sourceMappingURL=usePdfClipOutlines.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/connection/viewer/pdf/usePdfClipOutlines.tsx"],
4
+ "sourcesContent": ["/**\n * The open presentation's clips of the viewed document, outlined over its PDF pages\n * (`clipOutlinesByPage`); a label goes to the clip's slide in the presentation.\n */\n\nimport { useCallback, useMemo, type ReactNode } from 'react'\nimport { useArbiSessionStore } from '@arbidocs/react'\nimport { usePresentation } from '../../../presentation/store'\nimport { showPresentation } from '../../presentation/requests'\nimport { PdfClipOutlines } from './PdfClipOutlines'\nimport { clipOutlinesByPage, type PdfClipOutline } from './clipOutlines'\n\n/** A PDF viewer's page overlay: `(page) => outlines | null`. */\nexport function usePdfClipOutlines(\n viewingId: string | null | undefined\n): (pageNumber: number) => ReactNode {\n const session = useArbiSessionStore()\n const clips = usePresentation((s) => s.clips)\n const slides = usePresentation((s) => s.slides)\n const byPage = useMemo(\n () => clipOutlinesByPage(viewingId, clips, slides),\n [viewingId, clips, slides]\n )\n const show = useCallback(\n (outline: PdfClipOutline) => {\n const state = usePresentation.getState()\n if (outline.slides.length) state.goTo(outline.slides[0])\n showPresentation(session, state.boundTo)\n },\n [session]\n )\n return useCallback(\n (pageNumber: number) => {\n const outlines = byPage.get(pageNumber)\n return outlines ? <PdfClipOutlines outlines={outlines} onShow={show} /> : null\n },\n [byPage, show]\n )\n}\n"],
5
+ "mappings": ";AAkCwB;AA7BxB,SAAS,aAAa,eAA+B;AACrD,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,0BAA+C;AAGjD,SAAS,mBACd,WACmC;AACnC,QAAM,UAAU,oBAAoB;AACpC,QAAM,QAAQ,gBAAgB,CAAC,MAAM,EAAE,KAAK;AAC5C,QAAM,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM;AAC9C,QAAM,SAAS;AAAA,IACb,MAAM,mBAAmB,WAAW,OAAO,MAAM;AAAA,IACjD,CAAC,WAAW,OAAO,MAAM;AAAA,EAC3B;AACA,QAAM,OAAO;AAAA,IACX,CAAC,YAA4B;AAC3B,YAAM,QAAQ,gBAAgB,SAAS;AACvC,UAAI,QAAQ,OAAO,OAAQ,OAAM,KAAK,QAAQ,OAAO,CAAC,CAAC;AACvD,uBAAiB,SAAS,MAAM,OAAO;AAAA,IACzC;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AACA,SAAO;AAAA,IACL,CAAC,eAAuB;AACtB,YAAM,WAAW,OAAO,IAAI,UAAU;AACtC,aAAO,WAAW,oBAAC,mBAAgB,UAAoB,QAAQ,MAAM,IAAK;AAAA,IAC5E;AAAA,IACA,CAAC,QAAQ,IAAI;AAAA,EACf;AACF;",
6
+ "names": []
7
+ }
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useMemo, useRef } from "react";
4
- import { useArbiSessionState, useParsedDocument } from "@arbidocs/react";
4
+ import { useArbiSessionState, useArbiSessionStore, useParsedDocument } from "@arbidocs/react";
5
5
  import { useProcessedChunks } from "@arbidocs/react/viewers";
6
6
  import { useViewerPassageCitation } from "../support.js";
7
7
  import { PdfPassageHighlights } from "./PdfPassageHighlights.js";
8
- import { passageBoxesByPage } from "./passageHighlights.js";
8
+ import { passageBoxesByPage, passagePlaced } from "./passageHighlights.js";
9
9
  const NONE = [];
10
10
  const NO_FOOTNOTES = {};
11
11
  function usePdfPassageHighlights(documentId) {
@@ -20,6 +20,15 @@ function usePdfPassageHighlights(documentId) {
20
20
  () => passageBoxesByPage(processedChunks, { cited, active }),
21
21
  [processedChunks, cited, active]
22
22
  );
23
+ const session = useArbiSessionStore();
24
+ const fellBackFor = useRef(null);
25
+ useEffect(() => {
26
+ if (!active || !parsed || !documentId) return;
27
+ const key = `${documentId}:${active}`;
28
+ if (fellBackFor.current === key || passagePlaced(processedChunks, active)) return;
29
+ fellBackFor.current = key;
30
+ session.setDocumentViewer({ tab: "html" });
31
+ }, [active, parsed, processedChunks, documentId, session]);
23
32
  const centredFor = useRef(null);
24
33
  const activeKey = active ? `${documentId}:${active}` : null;
25
34
  useEffect(() => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/connection/viewer/pdf/usePdfPassageHighlights.tsx"],
4
- "sourcesContent": ["/**\n * The passages a citation lights, drawn over the PDF page by page: a fact's cited passages (its\n * Citation popover is open) and the passage a citation opened the document at, as the parsed view\n * lights them. Nothing is fetched until one is lit; the parsed chunks are the parsed view's own\n * query, so opening that tab afterwards costs nothing more.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useArbiSessionState, useParsedDocument } from '@arbidocs/react'\nimport { useProcessedChunks } from '@arbidocs/react/viewers'\nimport { useViewerPassageCitation } from '../support'\nimport { PdfPassageHighlights } from './PdfPassageHighlights'\nimport { passageBoxesByPage } from './passageHighlights'\n\nconst NONE: readonly string[] = []\nconst NO_FOOTNOTES: Record<string, string> = {}\n\n/** A PDF viewer's page overlay for the document being viewed: `(page) => highlights | null`. */\nexport function usePdfPassageHighlights(\n documentId: string | undefined\n): (pageNumber: number) => ReactNode {\n const citedIds = useViewerPassageCitation()?.highlighted ?? NONE\n const cited = useMemo(() => new Set(citedIds), [citedIds])\n const active = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null)\n\n const { data: parsed } = useParsedDocument(documentId, 'final', {\n enabled: cited.size > 0 || !!active,\n })\n const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES)\n const boxesByPage = useMemo(\n () => passageBoxesByPage(processedChunks, { cited, active }),\n [processedChunks, cited, active]\n )\n\n // The passage being read is brought into view once, when its page first draws it: the viewer\n // opens the page, this centres the passage on it, and scrolling away is then left alone.\n const centredFor = useRef<string | null>(null)\n const activeKey = active ? `${documentId}:${active}` : null\n useEffect(() => {\n if (!activeKey) centredFor.current = null\n }, [activeKey])\n const centre = useCallback(\n (element: HTMLElement) => {\n if (!activeKey || centredFor.current === activeKey) return\n centredFor.current = activeKey\n element.scrollIntoView?.({ block: 'center', behavior: 'smooth' })\n },\n [activeKey]\n )\n\n return useCallback(\n (pageNumber: number) => {\n const boxes = boxesByPage.get(pageNumber)\n return boxes ? (\n <PdfPassageHighlights boxes={boxes} activeId={active} onActiveDrawn={centre} />\n ) : null\n },\n [boxesByPage, active, centre]\n )\n}\n"],
5
- "mappings": ";AAsDQ;AA/CR,SAAS,aAAa,WAAW,SAAS,cAA8B;AACxE,SAAS,qBAAqB,yBAAyB;AACvD,SAAS,0BAA0B;AACnC,SAAS,gCAAgC;AACzC,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;AAEnC,MAAM,OAA0B,CAAC;AACjC,MAAM,eAAuC,CAAC;AAGvC,SAAS,wBACd,YACmC;AACnC,QAAM,WAAW,yBAAyB,GAAG,eAAe;AAC5D,QAAM,QAAQ,QAAQ,MAAM,IAAI,IAAI,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACzD,QAAM,SAAS,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,aAAa,IAAI;AAE9E,QAAM,EAAE,MAAM,OAAO,IAAI,kBAAkB,YAAY,SAAS;AAAA,IAC9D,SAAS,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,EAC/B,CAAC;AACD,QAAM,EAAE,gBAAgB,IAAI,mBAAmB,QAAQ,QAAQ,YAAY;AAC3E,QAAM,cAAc;AAAA,IAClB,MAAM,mBAAmB,iBAAiB,EAAE,OAAO,OAAO,CAAC;AAAA,IAC3D,CAAC,iBAAiB,OAAO,MAAM;AAAA,EACjC;AAIA,QAAM,aAAa,OAAsB,IAAI;AAC7C,QAAM,YAAY,SAAS,GAAG,UAAU,IAAI,MAAM,KAAK;AACvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAW,YAAW,UAAU;AAAA,EACvC,GAAG,CAAC,SAAS,CAAC;AACd,QAAM,SAAS;AAAA,IACb,CAAC,YAAyB;AACxB,UAAI,CAAC,aAAa,WAAW,YAAY,UAAW;AACpD,iBAAW,UAAU;AACrB,cAAQ,iBAAiB,EAAE,OAAO,UAAU,UAAU,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO;AAAA,IACL,CAAC,eAAuB;AACtB,YAAM,QAAQ,YAAY,IAAI,UAAU;AACxC,aAAO,QACL,oBAAC,wBAAqB,OAAc,UAAU,QAAQ,eAAe,QAAQ,IAC3E;AAAA,IACN;AAAA,IACA,CAAC,aAAa,QAAQ,MAAM;AAAA,EAC9B;AACF;",
4
+ "sourcesContent": ["/**\n * The passages a citation lights, drawn over the PDF page by page: a fact's cited passages (its\n * Citation popover is open) and the passage a citation opened the document at, as the parsed view\n * lights them. Nothing is fetched until one is lit; the parsed chunks are the parsed view's own\n * query, so opening that tab afterwards costs nothing more.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useArbiSessionState, useArbiSessionStore, useParsedDocument } from '@arbidocs/react'\nimport { useProcessedChunks } from '@arbidocs/react/viewers'\nimport { useViewerPassageCitation } from '../support'\nimport { PdfPassageHighlights } from './PdfPassageHighlights'\nimport { passageBoxesByPage, passagePlaced } from './passageHighlights'\n\nconst NONE: readonly string[] = []\nconst NO_FOOTNOTES: Record<string, string> = {}\n\n/** A PDF viewer's page overlay for the document being viewed: `(page) => highlights | null`. */\nexport function usePdfPassageHighlights(\n documentId: string | undefined\n): (pageNumber: number) => ReactNode {\n const citedIds = useViewerPassageCitation()?.highlighted ?? NONE\n const cited = useMemo(() => new Set(citedIds), [citedIds])\n const active = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null)\n\n const { data: parsed } = useParsedDocument(documentId, 'final', {\n enabled: cited.size > 0 || !!active,\n })\n const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES)\n const boxesByPage = useMemo(\n () => passageBoxesByPage(processedChunks, { cited, active }),\n [processedChunks, cited, active]\n )\n\n // The passage being read could not be placed on its page (a document parsed before passages had\n // boxes): the text view marks it instead.\n const session = useArbiSessionStore()\n const fellBackFor = useRef<string | null>(null)\n useEffect(() => {\n if (!active || !parsed || !documentId) return\n const key = `${documentId}:${active}`\n if (fellBackFor.current === key || passagePlaced(processedChunks, active)) return\n fellBackFor.current = key\n session.setDocumentViewer({ tab: 'html' })\n }, [active, parsed, processedChunks, documentId, session])\n\n // The passage being read is brought into view once, when its page first draws it: the viewer\n // opens the page, this centres the passage on it, and scrolling away is then left alone.\n const centredFor = useRef<string | null>(null)\n const activeKey = active ? `${documentId}:${active}` : null\n useEffect(() => {\n if (!activeKey) centredFor.current = null\n }, [activeKey])\n const centre = useCallback(\n (element: HTMLElement) => {\n if (!activeKey || centredFor.current === activeKey) return\n centredFor.current = activeKey\n element.scrollIntoView?.({ block: 'center', behavior: 'smooth' })\n },\n [activeKey]\n )\n\n return useCallback(\n (pageNumber: number) => {\n const boxes = boxesByPage.get(pageNumber)\n return boxes ? (\n <PdfPassageHighlights boxes={boxes} activeId={active} onActiveDrawn={centre} />\n ) : null\n },\n [boxesByPage, active, centre]\n )\n}\n"],
5
+ "mappings": ";AAkEQ;AA3DR,SAAS,aAAa,WAAW,SAAS,cAA8B;AACxE,SAAS,qBAAqB,qBAAqB,yBAAyB;AAC5E,SAAS,0BAA0B;AACnC,SAAS,gCAAgC;AACzC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB,qBAAqB;AAElD,MAAM,OAA0B,CAAC;AACjC,MAAM,eAAuC,CAAC;AAGvC,SAAS,wBACd,YACmC;AACnC,QAAM,WAAW,yBAAyB,GAAG,eAAe;AAC5D,QAAM,QAAQ,QAAQ,MAAM,IAAI,IAAI,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACzD,QAAM,SAAS,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,aAAa,IAAI;AAE9E,QAAM,EAAE,MAAM,OAAO,IAAI,kBAAkB,YAAY,SAAS;AAAA,IAC9D,SAAS,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,EAC/B,CAAC;AACD,QAAM,EAAE,gBAAgB,IAAI,mBAAmB,QAAQ,QAAQ,YAAY;AAC3E,QAAM,cAAc;AAAA,IAClB,MAAM,mBAAmB,iBAAiB,EAAE,OAAO,OAAO,CAAC;AAAA,IAC3D,CAAC,iBAAiB,OAAO,MAAM;AAAA,EACjC;AAIA,QAAM,UAAU,oBAAoB;AACpC,QAAM,cAAc,OAAsB,IAAI;AAC9C,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,UAAU,CAAC,WAAY;AACvC,UAAM,MAAM,GAAG,UAAU,IAAI,MAAM;AACnC,QAAI,YAAY,YAAY,OAAO,cAAc,iBAAiB,MAAM,EAAG;AAC3E,gBAAY,UAAU;AACtB,YAAQ,kBAAkB,EAAE,KAAK,OAAO,CAAC;AAAA,EAC3C,GAAG,CAAC,QAAQ,QAAQ,iBAAiB,YAAY,OAAO,CAAC;AAIzD,QAAM,aAAa,OAAsB,IAAI;AAC7C,QAAM,YAAY,SAAS,GAAG,UAAU,IAAI,MAAM,KAAK;AACvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAW,YAAW,UAAU;AAAA,EACvC,GAAG,CAAC,SAAS,CAAC;AACd,QAAM,SAAS;AAAA,IACb,CAAC,YAAyB;AACxB,UAAI,CAAC,aAAa,WAAW,YAAY,UAAW;AACpD,iBAAW,UAAU;AACrB,cAAQ,iBAAiB,EAAE,OAAO,UAAU,UAAU,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO;AAAA,IACL,CAAC,eAAuB;AACtB,YAAM,QAAQ,YAAY,IAAI,UAAU;AACxC,aAAO,QACL,oBAAC,wBAAqB,OAAc,UAAU,QAAQ,eAAe,QAAQ,IAC3E;AAAA,IACN;AAAA,IACA,CAAC,aAAa,QAAQ,MAAM;AAAA,EAC9B;AACF;",
6
6
  "names": []
7
7
  }
@@ -10,8 +10,8 @@ require('../chunk-ZU2B2RZK.cjs');
10
10
  var chunkNSD37OF5_cjs = require('../chunk-NSD37OF5.cjs');
11
11
  var chunkOEJQFPWO_cjs = require('../chunk-OEJQFPWO.cjs');
12
12
  require('../chunk-JV5TVUOU.cjs');
13
- require('../chunk-IPSHAMO2.cjs');
14
13
  var chunkZW6FPIFC_cjs = require('../chunk-ZW6FPIFC.cjs');
14
+ require('../chunk-IPSHAMO2.cjs');
15
15
  var chunkTKHCIHE2_cjs = require('../chunk-TKHCIHE2.cjs');
16
16
  require('../chunk-JDFBEGQO.cjs');
17
17
  require('../chunk-ULWRNGGE.cjs');