@arbidocs/blocks 0.5.123 → 0.5.125

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 (192) hide show
  1. package/dist/{ClippingMediaViewer-IEIBT74X.cjs → ClippingMediaViewer-ZFEX5A3U.cjs} +11 -10
  2. package/dist/ClippingMediaViewer-ZFEX5A3U.cjs.map +1 -0
  3. package/dist/{ClippingPdfViewer-OGYLMVCE.cjs → ClippingPdfViewer-3LRTEPHV.cjs} +45 -11
  4. package/dist/ClippingPdfViewer-3LRTEPHV.cjs.map +1 -0
  5. package/dist/ConnectedCallDock-XJOYVVAH.cjs +6 -6
  6. package/dist/ConnectedCallRoom-CUDYAPQK.cjs +6 -6
  7. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs → ConnectedNativeDocxComparison-7QQ55JIO.cjs} +13 -13
  8. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs.map → ConnectedNativeDocxComparison-7QQ55JIO.cjs.map} +1 -1
  9. package/dist/{ConnectedPresentation-5DOJ35XL.cjs → ConnectedPresentation-L32JPRFI.cjs} +30 -156
  10. package/dist/ConnectedPresentation-L32JPRFI.cjs.map +1 -0
  11. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
  12. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
  13. package/dist/{ConnectedSlidesTab-7YMEDGUU.cjs → ConnectedSlidesTab-P7GGNUTO.cjs} +31 -29
  14. package/dist/ConnectedSlidesTab-P7GGNUTO.cjs.map +1 -0
  15. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs → ConnectedStreamedWordArtifact-7NJ3N52V.cjs} +13 -13
  16. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs.map → ConnectedStreamedWordArtifact-7NJ3N52V.cjs.map} +1 -1
  17. package/dist/{DocumentReviewCard-M53XFLI2.cjs → DocumentReviewCard-BFPOFQXI.cjs} +16 -16
  18. package/dist/{DocumentReviewCard-M53XFLI2.cjs.map → DocumentReviewCard-BFPOFQXI.cjs.map} +1 -1
  19. package/dist/{FilesViewerDialog-2QCCRWF2.cjs → FilesViewerDialog-MHUVEZ7M.cjs} +35 -32
  20. package/dist/FilesViewerDialog-MHUVEZ7M.cjs.map +1 -0
  21. package/dist/{NativeDocxEditor-2LQY2CTV.cjs → NativeDocxEditor-SIRYPMBN.cjs} +6 -6
  22. package/dist/{NativeDocxEditor-2LQY2CTV.cjs.map → NativeDocxEditor-SIRYPMBN.cjs.map} +1 -1
  23. package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
  24. package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
  25. package/dist/{WorkspaceTableView-3XYAV4BV.cjs → WorkspaceTableView-MIFYXV3G.cjs} +8 -8
  26. package/dist/{WorkspaceTableView-3XYAV4BV.cjs.map → WorkspaceTableView-MIFYXV3G.cjs.map} +1 -1
  27. package/dist/agents/index.cjs +216 -216
  28. package/dist/ai-IEIR7SC2.cjs +3 -3
  29. package/dist/auth/index.cjs +1 -1
  30. package/dist/calls/index.cjs +2 -2
  31. package/dist/chat/index.cjs +6 -6
  32. package/dist/{chunk-GNZAH6UI.cjs → chunk-2K6IMIVL.cjs} +3 -3
  33. package/dist/{chunk-GNZAH6UI.cjs.map → chunk-2K6IMIVL.cjs.map} +1 -1
  34. package/dist/{chunk-NQML7IUC.cjs → chunk-3UP32FM3.cjs} +6 -6
  35. package/dist/{chunk-NQML7IUC.cjs.map → chunk-3UP32FM3.cjs.map} +1 -1
  36. package/dist/chunk-3ZZZO4F7.cjs +145 -0
  37. package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
  38. package/dist/{chunk-L4CIFLCU.cjs → chunk-4LP5MJGQ.cjs} +4 -4
  39. package/dist/{chunk-L4CIFLCU.cjs.map → chunk-4LP5MJGQ.cjs.map} +1 -1
  40. package/dist/{chunk-JD2HX2BR.cjs → chunk-6JMW3IJ2.cjs} +152 -155
  41. package/dist/chunk-6JMW3IJ2.cjs.map +1 -0
  42. package/dist/{chunk-WV7BCGCK.cjs → chunk-7RJZIPLE.cjs} +33 -33
  43. package/dist/{chunk-WV7BCGCK.cjs.map → chunk-7RJZIPLE.cjs.map} +1 -1
  44. package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
  45. package/dist/chunk-ADPRIBSH.cjs.map +1 -0
  46. package/dist/{chunk-7NLO7ASW.cjs → chunk-AISYXX4M.cjs} +4 -4
  47. package/dist/{chunk-7NLO7ASW.cjs.map → chunk-AISYXX4M.cjs.map} +1 -1
  48. package/dist/{chunk-5QERK4PK.cjs → chunk-AS6QZETU.cjs} +35 -35
  49. package/dist/{chunk-5QERK4PK.cjs.map → chunk-AS6QZETU.cjs.map} +1 -1
  50. package/dist/{chunk-V6MW7B4B.cjs → chunk-B3R62764.cjs} +6 -6
  51. package/dist/{chunk-V6MW7B4B.cjs.map → chunk-B3R62764.cjs.map} +1 -1
  52. package/dist/{chunk-VKH3BEZE.cjs → chunk-BLIO3B7Z.cjs} +3 -3
  53. package/dist/{chunk-VKH3BEZE.cjs.map → chunk-BLIO3B7Z.cjs.map} +1 -1
  54. package/dist/{chunk-46P7IDBX.cjs → chunk-CQ2RJYE2.cjs} +4 -4
  55. package/dist/chunk-CQ2RJYE2.cjs.map +1 -0
  56. package/dist/{chunk-MXBXZXXQ.cjs → chunk-ENOPKX7E.cjs} +3 -3
  57. package/dist/{chunk-MXBXZXXQ.cjs.map → chunk-ENOPKX7E.cjs.map} +1 -1
  58. package/dist/{chunk-2CSLFAGF.cjs → chunk-GAMRVB3I.cjs} +4 -3
  59. package/dist/chunk-GAMRVB3I.cjs.map +1 -0
  60. package/dist/chunk-IRGRMJPP.cjs +18 -0
  61. package/dist/{chunk-SDRYSLOX.cjs.map → chunk-IRGRMJPP.cjs.map} +1 -1
  62. package/dist/{chunk-ADDQKZ5I.cjs → chunk-J3FFSEKO.cjs} +4 -4
  63. package/dist/{chunk-ADDQKZ5I.cjs.map → chunk-J3FFSEKO.cjs.map} +1 -1
  64. package/dist/chunk-JITYC4OS.cjs +66 -0
  65. package/dist/chunk-JITYC4OS.cjs.map +1 -0
  66. package/dist/chunk-JY7UUZQG.cjs +1513 -0
  67. package/dist/chunk-JY7UUZQG.cjs.map +1 -0
  68. package/dist/{chunk-ALK3PUUB.cjs → chunk-L6HTZIBD.cjs} +3 -3
  69. package/dist/{chunk-ALK3PUUB.cjs.map → chunk-L6HTZIBD.cjs.map} +1 -1
  70. package/dist/chunk-MVXHTAJ4.cjs +111 -0
  71. package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
  72. package/dist/{chunk-OHHKBURG.cjs → chunk-OGK377NL.cjs} +33 -33
  73. package/dist/{chunk-OHHKBURG.cjs.map → chunk-OGK377NL.cjs.map} +1 -1
  74. package/dist/{chunk-T73BHNQX.cjs → chunk-OHWHYVKG.cjs} +3 -3
  75. package/dist/{chunk-T73BHNQX.cjs.map → chunk-OHWHYVKG.cjs.map} +1 -1
  76. package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
  77. package/dist/chunk-ORNLCBNE.cjs.map +1 -0
  78. package/dist/{chunk-MLA2BJ2Y.cjs → chunk-PSB64T43.cjs} +28 -28
  79. package/dist/{chunk-MLA2BJ2Y.cjs.map → chunk-PSB64T43.cjs.map} +1 -1
  80. package/dist/{chunk-COD5ENHK.cjs → chunk-PVJ5ODDB.cjs} +4 -4
  81. package/dist/{chunk-COD5ENHK.cjs.map → chunk-PVJ5ODDB.cjs.map} +1 -1
  82. package/dist/{chunk-7557LDAN.cjs → chunk-PWBRE7JA.cjs} +5 -5
  83. package/dist/{chunk-7557LDAN.cjs.map → chunk-PWBRE7JA.cjs.map} +1 -1
  84. package/dist/{chunk-7PN3YENO.cjs → chunk-QIK7E6VF.cjs} +4 -4
  85. package/dist/{chunk-7PN3YENO.cjs.map → chunk-QIK7E6VF.cjs.map} +1 -1
  86. package/dist/{chunk-DWMWEALB.cjs → chunk-TSFNLY3K.cjs} +143 -1634
  87. package/dist/chunk-TSFNLY3K.cjs.map +1 -0
  88. package/dist/{chunk-YGBHY67W.cjs → chunk-UA7HOLAZ.cjs} +5 -5
  89. package/dist/{chunk-YGBHY67W.cjs.map → chunk-UA7HOLAZ.cjs.map} +1 -1
  90. package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
  91. package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
  92. package/dist/chunk-WVZLAAIZ.cjs +31 -0
  93. package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
  94. package/dist/{chunk-E3L5DB5F.cjs → chunk-YOEP3I4V.cjs} +5 -5
  95. package/dist/{chunk-E3L5DB5F.cjs.map → chunk-YOEP3I4V.cjs.map} +1 -1
  96. package/dist/{chunk-SNPK3R3O.cjs → chunk-YVO6Z5BS.cjs} +10 -10
  97. package/dist/{chunk-SNPK3R3O.cjs.map → chunk-YVO6Z5BS.cjs.map} +1 -1
  98. package/dist/chunk-ZZZITHGK.cjs +119 -0
  99. package/dist/chunk-ZZZITHGK.cjs.map +1 -0
  100. package/dist/connect/docx.cjs +17 -17
  101. package/dist/connect/index.cjs +994 -994
  102. package/dist/connect/viewer.cjs +28 -25
  103. package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
  104. package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
  105. package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
  106. package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
  107. package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
  108. package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
  109. package/dist/connection/presentation/SpotlightLayer.js +19 -0
  110. package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
  111. package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
  112. package/dist/connection/presentation/SpotlightStrip.js +237 -0
  113. package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
  114. package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
  115. package/dist/connection/presentation/useViewerClipping.js +8 -4
  116. package/dist/connection/presentation/useViewerClipping.js.map +2 -2
  117. package/dist/connection/viewer/ConnectedDocumentViewer.js +1 -1
  118. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  119. package/dist/connection/viewer/VersionDropdown.js +1 -1
  120. package/dist/connection/viewer/VersionDropdown.js.map +1 -1
  121. package/dist/connection/viewer/ViewerPdfPane.js +2 -0
  122. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  123. package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
  124. package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
  125. package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
  126. package/dist/connection/viewer/pdf/usePassageTextFallback.d.ts +12 -0
  127. package/dist/connection/viewer/pdf/usePassageTextFallback.js +30 -0
  128. package/dist/connection/viewer/pdf/usePassageTextFallback.js.map +7 -0
  129. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js +2 -11
  130. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js.map +2 -2
  131. package/dist/connection/viewer/useCleanView.d.ts +3 -1
  132. package/dist/connection/viewer/useCleanView.js +6 -3
  133. package/dist/connection/viewer/useCleanView.js.map +2 -2
  134. package/dist/connection/viewer/useViewerTabs.js +13 -1
  135. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  136. package/dist/document-tools/DocumentToolButtons.js +1 -1
  137. package/dist/document-tools/DocumentToolButtons.js.map +1 -1
  138. package/dist/document-tools/index.cjs +20 -20
  139. package/dist/docx/DocxCommandMenu.js +2 -1
  140. package/dist/docx/DocxCommandMenu.js.map +2 -2
  141. package/dist/docx/index.cjs +38 -38
  142. package/dist/embed/index.cjs +20 -20
  143. package/dist/facts/index.cjs +64 -64
  144. package/dist/files/index.cjs +223 -223
  145. package/dist/index.cjs +521 -521
  146. package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
  147. package/dist/presentation/ClipCaptureOverlay.js +43 -14
  148. package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
  149. package/dist/presentation/PresentControls.d.ts +8 -0
  150. package/dist/presentation/PresentControls.js +1 -0
  151. package/dist/presentation/PresentControls.js.map +2 -2
  152. package/dist/presentation/PresentationStage.d.ts +10 -2
  153. package/dist/presentation/PresentationStage.js +6 -3
  154. package/dist/presentation/PresentationStage.js.map +2 -2
  155. package/dist/presentation/PresenterView.js +1 -22
  156. package/dist/presentation/PresenterView.js.map +2 -2
  157. package/dist/presentation/SpotlightView.d.ts +19 -0
  158. package/dist/presentation/SpotlightView.js +180 -0
  159. package/dist/presentation/SpotlightView.js.map +7 -0
  160. package/dist/presentation/passage-clip.d.ts +17 -0
  161. package/dist/presentation/passage-clip.js +25 -0
  162. package/dist/presentation/passage-clip.js.map +7 -0
  163. package/dist/presentation/spotlight.d.ts +58 -0
  164. package/dist/presentation/spotlight.js +110 -0
  165. package/dist/presentation/spotlight.js.map +7 -0
  166. package/dist/presentation/store.d.ts +5 -0
  167. package/dist/presentation/store.js +19 -0
  168. package/dist/presentation/store.js.map +2 -2
  169. package/dist/presentation/usePointerActive.d.ts +2 -0
  170. package/dist/presentation/usePointerActive.js +28 -0
  171. package/dist/presentation/usePointerActive.js.map +7 -0
  172. package/dist/settings/index.cjs +146 -146
  173. package/dist/site/index.cjs +6 -6
  174. package/dist/studio/index.cjs +9 -9
  175. package/dist/styles.css +1 -1
  176. package/dist/workflow-canvas/index.cjs +35 -35
  177. package/node_modules/@arbidocs/coedit/package.json +1 -1
  178. package/package.json +5 -5
  179. package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
  180. package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
  181. package/dist/ConnectedPresentation-5DOJ35XL.cjs.map +0 -1
  182. package/dist/ConnectedSlidesTab-7YMEDGUU.cjs.map +0 -1
  183. package/dist/FilesViewerDialog-2QCCRWF2.cjs.map +0 -1
  184. package/dist/chunk-2CSLFAGF.cjs.map +0 -1
  185. package/dist/chunk-46P7IDBX.cjs.map +0 -1
  186. package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
  187. package/dist/chunk-DWMWEALB.cjs.map +0 -1
  188. package/dist/chunk-JD2HX2BR.cjs.map +0 -1
  189. package/dist/chunk-SDRYSLOX.cjs +0 -18
  190. package/dist/chunk-WFMWKPGY.cjs.map +0 -1
  191. package/dist/chunk-XK4TVJKD.cjs +0 -73
  192. package/dist/chunk-XK4TVJKD.cjs.map +0 -1
@@ -24,5 +24,10 @@ export interface PassageHighlightState {
24
24
  export declare function passageHighlight(chunkId: string, { cited, active }: PassageHighlightState): PassageHighlight | null;
25
25
  /** The passage has a box on its page to light (not none, nor the whole page). */
26
26
  export declare function passagePlaced(pages: readonly ProcessedPage[], chunkId: string): boolean;
27
+ /**
28
+ * Every passage placed on its page (a box, not the whole page), by page number: what clip mode
29
+ * outlines under the pointer and clips with a click.
30
+ */
31
+ export declare function placedPassagesByPage(pages: readonly ProcessedPage[]): Map<number, PageBox[]>;
27
32
  /** The lit passages' boxes, by page number. Passages without a usable box are left out. */
28
33
  export declare function passageBoxesByPage(pages: readonly ProcessedPage[], state: PassageHighlightState): Map<number, PdfPassageBox[]>;
@@ -25,6 +25,18 @@ function passagePlaced(pages, chunkId) {
25
25
  }
26
26
  return false;
27
27
  }
28
+ function placedPassagesByPage(pages) {
29
+ const byPage = /* @__PURE__ */ new Map();
30
+ for (const page of pages) {
31
+ if (page.pageNumber === null) continue;
32
+ for (const chunk of page.chunks) {
33
+ const box = asBox(chunk.pageBbox);
34
+ if (!box || isWholePage(box)) continue;
35
+ byPage.set(page.pageNumber, [...byPage.get(page.pageNumber) ?? [], box]);
36
+ }
37
+ }
38
+ return byPage;
39
+ }
28
40
  function passageBoxesByPage(pages, state) {
29
41
  const byPage = /* @__PURE__ */ new Map();
30
42
  if (state.cited.size === 0 && !state.active) return byPage;
@@ -46,6 +58,7 @@ function passageBoxesByPage(pages, state) {
46
58
  export {
47
59
  passageBoxesByPage,
48
60
  passageHighlight,
49
- passagePlaced
61
+ passagePlaced,
62
+ placedPassagesByPage
50
63
  };
51
64
  //# 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 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;",
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/**\n * Every passage placed on its page (a box, not the whole page), by page number: what clip mode\n * outlines under the pointer and clips with a click.\n */\nexport function placedPassagesByPage(pages: readonly ProcessedPage[]): Map<number, PageBox[]> {\n const byPage = new Map<number, PageBox[]>()\n for (const page of pages) {\n if (page.pageNumber === null) continue\n for (const chunk of page.chunks) {\n const box = asBox(chunk.pageBbox)\n if (!box || isWholePage(box)) continue\n byPage.set(page.pageNumber, [...(byPage.get(page.pageNumber) ?? []), box])\n }\n }\n return byPage\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;AAMO,SAAS,qBAAqB,OAAyD;AAC5F,QAAM,SAAS,oBAAI,IAAuB;AAC1C,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,eAAe,KAAM;AAC9B,eAAW,SAAS,KAAK,QAAQ;AAC/B,YAAM,MAAM,MAAM,MAAM,QAAQ;AAChC,UAAI,CAAC,OAAO,YAAY,GAAG,EAAG;AAC9B,aAAO,IAAI,KAAK,YAAY,CAAC,GAAI,OAAO,IAAI,KAAK,UAAU,KAAK,CAAC,GAAI,GAAG,CAAC;AAAA,IAC3E;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,12 @@
1
+ /**
2
+ * A passage opens on the PDF, lit in the box the parser found it in (`showDocumentPlace`). When the
3
+ * PDF cannot show it, the text view, where every passage is marked, is opened instead: the passage
4
+ * has no box on its page (a document parsed before passages had boxes), or the PDF cannot be
5
+ * loaded. Decided by the PDF pane, not by the PDF viewer in it, so a PDF that never loads still
6
+ * falls back. Once per passage: going back to the PDF afterwards stays there.
7
+ */
8
+ /**
9
+ * The fallback for the session's viewing document (the one the PDF's highlights read), from the PDF
10
+ * pane: it is there while the PDF tab is, whether its PDF has loaded, is loading or has failed.
11
+ */
12
+ export declare function usePassageTextFallback(pdfFailed: boolean): void;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { useArbiSessionState, useArbiSessionStore, useParsedDocument } from "@arbidocs/react";
4
+ import { useProcessedChunks } from "@arbidocs/react/viewers";
5
+ import { passagePlaced } from "./passageHighlights.js";
6
+ const NO_FOOTNOTES = {};
7
+ const fellBackFor = /* @__PURE__ */ new WeakMap();
8
+ function usePassageTextFallback(pdfFailed) {
9
+ const session = useArbiSessionStore();
10
+ const documentId = useArbiSessionState((s) => s.viewingDocument?.id);
11
+ const onPdf = useArbiSessionState((s) => s.documentViewer.tab === "pdf");
12
+ const active = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null);
13
+ const { data: parsed } = useParsedDocument(documentId, "final", {
14
+ enabled: onPdf && !!active
15
+ });
16
+ const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES);
17
+ useEffect(() => {
18
+ if (!onPdf || !active || !documentId) return;
19
+ const key = `${documentId}:${active}`;
20
+ if (fellBackFor.get(session) === key) return;
21
+ const unplaced = !!parsed && !passagePlaced(processedChunks, active);
22
+ if (!pdfFailed && !unplaced) return;
23
+ fellBackFor.set(session, key);
24
+ session.setDocumentViewer({ tab: "html" });
25
+ }, [onPdf, pdfFailed, active, parsed, processedChunks, documentId, session]);
26
+ }
27
+ export {
28
+ usePassageTextFallback
29
+ };
30
+ //# sourceMappingURL=usePassageTextFallback.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/connection/viewer/pdf/usePassageTextFallback.ts"],
4
+ "sourcesContent": ["/**\n * A passage opens on the PDF, lit in the box the parser found it in (`showDocumentPlace`). When the\n * PDF cannot show it, the text view, where every passage is marked, is opened instead: the passage\n * has no box on its page (a document parsed before passages had boxes), or the PDF cannot be\n * loaded. Decided by the PDF pane, not by the PDF viewer in it, so a PDF that never loads still\n * falls back. Once per passage: going back to the PDF afterwards stays there.\n */\n\nimport { useEffect } from 'react'\nimport { useArbiSessionState, useArbiSessionStore, useParsedDocument } from '@arbidocs/react'\nimport { useProcessedChunks } from '@arbidocs/react/viewers'\nimport { passagePlaced } from './passageHighlights'\n\nconst NO_FOOTNOTES: Record<string, string> = {}\n/**\n * The passage each session last fell back for. Kept beside the session, not in the pane: the pane\n * unmounts with the PDF tab, and coming back to it must not fall back again.\n */\nconst fellBackFor = new WeakMap<object, string>()\n\n/**\n * The fallback for the session's viewing document (the one the PDF's highlights read), from the PDF\n * pane: it is there while the PDF tab is, whether its PDF has loaded, is loading or has failed.\n */\nexport function usePassageTextFallback(pdfFailed: boolean): void {\n const session = useArbiSessionStore()\n const documentId = useArbiSessionState((s) => s.viewingDocument?.id)\n const onPdf = useArbiSessionState((s) => s.documentViewer.tab === 'pdf')\n const active = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null)\n // The PDF's highlights read the same query, so this costs nothing more.\n const { data: parsed } = useParsedDocument(documentId, 'final', {\n enabled: onPdf && !!active,\n })\n const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES)\n useEffect(() => {\n if (!onPdf || !active || !documentId) return\n const key = `${documentId}:${active}`\n if (fellBackFor.get(session) === key) return\n const unplaced = !!parsed && !passagePlaced(processedChunks, active)\n if (!pdfFailed && !unplaced) return\n fellBackFor.set(session, key)\n session.setDocumentViewer({ tab: 'html' })\n }, [onPdf, pdfFailed, active, parsed, processedChunks, documentId, session])\n}\n"],
5
+ "mappings": ";AAQA,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB,qBAAqB,yBAAyB;AAC5E,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAE9B,MAAM,eAAuC,CAAC;AAK9C,MAAM,cAAc,oBAAI,QAAwB;AAMzC,SAAS,uBAAuB,WAA0B;AAC/D,QAAM,UAAU,oBAAoB;AACpC,QAAM,aAAa,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,EAAE;AACnE,QAAM,QAAQ,oBAAoB,CAAC,MAAM,EAAE,eAAe,QAAQ,KAAK;AACvE,QAAM,SAAS,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,aAAa,IAAI;AAE9E,QAAM,EAAE,MAAM,OAAO,IAAI,kBAAkB,YAAY,SAAS;AAAA,IAC9D,SAAS,SAAS,CAAC,CAAC;AAAA,EACtB,CAAC;AACD,QAAM,EAAE,gBAAgB,IAAI,mBAAmB,QAAQ,QAAQ,YAAY;AAC3E,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAY;AACtC,UAAM,MAAM,GAAG,UAAU,IAAI,MAAM;AACnC,QAAI,YAAY,IAAI,OAAO,MAAM,IAAK;AACtC,UAAM,WAAW,CAAC,CAAC,UAAU,CAAC,cAAc,iBAAiB,MAAM;AACnE,QAAI,CAAC,aAAa,CAAC,SAAU;AAC7B,gBAAY,IAAI,SAAS,GAAG;AAC5B,YAAQ,kBAAkB,EAAE,KAAK,OAAO,CAAC;AAAA,EAC3C,GAAG,CAAC,OAAO,WAAW,QAAQ,QAAQ,iBAAiB,YAAY,OAAO,CAAC;AAC7E;",
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, useArbiSessionStore, useParsedDocument } from "@arbidocs/react";
4
+ import { useArbiSessionState, 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, passagePlaced } from "./passageHighlights.js";
8
+ import { passageBoxesByPage } from "./passageHighlights.js";
9
9
  const NONE = [];
10
10
  const NO_FOOTNOTES = {};
11
11
  function usePdfPassageHighlights(documentId) {
@@ -20,15 +20,6 @@ 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]);
32
23
  const centredFor = useRef(null);
33
24
  const activeKey = active ? `${documentId}:${active}` : null;
34
25
  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, 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;",
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;",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,9 @@
5
5
  * the viewer back in ends the clean view.
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
- export declare function useCleanView(): {
8
+ export declare function useCleanView(
9
+ /** Over the body in any view (the spotlight's strip). */
10
+ extra?: ReactNode): {
9
11
  on: boolean;
10
12
  frame: {
11
13
  bare: boolean;
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef } from "react";
4
4
  import { useArbiSessionState, useArbiSessionStore } from "@arbidocs/react";
5
5
  import { CleanViewControl } from "./CleanViewControl.js";
6
- function useCleanView() {
6
+ function useCleanView(extra) {
7
7
  const session = useArbiSessionStore();
8
8
  const detached = useArbiSessionState((s) => s.documentViewer.detached);
9
9
  const presenting = useArbiSessionState((s) => s.documentViewer.presenting);
@@ -19,7 +19,10 @@ function useCleanView() {
19
19
  on,
20
20
  frame: {
21
21
  bare: on,
22
- overlay: on ? /* @__PURE__ */ jsx(CleanViewControl, { onExit: () => session.setDocumentViewer({ presenting: false }) }) : null
22
+ overlay: /* @__PURE__ */ jsxs(Fragment, { children: [
23
+ on && /* @__PURE__ */ jsx(CleanViewControl, { onExit: () => session.setDocumentViewer({ presenting: false }) }),
24
+ extra
25
+ ] })
23
26
  }
24
27
  };
25
28
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/useCleanView.tsx"],
4
- "sourcesContent": ["/**\n * The viewer's clean view: popped out with `documentViewer.presenting`, it shows only the document\n * on black (no header, bars or controls), to share in a call or put full screen. Its one control\n * (`CleanViewControl`: full screen, show the controls again) shows while the pointer moves. Popping\n * the viewer back in ends the clean view.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\nimport { useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport { CleanViewControl } from './CleanViewControl'\n\nexport function useCleanView(): { on: boolean; frame: { bare: boolean; overlay: ReactNode } } {\n const session = useArbiSessionStore()\n const detached = useArbiSessionState((s) => s.documentViewer.detached)\n const presenting = useArbiSessionState((s) => s.documentViewer.presenting)\n const on = detached && presenting\n\n // Back in the app's window: the next pop-out shows the controls as usual.\n const wasDetached = useRef(detached)\n useEffect(() => {\n if (wasDetached.current && !detached && presenting) {\n session.setDocumentViewer({ presenting: false })\n }\n wasDetached.current = detached\n }, [detached, presenting, session])\n\n return {\n on,\n frame: {\n bare: on,\n overlay: on ? (\n <CleanViewControl onExit={() => session.setDocumentViewer({ presenting: false })} />\n ) : null,\n },\n }\n}\n"],
5
- "mappings": ";AA+BQ;AAxBR,SAAS,WAAW,cAA8B;AAClD,SAAS,qBAAqB,2BAA2B;AACzD,SAAS,wBAAwB;AAE1B,SAAS,eAA8E;AAC5F,QAAM,UAAU,oBAAoB;AACpC,QAAM,WAAW,oBAAoB,CAAC,MAAM,EAAE,eAAe,QAAQ;AACrE,QAAM,aAAa,oBAAoB,CAAC,MAAM,EAAE,eAAe,UAAU;AACzE,QAAM,KAAK,YAAY;AAGvB,QAAM,cAAc,OAAO,QAAQ;AACnC,YAAU,MAAM;AACd,QAAI,YAAY,WAAW,CAAC,YAAY,YAAY;AAClD,cAAQ,kBAAkB,EAAE,YAAY,MAAM,CAAC;AAAA,IACjD;AACA,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,UAAU,YAAY,OAAO,CAAC;AAElC,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,KACP,oBAAC,oBAAiB,QAAQ,MAAM,QAAQ,kBAAkB,EAAE,YAAY,MAAM,CAAC,GAAG,IAChF;AAAA,IACN;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["/**\n * The viewer's clean view: popped out with `documentViewer.presenting`, it shows only the document\n * on black (no header, bars or controls), to share in a call or put full screen. Its one control\n * (`CleanViewControl`: full screen, show the controls again) shows while the pointer moves. Popping\n * the viewer back in ends the clean view.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\nimport { useArbiSessionState, useArbiSessionStore } from '@arbidocs/react'\nimport { CleanViewControl } from './CleanViewControl'\n\nexport function useCleanView(\n /** Over the body in any view (the spotlight's strip). */\n extra?: ReactNode\n): { on: boolean; frame: { bare: boolean; overlay: ReactNode } } {\n const session = useArbiSessionStore()\n const detached = useArbiSessionState((s) => s.documentViewer.detached)\n const presenting = useArbiSessionState((s) => s.documentViewer.presenting)\n const on = detached && presenting\n\n // Back in the app's window: the next pop-out shows the controls as usual.\n const wasDetached = useRef(detached)\n useEffect(() => {\n if (wasDetached.current && !detached && presenting) {\n session.setDocumentViewer({ presenting: false })\n }\n wasDetached.current = detached\n }, [detached, presenting, session])\n\n return {\n on,\n frame: {\n bare: on,\n overlay: (\n <>\n {on && (\n <CleanViewControl onExit={() => session.setDocumentViewer({ presenting: false })} />\n )}\n {extra}\n </>\n ),\n },\n }\n}\n"],
5
+ "mappings": ";AAkCQ,mBAEI,KAFJ;AA3BR,SAAS,WAAW,cAA8B;AAClD,SAAS,qBAAqB,2BAA2B;AACzD,SAAS,wBAAwB;AAE1B,SAAS,aAEd,OAC+D;AAC/D,QAAM,UAAU,oBAAoB;AACpC,QAAM,WAAW,oBAAoB,CAAC,MAAM,EAAE,eAAe,QAAQ;AACrE,QAAM,aAAa,oBAAoB,CAAC,MAAM,EAAE,eAAe,UAAU;AACzE,QAAM,KAAK,YAAY;AAGvB,QAAM,cAAc,OAAO,QAAQ;AACnC,YAAU,MAAM;AACd,QAAI,YAAY,WAAW,CAAC,YAAY,YAAY;AAClD,cAAQ,kBAAkB,EAAE,YAAY,MAAM,CAAC;AAAA,IACjD;AACA,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,UAAU,YAAY,OAAO,CAAC;AAElC,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SACE,iCACG;AAAA,cACC,oBAAC,oBAAiB,QAAQ,MAAM,QAAQ,kBAAkB,EAAE,YAAY,MAAM,CAAC,GAAG;AAAA,QAEnF;AAAA,SACH;AAAA,IAEJ;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -41,6 +41,7 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
41
41
  phonePdfChosen
42
42
  } = useArbiSessionState((s) => s.documentViewer);
43
43
  const setActiveTab = (tab) => session.setDocumentViewer({ tab });
44
+ const passageId = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null);
44
45
  const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === "Text";
45
46
  const isPhone = useIsPhone();
46
47
  const phoneDefaultDecidedFor = useRef(null);
@@ -51,6 +52,8 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
51
52
  setActiveTab("slides");
52
53
  } else if (!isPresentation && documentData && activeTab === "slides") {
53
54
  setActiveTab(isDocx ? "docx" : isXlsx ? "xlsx" : "pdf");
55
+ } else if (passageId && activeTab === "pdf" && (isArtifact || isDocx)) {
56
+ setActiveTab("html");
54
57
  } else if (isArtifact && (activeTab === "pdf" || !liveKind && activeTab === "docx")) {
55
58
  setActiveTab(liveKind ? "preview" : "edit");
56
59
  } else if (isDocx && activeTab === "pdf") {
@@ -62,7 +65,16 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
62
65
  } else if (!isArtifact && !isDocx && !isXlsx && documentData && (activeTab === "docx" || activeTab === "xlsx")) {
63
66
  setActiveTab("pdf");
64
67
  }
65
- }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind, isPresentation]);
68
+ }, [
69
+ hasDocumentData,
70
+ documentKey,
71
+ isArtifact,
72
+ isDocx,
73
+ isXlsx,
74
+ liveKind,
75
+ isPresentation,
76
+ passageId
77
+ ]);
66
78
  useEffect(() => {
67
79
  if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return;
68
80
  phoneDefaultDecidedFor.current = documentKey;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/useViewerTabs.tsx"],
4
- "sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay, Presentation } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isPresentation,\n isDraft,\n isStreaming,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A presentation opens on its slides; another document never shows that tab.\n if (isPresentation && hasDocumentData && activeTab === 'pdf') {\n setActiveTab('slides')\n } else if (!isPresentation && documentData && activeTab === 'slides') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n else if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind, isPresentation])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n // A presentation's slides, edited; then its PDF (the slides as saved), once it has one.\n ...(isPresentation\n ? [\n {\n id: 'slides',\n icon: <Presentation className=\"size-5\" />,\n tooltip: 'Slides',\n label: tabLabel('slides', 'Slides'),\n },\n ]\n : []),\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n ...(!liveKind && !isDraft && !isStreaming && isDocx\n ? [\n {\n id: 'pdf',\n icon: <PdfIcon size={20} />,\n tooltip: 'PDF',\n label: tabLabel('pdf', 'PDF'),\n },\n ]\n : []),\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n ...(isPresentation && isDraft\n ? []\n : [{ id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) }]),\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay, Presentation } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isPresentation,\n isDraft,\n isStreaming,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A passage being opened (a citation, a search hit): it is lit on the PDF, else marked on the text\n // view, never in an editor.\n const passageId = useArbiSessionState((s) => s.viewingDocument?.passageId ?? null)\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor. Also on a passage opened: it asks for the PDF tab whatever the type.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A presentation opens on its slides; another document never shows that tab.\n if (isPresentation && hasDocumentData && activeTab === 'pdf') {\n setActiveTab('slides')\n } else if (!isPresentation && documentData && activeTab === 'slides') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // A passage opened on a document whose type leaves the PDF tab goes to the text view, where\n // every passage is marked (the PDF pane's own fallback is not there to do it).\n else if (passageId && activeTab === 'pdf' && (isArtifact || isDocx)) {\n setActiveTab('html')\n }\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n else if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n hasDocumentData,\n documentKey,\n isArtifact,\n isDocx,\n isXlsx,\n liveKind,\n isPresentation,\n passageId,\n ])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n // A presentation's slides, edited; then its PDF (the slides as saved), once it has one.\n ...(isPresentation\n ? [\n {\n id: 'slides',\n icon: <Presentation className=\"size-5\" />,\n tooltip: 'Slides',\n label: tabLabel('slides', 'Slides'),\n },\n ]\n : []),\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n ...(!liveKind && !isDraft && !isStreaming && isDocx\n ? [\n {\n id: 'pdf',\n icon: <PdfIcon size={20} />,\n tooltip: 'PDF',\n label: tabLabel('pdf', 'PDF'),\n },\n ]\n : []),\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n ...(isPresentation && isDraft\n ? []\n : [{ id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) }]),\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -31,7 +31,7 @@ function ClipButton({ active, onClick, compact }) {
31
31
  variant: active ? "default" : "outline",
32
32
  size: compact ? "icon" : "sm",
33
33
  "aria-pressed": active,
34
- title: "Clip: drag over a page to show that part in a presentation",
34
+ title: "Clip: click a passage (or drag over any area) to gather it, then Show",
35
35
  "aria-label": "Clip",
36
36
  "data-testid": "clip-toggle",
37
37
  className: TOUCH,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/document-tools/DocumentToolButtons.tsx"],
4
- "sourcesContent": ["/**\n * The viewer-header buttons of the PDF document tools: Annotate, Show original, Download with\n * markup and Sign. Separate parts so a host can place them among its own header actions. On a\n * narrow (`compact`) header each is icon-only; its accessible name stays.\n */\n\nimport type { ReactElement } from 'react'\nimport { Download, FileText, PencilLine, Scissors } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\n\nconst TOUCH = 'pointer-coarse:min-h-11'\n\ninterface ToggleProps {\n /** On (pressed). */\n active: boolean\n onClick: () => void\n compact?: boolean\n}\n\n/** Annotate mode: highlight, comment, stamp, redact. */\nexport function AnnotateButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Annotate: highlight, comment, stamp, redact\"\n aria-label=\"Annotate\"\n data-testid=\"annotate-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <PencilLine className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Annotate</span>}\n </Button>\n )\n}\n\n/** Clip mode: drag over a page to show that part of it in the presentation. */\nexport function ClipButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Clip: drag over a page to show that part in a presentation\"\n aria-label=\"Clip\"\n data-testid=\"clip-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <Scissors className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Clip</span>}\n </Button>\n )\n}\n\n/** The markup is the default view of a marked-up PDF; this shows the untouched file. */\nexport function ShowOriginalButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title={active ? 'Show the markup again' : 'Show the original, without markup'}\n aria-label=\"Show original\"\n data-testid=\"markup-show-original\"\n className={TOUCH}\n onClick={onClick}\n >\n <FileText className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Show original</span>}\n </Button>\n )\n}\n\n/**\n * \"Download with markup\": the PDF with its annotations, which Acrobat and Preview show. With a\n * `disabledReason` (a signed, locked version) it is off and says why.\n */\nexport function DownloadMarkupButton({\n onClick,\n disabledReason,\n}: {\n onClick: () => void\n disabledReason?: string\n}): ReactElement {\n const button = (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n title={\n disabledReason ??\n 'Download with markup: the PDF with its annotations (opens in Acrobat or Preview)'\n }\n aria-label=\"Download with markup\"\n aria-description={disabledReason}\n disabled={!!disabledReason}\n data-testid=\"markup-download\"\n className={TOUCH}\n onClick={onClick}\n >\n <Download className=\"size-4\" />\n </Button>\n )\n // A disabled button gets no pointer events, so the reason sits on a wrapper too.\n return disabledReason ? (\n <span title={disabledReason} className=\"inline-flex\" data-testid=\"markup-download-locked\">\n {button}\n </span>\n ) : (\n button\n )\n}\n\n/** One line where a signed version's content can be edited: an edit is a new, unsigned version. */\nexport function SignedEditNote(): ReactElement {\n return (\n <p\n className=\"border-b px-3 py-1.5 text-xs text-muted-foreground\"\n data-testid=\"signed-edit-note\"\n >\n Editing creates a new unsigned version\n </p>\n )\n}\n"],
4
+ "sourcesContent": ["/**\n * The viewer-header buttons of the PDF document tools: Annotate, Show original, Download with\n * markup and Sign. Separate parts so a host can place them among its own header actions. On a\n * narrow (`compact`) header each is icon-only; its accessible name stays.\n */\n\nimport type { ReactElement } from 'react'\nimport { Download, FileText, PencilLine, Scissors } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\n\nconst TOUCH = 'pointer-coarse:min-h-11'\n\ninterface ToggleProps {\n /** On (pressed). */\n active: boolean\n onClick: () => void\n compact?: boolean\n}\n\n/** Annotate mode: highlight, comment, stamp, redact. */\nexport function AnnotateButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Annotate: highlight, comment, stamp, redact\"\n aria-label=\"Annotate\"\n data-testid=\"annotate-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <PencilLine className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Annotate</span>}\n </Button>\n )\n}\n\n/** Clip mode: drag over a page to show that part of it in the presentation. */\nexport function ClipButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Clip: click a passage (or drag over any area) to gather it, then Show\"\n aria-label=\"Clip\"\n data-testid=\"clip-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <Scissors className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Clip</span>}\n </Button>\n )\n}\n\n/** The markup is the default view of a marked-up PDF; this shows the untouched file. */\nexport function ShowOriginalButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title={active ? 'Show the markup again' : 'Show the original, without markup'}\n aria-label=\"Show original\"\n data-testid=\"markup-show-original\"\n className={TOUCH}\n onClick={onClick}\n >\n <FileText className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Show original</span>}\n </Button>\n )\n}\n\n/**\n * \"Download with markup\": the PDF with its annotations, which Acrobat and Preview show. With a\n * `disabledReason` (a signed, locked version) it is off and says why.\n */\nexport function DownloadMarkupButton({\n onClick,\n disabledReason,\n}: {\n onClick: () => void\n disabledReason?: string\n}): ReactElement {\n const button = (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n title={\n disabledReason ??\n 'Download with markup: the PDF with its annotations (opens in Acrobat or Preview)'\n }\n aria-label=\"Download with markup\"\n aria-description={disabledReason}\n disabled={!!disabledReason}\n data-testid=\"markup-download\"\n className={TOUCH}\n onClick={onClick}\n >\n <Download className=\"size-4\" />\n </Button>\n )\n // A disabled button gets no pointer events, so the reason sits on a wrapper too.\n return disabledReason ? (\n <span title={disabledReason} className=\"inline-flex\" data-testid=\"markup-download-locked\">\n {button}\n </span>\n ) : (\n button\n )\n}\n\n/** One line where a signed version's content can be edited: an edit is a new, unsigned version. */\nexport function SignedEditNote(): ReactElement {\n return (\n <p\n className=\"border-b px-3 py-1.5 text-xs text-muted-foreground\"\n data-testid=\"signed-edit-note\"\n >\n Editing creates a new unsigned version\n </p>\n )\n}\n"],
5
5
  "mappings": ";AAsBI,SAWE,KAXF;AAfJ,SAAS,UAAU,UAAU,YAAY,gBAAgB;AACzD,SAAS,cAAc;AAEvB,MAAM,QAAQ;AAUP,SAAS,eAAe,EAAE,QAAQ,SAAS,QAAQ,GAA8B;AACtF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,SAAS,YAAY;AAAA,MAC9B,MAAM,UAAU,SAAS;AAAA,MACzB,gBAAc;AAAA,MACd,OAAM;AAAA,MACN,cAAW;AAAA,MACX,eAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MAEA;AAAA,4BAAC,cAAW,WAAU,UAAS;AAAA,QAC9B,CAAC,WAAW,oBAAC,UAAK,WAAU,QAAO,sBAAQ;AAAA;AAAA;AAAA,EAC9C;AAEJ;AAGO,SAAS,WAAW,EAAE,QAAQ,SAAS,QAAQ,GAA8B;AAClF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,SAAS,YAAY;AAAA,MAC9B,MAAM,UAAU,SAAS;AAAA,MACzB,gBAAc;AAAA,MACd,OAAM;AAAA,MACN,cAAW;AAAA,MACX,eAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MAEA;AAAA,4BAAC,YAAS,WAAU,UAAS;AAAA,QAC5B,CAAC,WAAW,oBAAC,UAAK,WAAU,QAAO,kBAAI;AAAA;AAAA;AAAA,EAC1C;AAEJ;AAGO,SAAS,mBAAmB,EAAE,QAAQ,SAAS,QAAQ,GAA8B;AAC1F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,SAAS,YAAY;AAAA,MAC9B,MAAM,UAAU,SAAS;AAAA,MACzB,gBAAc;AAAA,MACd,OAAO,SAAS,0BAA0B;AAAA,MAC1C,cAAW;AAAA,MACX,eAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MAEA;AAAA,4BAAC,YAAS,WAAU,UAAS;AAAA,QAC5B,CAAC,WAAW,oBAAC,UAAK,WAAU,QAAO,2BAAa;AAAA;AAAA;AAAA,EACnD;AAEJ;AAMO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AACF,GAGiB;AACf,QAAM,SACJ;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OACE,kBACA;AAAA,MAEF,cAAW;AAAA,MACX,oBAAkB;AAAA,MAClB,UAAU,CAAC,CAAC;AAAA,MACZ,eAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MAEA,8BAAC,YAAS,WAAU,UAAS;AAAA;AAAA,EAC/B;AAGF,SAAO,iBACL,oBAAC,UAAK,OAAO,gBAAgB,WAAU,eAAc,eAAY,0BAC9D,kBACH,IAEA;AAEJ;AAGO,SAAS,iBAA+B;AAC7C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MACb;AAAA;AAAA,EAED;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunk46P7IDBX_cjs = require('../chunk-46P7IDBX.cjs');
5
- var chunkGNZAH6UI_cjs = require('../chunk-GNZAH6UI.cjs');
4
+ var chunkCQ2RJYE2_cjs = require('../chunk-CQ2RJYE2.cjs');
5
+ var chunk2K6IMIVL_cjs = require('../chunk-2K6IMIVL.cjs');
6
6
  var chunkJH6JTI76_cjs = require('../chunk-JH6JTI76.cjs');
7
+ var chunkZESMRGDV_cjs = require('../chunk-ZESMRGDV.cjs');
7
8
  require('../chunk-QQMMCXBP.cjs');
8
9
  require('../chunk-DTMBAFIL.cjs');
9
- var chunkZESMRGDV_cjs = require('../chunk-ZESMRGDV.cjs');
10
10
  require('../chunk-JDFBEGQO.cjs');
11
11
  require('../chunk-ULWRNGGE.cjs');
12
12
  require('../chunk-PLIF5CUV.cjs');
@@ -15,71 +15,71 @@ require('../chunk-PLIF5CUV.cjs');
15
15
 
16
16
  Object.defineProperty(exports, "AnnotateButton", {
17
17
  enumerable: true,
18
- get: function () { return chunk46P7IDBX_cjs.AnnotateButton; }
18
+ get: function () { return chunkCQ2RJYE2_cjs.AnnotateButton; }
19
19
  });
20
20
  Object.defineProperty(exports, "ClipButton", {
21
21
  enumerable: true,
22
- get: function () { return chunk46P7IDBX_cjs.ClipButton; }
22
+ get: function () { return chunkCQ2RJYE2_cjs.ClipButton; }
23
23
  });
24
24
  Object.defineProperty(exports, "DEFAULT_VERSION_SNAPSHOT_BAR_LABELS", {
25
25
  enumerable: true,
26
- get: function () { return chunk46P7IDBX_cjs.DEFAULT_VERSION_SNAPSHOT_BAR_LABELS; }
26
+ get: function () { return chunkCQ2RJYE2_cjs.DEFAULT_VERSION_SNAPSHOT_BAR_LABELS; }
27
27
  });
28
28
  Object.defineProperty(exports, "DownloadMarkupButton", {
29
29
  enumerable: true,
30
- get: function () { return chunk46P7IDBX_cjs.DownloadMarkupButton; }
30
+ get: function () { return chunkCQ2RJYE2_cjs.DownloadMarkupButton; }
31
31
  });
32
32
  Object.defineProperty(exports, "FileShareDialog", {
33
33
  enumerable: true,
34
- get: function () { return chunk46P7IDBX_cjs.FileShareDialog; }
34
+ get: function () { return chunkCQ2RJYE2_cjs.FileShareDialog; }
35
35
  });
36
36
  Object.defineProperty(exports, "MarkupNotices", {
37
37
  enumerable: true,
38
- get: function () { return chunk46P7IDBX_cjs.MarkupNotices; }
38
+ get: function () { return chunkCQ2RJYE2_cjs.MarkupNotices; }
39
39
  });
40
40
  Object.defineProperty(exports, "MarkupViewNote", {
41
41
  enumerable: true,
42
- get: function () { return chunk46P7IDBX_cjs.MarkupViewNote; }
42
+ get: function () { return chunkCQ2RJYE2_cjs.MarkupViewNote; }
43
43
  });
44
44
  Object.defineProperty(exports, "PlaceMySignatureMenuItems", {
45
45
  enumerable: true,
46
- get: function () { return chunk46P7IDBX_cjs.PlaceMySignatureMenuItems; }
46
+ get: function () { return chunkCQ2RJYE2_cjs.PlaceMySignatureMenuItems; }
47
47
  });
48
48
  Object.defineProperty(exports, "ShowOriginalButton", {
49
49
  enumerable: true,
50
- get: function () { return chunk46P7IDBX_cjs.ShowOriginalButton; }
50
+ get: function () { return chunkCQ2RJYE2_cjs.ShowOriginalButton; }
51
51
  });
52
52
  Object.defineProperty(exports, "SignatureRequestBanner", {
53
53
  enumerable: true,
54
- get: function () { return chunk46P7IDBX_cjs.SignatureRequestBanner; }
54
+ get: function () { return chunkCQ2RJYE2_cjs.SignatureRequestBanner; }
55
55
  });
56
56
  Object.defineProperty(exports, "SignedEditNote", {
57
57
  enumerable: true,
58
- get: function () { return chunk46P7IDBX_cjs.SignedEditNote; }
58
+ get: function () { return chunkCQ2RJYE2_cjs.SignedEditNote; }
59
59
  });
60
60
  Object.defineProperty(exports, "VersionSnapshotBar", {
61
61
  enumerable: true,
62
- get: function () { return chunk46P7IDBX_cjs.VersionSnapshotBar; }
62
+ get: function () { return chunkCQ2RJYE2_cjs.VersionSnapshotBar; }
63
63
  });
64
64
  Object.defineProperty(exports, "DELETE_SAVED_SIGNATURE_TEXT", {
65
65
  enumerable: true,
66
- get: function () { return chunkGNZAH6UI_cjs.DELETE_SAVED_SIGNATURE_TEXT; }
66
+ get: function () { return chunk2K6IMIVL_cjs.DELETE_SAVED_SIGNATURE_TEXT; }
67
67
  });
68
68
  Object.defineProperty(exports, "SavedSignatureSettings", {
69
69
  enumerable: true,
70
- get: function () { return chunkGNZAH6UI_cjs.SavedSignatureSettings; }
70
+ get: function () { return chunk2K6IMIVL_cjs.SavedSignatureSettings; }
71
71
  });
72
72
  Object.defineProperty(exports, "SignatureCertificate", {
73
73
  enumerable: true,
74
- get: function () { return chunkGNZAH6UI_cjs.SignatureCertificate; }
74
+ get: function () { return chunk2K6IMIVL_cjs.SignatureCertificate; }
75
75
  });
76
76
  Object.defineProperty(exports, "SignatureStatus", {
77
77
  enumerable: true,
78
- get: function () { return chunkGNZAH6UI_cjs.SignatureStatus; }
78
+ get: function () { return chunk2K6IMIVL_cjs.SignatureStatus; }
79
79
  });
80
80
  Object.defineProperty(exports, "formatSignedAt", {
81
81
  enumerable: true,
82
- get: function () { return chunkGNZAH6UI_cjs.formatSignedAt; }
82
+ get: function () { return chunk2K6IMIVL_cjs.formatSignedAt; }
83
83
  });
84
84
  Object.defineProperty(exports, "SignDocumentDialog", {
85
85
  enumerable: true,
@@ -128,7 +128,8 @@ function DocxCommandMenu({
128
128
  "table-column-left",
129
129
  "table-column-right"
130
130
  ]);
131
- if ((!button || !button.disabled) && target.closest('[aria-disabled="true"]') === null && (button && item && direct.has(item) || target.closest('[role="gridcell"]') || target.closest('[role="menuitemradio"]') || target.closest('[data-testid="docx-insert-my-signature"]') || target.closest('[data-testid="docx-insert-my-initials"]') || target.closest('.native-docx-style-gallery [role="option"]') || button && button.closest(".native-docx-style-gallery"))) {
131
+ if ((!button || !button.disabled) && target.closest('[aria-disabled="true"]') === null && (button && item && direct.has(item) || target.closest('[role="gridcell"]') || target.closest('[role="menuitemradio"]') || target.closest('[data-testid="docx-insert-my-signature"]') || target.closest('[data-testid="docx-insert-my-initials"]') || // Picking a Quick Part inserts it at the caret: back to the document.
132
+ target.closest('[data-testid="docx-quick-parts-panel"] li button') || target.closest('.native-docx-style-gallery [role="option"]') || button && button.closest(".native-docx-style-gallery"))) {
132
133
  close();
133
134
  }
134
135
  },