@arbidocs/blocks 0.5.124 → 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 (109) hide show
  1. package/dist/ConnectedCallDock-XJOYVVAH.cjs +6 -6
  2. package/dist/ConnectedCallRoom-CUDYAPQK.cjs +6 -6
  3. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs → ConnectedNativeDocxComparison-7QQ55JIO.cjs} +12 -12
  4. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs.map → ConnectedNativeDocxComparison-7QQ55JIO.cjs.map} +1 -1
  5. package/dist/{ConnectedPresentation-OV2KBOLK.cjs → ConnectedPresentation-L32JPRFI.cjs} +9 -9
  6. package/dist/{ConnectedPresentation-OV2KBOLK.cjs.map → ConnectedPresentation-L32JPRFI.cjs.map} +1 -1
  7. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
  8. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
  9. package/dist/{ConnectedSlidesTab-LUAGZ6FD.cjs → ConnectedSlidesTab-P7GGNUTO.cjs} +9 -9
  10. package/dist/{ConnectedSlidesTab-LUAGZ6FD.cjs.map → ConnectedSlidesTab-P7GGNUTO.cjs.map} +1 -1
  11. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs → ConnectedStreamedWordArtifact-7NJ3N52V.cjs} +12 -12
  12. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs.map → ConnectedStreamedWordArtifact-7NJ3N52V.cjs.map} +1 -1
  13. package/dist/{DocumentReviewCard-M53XFLI2.cjs → DocumentReviewCard-BFPOFQXI.cjs} +16 -16
  14. package/dist/{DocumentReviewCard-M53XFLI2.cjs.map → DocumentReviewCard-BFPOFQXI.cjs.map} +1 -1
  15. package/dist/{FilesViewerDialog-JWKNJLWG.cjs → FilesViewerDialog-MHUVEZ7M.cjs} +29 -29
  16. package/dist/{FilesViewerDialog-JWKNJLWG.cjs.map → FilesViewerDialog-MHUVEZ7M.cjs.map} +1 -1
  17. package/dist/{NativeDocxEditor-2LQY2CTV.cjs → NativeDocxEditor-SIRYPMBN.cjs} +6 -6
  18. package/dist/{NativeDocxEditor-2LQY2CTV.cjs.map → NativeDocxEditor-SIRYPMBN.cjs.map} +1 -1
  19. package/dist/{WorkspaceTableView-3XYAV4BV.cjs → WorkspaceTableView-MIFYXV3G.cjs} +8 -8
  20. package/dist/{WorkspaceTableView-3XYAV4BV.cjs.map → WorkspaceTableView-MIFYXV3G.cjs.map} +1 -1
  21. package/dist/agents/index.cjs +215 -215
  22. package/dist/ai-IEIR7SC2.cjs +3 -3
  23. package/dist/auth/index.cjs +1 -1
  24. package/dist/calls/index.cjs +2 -2
  25. package/dist/chat/index.cjs +6 -6
  26. package/dist/{chunk-GNZAH6UI.cjs → chunk-2K6IMIVL.cjs} +3 -3
  27. package/dist/{chunk-GNZAH6UI.cjs.map → chunk-2K6IMIVL.cjs.map} +1 -1
  28. package/dist/{chunk-CQQQIZU4.cjs → chunk-3UP32FM3.cjs} +5 -5
  29. package/dist/{chunk-CQQQIZU4.cjs.map → chunk-3UP32FM3.cjs.map} +1 -1
  30. package/dist/{chunk-QG2U2JGX.cjs → chunk-4LP5MJGQ.cjs} +4 -4
  31. package/dist/{chunk-QG2U2JGX.cjs.map → chunk-4LP5MJGQ.cjs.map} +1 -1
  32. package/dist/{chunk-BX6G2ZCI.cjs → chunk-6JMW3IJ2.cjs} +112 -87
  33. package/dist/chunk-6JMW3IJ2.cjs.map +1 -0
  34. package/dist/{chunk-XGM4VVNV.cjs → chunk-7RJZIPLE.cjs} +33 -33
  35. package/dist/{chunk-XGM4VVNV.cjs.map → chunk-7RJZIPLE.cjs.map} +1 -1
  36. package/dist/{chunk-7NLO7ASW.cjs → chunk-AISYXX4M.cjs} +4 -4
  37. package/dist/{chunk-7NLO7ASW.cjs.map → chunk-AISYXX4M.cjs.map} +1 -1
  38. package/dist/{chunk-5QERK4PK.cjs → chunk-AS6QZETU.cjs} +35 -35
  39. package/dist/{chunk-5QERK4PK.cjs.map → chunk-AS6QZETU.cjs.map} +1 -1
  40. package/dist/{chunk-V6MW7B4B.cjs → chunk-B3R62764.cjs} +6 -6
  41. package/dist/{chunk-V6MW7B4B.cjs.map → chunk-B3R62764.cjs.map} +1 -1
  42. package/dist/{chunk-VKH3BEZE.cjs → chunk-BLIO3B7Z.cjs} +3 -3
  43. package/dist/{chunk-VKH3BEZE.cjs.map → chunk-BLIO3B7Z.cjs.map} +1 -1
  44. package/dist/{chunk-3IH55CDE.cjs → chunk-CQ2RJYE2.cjs} +3 -3
  45. package/dist/{chunk-3IH55CDE.cjs.map → chunk-CQ2RJYE2.cjs.map} +1 -1
  46. package/dist/{chunk-MXBXZXXQ.cjs → chunk-ENOPKX7E.cjs} +3 -3
  47. package/dist/{chunk-MXBXZXXQ.cjs.map → chunk-ENOPKX7E.cjs.map} +1 -1
  48. package/dist/{chunk-2CSLFAGF.cjs → chunk-GAMRVB3I.cjs} +4 -3
  49. package/dist/chunk-GAMRVB3I.cjs.map +1 -0
  50. package/dist/chunk-IRGRMJPP.cjs +18 -0
  51. package/dist/{chunk-SDRYSLOX.cjs.map → chunk-IRGRMJPP.cjs.map} +1 -1
  52. package/dist/{chunk-ADDQKZ5I.cjs → chunk-J3FFSEKO.cjs} +4 -4
  53. package/dist/{chunk-ADDQKZ5I.cjs.map → chunk-J3FFSEKO.cjs.map} +1 -1
  54. package/dist/{chunk-ALK3PUUB.cjs → chunk-L6HTZIBD.cjs} +3 -3
  55. package/dist/{chunk-ALK3PUUB.cjs.map → chunk-L6HTZIBD.cjs.map} +1 -1
  56. package/dist/{chunk-OHHKBURG.cjs → chunk-OGK377NL.cjs} +33 -33
  57. package/dist/{chunk-OHHKBURG.cjs.map → chunk-OGK377NL.cjs.map} +1 -1
  58. package/dist/{chunk-T73BHNQX.cjs → chunk-OHWHYVKG.cjs} +3 -3
  59. package/dist/{chunk-T73BHNQX.cjs.map → chunk-OHWHYVKG.cjs.map} +1 -1
  60. package/dist/{chunk-MLA2BJ2Y.cjs → chunk-PSB64T43.cjs} +28 -28
  61. package/dist/{chunk-MLA2BJ2Y.cjs.map → chunk-PSB64T43.cjs.map} +1 -1
  62. package/dist/{chunk-COD5ENHK.cjs → chunk-PVJ5ODDB.cjs} +4 -4
  63. package/dist/{chunk-COD5ENHK.cjs.map → chunk-PVJ5ODDB.cjs.map} +1 -1
  64. package/dist/{chunk-7557LDAN.cjs → chunk-PWBRE7JA.cjs} +5 -5
  65. package/dist/{chunk-7557LDAN.cjs.map → chunk-PWBRE7JA.cjs.map} +1 -1
  66. package/dist/{chunk-7PN3YENO.cjs → chunk-QIK7E6VF.cjs} +4 -4
  67. package/dist/{chunk-7PN3YENO.cjs.map → chunk-QIK7E6VF.cjs.map} +1 -1
  68. package/dist/{chunk-H236SNEV.cjs → chunk-TSFNLY3K.cjs} +4 -4
  69. package/dist/{chunk-H236SNEV.cjs.map → chunk-TSFNLY3K.cjs.map} +1 -1
  70. package/dist/{chunk-YGBHY67W.cjs → chunk-UA7HOLAZ.cjs} +5 -5
  71. package/dist/{chunk-YGBHY67W.cjs.map → chunk-UA7HOLAZ.cjs.map} +1 -1
  72. package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
  73. package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
  74. package/dist/{chunk-E3L5DB5F.cjs → chunk-YOEP3I4V.cjs} +5 -5
  75. package/dist/{chunk-E3L5DB5F.cjs.map → chunk-YOEP3I4V.cjs.map} +1 -1
  76. package/dist/{chunk-EMRY62HS.cjs → chunk-YVO6Z5BS.cjs} +10 -10
  77. package/dist/{chunk-EMRY62HS.cjs.map → chunk-YVO6Z5BS.cjs.map} +1 -1
  78. package/dist/connect/docx.cjs +16 -16
  79. package/dist/connect/index.cjs +979 -979
  80. package/dist/connect/viewer.cjs +22 -22
  81. package/dist/connection/viewer/VersionDropdown.js +1 -1
  82. package/dist/connection/viewer/VersionDropdown.js.map +1 -1
  83. package/dist/connection/viewer/ViewerPdfPane.js +2 -0
  84. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  85. package/dist/connection/viewer/pdf/usePassageTextFallback.d.ts +12 -0
  86. package/dist/connection/viewer/pdf/usePassageTextFallback.js +30 -0
  87. package/dist/connection/viewer/pdf/usePassageTextFallback.js.map +7 -0
  88. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js +2 -11
  89. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js.map +2 -2
  90. package/dist/connection/viewer/useViewerTabs.js +13 -1
  91. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  92. package/dist/document-tools/index.cjs +20 -20
  93. package/dist/docx/DocxCommandMenu.js +2 -1
  94. package/dist/docx/DocxCommandMenu.js.map +2 -2
  95. package/dist/docx/index.cjs +38 -38
  96. package/dist/embed/index.cjs +19 -19
  97. package/dist/facts/index.cjs +64 -64
  98. package/dist/files/index.cjs +223 -223
  99. package/dist/index.cjs +521 -521
  100. package/dist/settings/index.cjs +146 -146
  101. package/dist/site/index.cjs +6 -6
  102. package/dist/studio/index.cjs +9 -9
  103. package/dist/styles.css +1 -1
  104. package/dist/workflow-canvas/index.cjs +34 -34
  105. package/node_modules/@arbidocs/coedit/package.json +1 -1
  106. package/package.json +5 -5
  107. package/dist/chunk-2CSLFAGF.cjs.map +0 -1
  108. package/dist/chunk-BX6G2ZCI.cjs.map +0 -1
  109. package/dist/chunk-SDRYSLOX.cjs +0 -18
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkBX6G2ZCI_cjs = require('../chunk-BX6G2ZCI.cjs');
4
+ var chunk6JMW3IJ2_cjs = require('../chunk-6JMW3IJ2.cjs');
5
5
  require('../chunk-JITYC4OS.cjs');
6
6
  require('../chunk-WVZLAAIZ.cjs');
7
7
  require('../chunk-MVXHTAJ4.cjs');
@@ -10,30 +10,31 @@ require('../chunk-ORNLCBNE.cjs');
10
10
  require('../chunk-4CIVQWAX.cjs');
11
11
  var chunkPL7HUTM3_cjs = require('../chunk-PL7HUTM3.cjs');
12
12
  require('../chunk-GFUOCGY6.cjs');
13
- require('../chunk-ADDQKZ5I.cjs');
14
- require('../chunk-KXIRVKCJ.cjs');
15
- require('../chunk-5QERK4PK.cjs');
16
- require('../chunk-T73BHNQX.cjs');
13
+ require('../chunk-J3FFSEKO.cjs');
14
+ require('../chunk-PWBRE7JA.cjs');
15
+ require('../chunk-4ONPEVTP.cjs');
16
+ require('../chunk-V3KLUWQQ.cjs');
17
+ require('../chunk-CQ2RJYE2.cjs');
18
+ require('../chunk-2K6IMIVL.cjs');
19
+ require('../chunk-JH6JTI76.cjs');
20
+ require('../chunk-ZESMRGDV.cjs');
21
+ require('../chunk-UUENH4BJ.cjs');
22
+ require('../chunk-AS6QZETU.cjs');
23
+ require('../chunk-OHWHYVKG.cjs');
17
24
  require('../chunk-HYUKPHCT.cjs');
18
- require('../chunk-ALK3PUUB.cjs');
25
+ require('../chunk-L6HTZIBD.cjs');
19
26
  require('../chunk-223D4727.cjs');
20
27
  require('../chunk-SNUBQMIS.cjs');
21
- require('../chunk-7557LDAN.cjs');
22
- require('../chunk-4ONPEVTP.cjs');
23
- require('../chunk-V3KLUWQQ.cjs');
24
28
  require('../chunk-P5AQYC4D.cjs');
25
29
  require('../chunk-WAV762GP.cjs');
26
- require('../chunk-3IH55CDE.cjs');
27
- require('../chunk-GNZAH6UI.cjs');
28
- require('../chunk-JH6JTI76.cjs');
29
30
  require('../chunk-QQMMCXBP.cjs');
30
31
  require('../chunk-DTMBAFIL.cjs');
31
- require('../chunk-ZESMRGDV.cjs');
32
32
  require('../chunk-VCEX7COE.cjs');
33
33
  require('../chunk-34HQO4ZQ.cjs');
34
34
  require('../chunk-KA3F6TIH.cjs');
35
35
  require('../chunk-K4763GD5.cjs');
36
36
  require('../chunk-2RLA6QO2.cjs');
37
+ require('../chunk-BLIO3B7Z.cjs');
37
38
  require('../chunk-MZZ3SBQL.cjs');
38
39
  require('../chunk-NY3YUCOW.cjs');
39
40
  require('../chunk-325GVZE6.cjs');
@@ -41,15 +42,12 @@ require('../chunk-WQMR3O2D.cjs');
41
42
  require('../chunk-ORELHENJ.cjs');
42
43
  require('../chunk-NWNVWO6L.cjs');
43
44
  require('../chunk-SK6HQ46Q.cjs');
44
- require('../chunk-MNIQDXM6.cjs');
45
- require('../chunk-E3Y7RI3J.cjs');
46
- require('../chunk-TG2GM7WJ.cjs');
47
- require('../chunk-VKH3BEZE.cjs');
48
45
  require('../chunk-OEJQFPWO.cjs');
46
+ require('../chunk-TG2GM7WJ.cjs');
47
+ require('../chunk-JJZOL5MG.cjs');
49
48
  require('../chunk-OYXWQTHF.cjs');
50
49
  require('../chunk-S237ORM3.cjs');
51
50
  require('../chunk-II2OEXHW.cjs');
52
- require('../chunk-JJZOL5MG.cjs');
53
51
  require('../chunk-3YEXZX4H.cjs');
54
52
  require('../chunk-4PA6VCCR.cjs');
55
53
  require('../chunk-WXUU3COI.cjs');
@@ -58,13 +56,13 @@ require('../chunk-RL2HI6NP.cjs');
58
56
  require('../chunk-6UZC4XVV.cjs');
59
57
  require('../chunk-YVCOQHCE.cjs');
60
58
  require('../chunk-JV5TVUOU.cjs');
59
+ require('../chunk-VZOOGA47.cjs');
61
60
  require('../chunk-ZVEW3JBT.cjs');
62
61
  require('../chunk-EG7EJFUE.cjs');
63
62
  require('../chunk-VG24E4JJ.cjs');
64
63
  require('../chunk-U2FFG2B3.cjs');
65
64
  require('../chunk-KKYNTWDU.cjs');
66
65
  require('../chunk-M74FWYNL.cjs');
67
- require('../chunk-VZOOGA47.cjs');
68
66
  require('../chunk-HQDR43JC.cjs');
69
67
  require('../chunk-JR2YSBD5.cjs');
70
68
  require('../chunk-3YZKDCWY.cjs');
@@ -81,21 +79,23 @@ require('../chunk-KQF7POTG.cjs');
81
79
  require('../chunk-75BNMCUX.cjs');
82
80
  require('../chunk-FX3K6LNZ.cjs');
83
81
  require('../chunk-QGVOT7E4.cjs');
82
+ require('../chunk-IPSHAMO2.cjs');
84
83
  require('../chunk-QRAQZTJE.cjs');
85
84
  require('../chunk-UDSHVNU3.cjs');
86
- require('../chunk-IPSHAMO2.cjs');
87
85
  require('../chunk-PPCATBOY.cjs');
86
+ require('../chunk-LJJJ6CYH.cjs');
87
+ require('../chunk-MNIQDXM6.cjs');
88
+ require('../chunk-E3Y7RI3J.cjs');
88
89
  require('../chunk-TKHCIHE2.cjs');
89
90
  require('../chunk-JDFBEGQO.cjs');
90
91
  require('../chunk-ULWRNGGE.cjs');
91
- require('../chunk-LJJJ6CYH.cjs');
92
92
  require('../chunk-PLIF5CUV.cjs');
93
93
 
94
94
 
95
95
 
96
96
  Object.defineProperty(exports, "ConnectedDocumentViewer", {
97
97
  enumerable: true,
98
- get: function () { return chunkBX6G2ZCI_cjs.ConnectedDocumentViewer; }
98
+ get: function () { return chunk6JMW3IJ2_cjs.ConnectedDocumentViewer; }
99
99
  });
100
100
  Object.defineProperty(exports, "ConnectedDocumentToolsProvider", {
101
101
  enumerable: true,
@@ -14,7 +14,7 @@ function VersionDropdown({
14
14
  {
15
15
  "aria-label": "Active document version",
16
16
  "data-testid": "document-version-dropdown",
17
- className: "max-w-44 rounded border border-input bg-background px-2 py-1 text-sm",
17
+ className: "max-w-44 rounded border border-input bg-background px-2 py-1 text-sm pointer-coarse:min-h-11",
18
18
  value: active?.id ?? "",
19
19
  onChange: (event) => {
20
20
  const id = event.currentTarget.value;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/viewer/VersionDropdown.tsx"],
4
- "sourcesContent": ["import type { ArtifactVersion } from '@arbidocs/react/artifacts'\n\n/** The version on screen, with a direct way to open another version. */\nexport function VersionDropdown({\n versions,\n activeId,\n isSnapshot,\n onOpen,\n onHistory,\n}: {\n versions: readonly ArtifactVersion[]\n activeId: string | null\n isSnapshot: boolean\n onOpen: (id: string) => void\n onHistory: () => void\n}) {\n const active = versions.find((version) => version.id === activeId)\n const pendingVersion = activeId?.match(/@v([1-9]\\d*)$/)?.[1]\n return (\n <select\n aria-label=\"Active document version\"\n data-testid=\"document-version-dropdown\"\n className=\"max-w-44 rounded border border-input bg-background px-2 py-1 text-sm\"\n value={active?.id ?? ''}\n onChange={(event) => {\n const id = event.currentTarget.value\n if (id === '__history') onHistory()\n else if (versions.some((version) => version.id === id)) onOpen(id)\n }}\n >\n {!active && (\n <option value=\"\">\n {pendingVersion\n ? `v${pendingVersion} \u00B7 ${isSnapshot ? 'Read only' : 'Current'}`\n : 'Version unavailable'}\n </option>\n )}\n {[...versions]\n .sort((a, b) => b.number - a.number)\n .map((version) => (\n <option key={version.id} value={version.id}>\n v{version.number}\n {version.isCurrent ? ' \u00B7 Current' : ' \u00B7 Read only'}\n </option>\n ))}\n <option value=\"__history\">Version history\u2026</option>\n </select>\n )\n}\n"],
4
+ "sourcesContent": ["import type { ArtifactVersion } from '@arbidocs/react/artifacts'\n\n/** The version on screen, with a direct way to open another version. */\nexport function VersionDropdown({\n versions,\n activeId,\n isSnapshot,\n onOpen,\n onHistory,\n}: {\n versions: readonly ArtifactVersion[]\n activeId: string | null\n isSnapshot: boolean\n onOpen: (id: string) => void\n onHistory: () => void\n}) {\n const active = versions.find((version) => version.id === activeId)\n const pendingVersion = activeId?.match(/@v([1-9]\\d*)$/)?.[1]\n return (\n <select\n aria-label=\"Active document version\"\n data-testid=\"document-version-dropdown\"\n className=\"max-w-44 rounded border border-input bg-background px-2 py-1 text-sm pointer-coarse:min-h-11\"\n value={active?.id ?? ''}\n onChange={(event) => {\n const id = event.currentTarget.value\n if (id === '__history') onHistory()\n else if (versions.some((version) => version.id === id)) onOpen(id)\n }}\n >\n {!active && (\n <option value=\"\">\n {pendingVersion\n ? `v${pendingVersion} \u00B7 ${isSnapshot ? 'Read only' : 'Current'}`\n : 'Version unavailable'}\n </option>\n )}\n {[...versions]\n .sort((a, b) => b.number - a.number)\n .map((version) => (\n <option key={version.id} value={version.id}>\n v{version.number}\n {version.isCurrent ? ' \u00B7 Current' : ' \u00B7 Read only'}\n </option>\n ))}\n <option value=\"__history\">Version history\u2026</option>\n </select>\n )\n}\n"],
5
5
  "mappings": ";AA+BQ,cASE,YATF;AA5BD,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,SAAS,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,QAAQ;AACjE,QAAM,iBAAiB,UAAU,MAAM,eAAe,IAAI,CAAC;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAW;AAAA,MACX,eAAY;AAAA,MACZ,WAAU;AAAA,MACV,OAAO,QAAQ,MAAM;AAAA,MACrB,UAAU,CAAC,UAAU;AACnB,cAAM,KAAK,MAAM,cAAc;AAC/B,YAAI,OAAO,YAAa,WAAU;AAAA,iBACzB,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,EAAE,EAAG,QAAO,EAAE;AAAA,MACnE;AAAA,MAEC;AAAA,SAAC,UACA,oBAAC,YAAO,OAAM,IACX,2BACG,IAAI,cAAc,SAAM,aAAa,cAAc,SAAS,KAC5D,uBACN;AAAA,QAED,CAAC,GAAG,QAAQ,EACV,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAClC,IAAI,CAAC,YACJ,qBAAC,YAAwB,OAAO,QAAQ,IAAI;AAAA;AAAA,UACxC,QAAQ;AAAA,UACT,QAAQ,YAAY,kBAAe;AAAA,aAFzB,QAAQ,EAGrB,CACD;AAAA,QACH,oBAAC,YAAO,OAAM,aAAY,mCAAgB;AAAA;AAAA;AAAA,EAC5C;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -12,6 +12,7 @@ import { friendlyFileType } from "@arbidocs/react/ui";
12
12
  import { ViewerLoadError, ViewerMessage, ViewerPreviewUnavailable } from "../../files/index.js";
13
13
  import { usePdfClipOutlines } from "./pdf/usePdfClipOutlines.js";
14
14
  import { usePdfPassageHighlights } from "./pdf/usePdfPassageHighlights.js";
15
+ import { usePassageTextFallback } from "./pdf/usePassageTextFallback.js";
15
16
  import { useViewerIsDetached } from "./support.js";
16
17
  import { isLegacyPresentationFile } from "../../presentation/panel-id.js";
17
18
  import { PresentationFileCard } from "../presentation/PresentationFileCard.js";
@@ -86,6 +87,7 @@ function ViewerPdfPane({
86
87
  placeMark = null
87
88
  }) {
88
89
  const { documentData, isDownloadOnly, isVideo, isAudio, isImage, isDocx } = doc;
90
+ usePassageTextFallback(!!pdfError);
89
91
  const showMarkup = markup.hasMarkup && !markup.showOriginal;
90
92
  if (isLegacyPresentationFile(documentData?.file_name)) {
91
93
  return /* @__PURE__ */ jsx(PresentationFileCard, { documentId, fileName: documentData?.file_name ?? "" });
@@ -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 { 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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",
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 { usePassageTextFallback } from './pdf/usePassageTextFallback'\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 // A passage the PDF cannot light (no box on its page, or no PDF) opens on the text view.\n usePassageTextFallback(!!pdfError)\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
  }
@@ -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
  }
@@ -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
  }
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunk3IH55CDE_cjs = require('../chunk-3IH55CDE.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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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 chunk3IH55CDE_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
  },