@arbidocs/blocks 0.5.115 → 0.5.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs → ConnectedNativeDocxComparison-546ILGLW.cjs} +8 -8
  2. package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs.map → ConnectedNativeDocxComparison-546ILGLW.cjs.map} +1 -1
  3. package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs} +8 -8
  4. package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs.map → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs.map} +1 -1
  5. package/dist/{FilesViewerDialog-I5QIHQZT.cjs → FilesViewerDialog-6UKR5WEF.cjs} +6 -6
  6. package/dist/{FilesViewerDialog-I5QIHQZT.cjs.map → FilesViewerDialog-6UKR5WEF.cjs.map} +1 -1
  7. package/dist/{NativeDocxEditor-H6TAEVGY.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
  8. package/dist/{NativeDocxEditor-H6TAEVGY.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
  9. package/dist/{chunk-M6IKVKU5.cjs → chunk-2CSLFAGF.cjs} +392 -149
  10. package/dist/chunk-2CSLFAGF.cjs.map +1 -0
  11. package/dist/{chunk-24EDG4PC.cjs → chunk-B2HNNG25.cjs} +5 -5
  12. package/dist/{chunk-24EDG4PC.cjs.map → chunk-B2HNNG25.cjs.map} +1 -1
  13. package/dist/{chunk-IW7CDJTA.cjs → chunk-COD5ENHK.cjs} +4 -4
  14. package/dist/{chunk-IW7CDJTA.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
  15. package/dist/chunk-HB2O4THB.cjs +18 -0
  16. package/dist/{chunk-CIHERNDO.cjs.map → chunk-HB2O4THB.cjs.map} +1 -1
  17. package/dist/{chunk-WR2SF44W.cjs → chunk-NIE3N6OM.cjs} +4 -4
  18. package/dist/{chunk-WR2SF44W.cjs.map → chunk-NIE3N6OM.cjs.map} +1 -1
  19. package/dist/{chunk-ZTXQIIFV.cjs → chunk-QHOHDNBU.cjs} +6 -6
  20. package/dist/{chunk-ZTXQIIFV.cjs.map → chunk-QHOHDNBU.cjs.map} +1 -1
  21. package/dist/{chunk-A3T3IC3K.cjs → chunk-SB4M3ITT.cjs} +190 -36
  22. package/dist/chunk-SB4M3ITT.cjs.map +1 -0
  23. package/dist/{chunk-X5LANJDZ.cjs → chunk-VGCTYTEW.cjs} +14 -6
  24. package/dist/chunk-VGCTYTEW.cjs.map +1 -0
  25. package/dist/{chunk-3A7QWUAW.cjs → chunk-VKH3BEZE.cjs} +3 -3
  26. package/dist/{chunk-3A7QWUAW.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
  27. package/dist/{chunk-42TURFHF.cjs → chunk-YGBHY67W.cjs} +5 -5
  28. package/dist/{chunk-42TURFHF.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
  29. package/dist/connect/docx.cjs +12 -12
  30. package/dist/connect/index.cjs +78 -78
  31. package/dist/connect/viewer.cjs +4 -4
  32. package/dist/connection/docx/ConnectedNativeDocxEditor.js +10 -2
  33. package/dist/connection/docx/ConnectedNativeDocxEditor.js.map +2 -2
  34. package/dist/connection/viewer/ConnectedDocumentViewer.js +124 -21
  35. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  36. package/dist/connection/viewer/VersionDropdown.d.ts +9 -0
  37. package/dist/connection/viewer/VersionDropdown.js +39 -0
  38. package/dist/connection/viewer/VersionDropdown.js.map +7 -0
  39. package/dist/connection/viewer/ViewerPdfPane.js +4 -1
  40. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  41. package/dist/connection/viewer/useViewerBlobs.d.ts +3 -1
  42. package/dist/connection/viewer/useViewerBlobs.js +14 -8
  43. package/dist/connection/viewer/useViewerBlobs.js.map +2 -2
  44. package/dist/connection/viewer/useViewerTabs.js +10 -0
  45. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  46. package/dist/docx/DocxCommandMenu.d.ts +8 -0
  47. package/dist/docx/DocxCommandMenu.js +202 -0
  48. package/dist/docx/DocxCommandMenu.js.map +7 -0
  49. package/dist/docx/NativeDocxEditor.d.ts +4 -2
  50. package/dist/docx/NativeDocxEditor.js +51 -12
  51. package/dist/docx/NativeDocxEditor.js.map +2 -2
  52. package/dist/docx/RibbonMenu.d.ts +3 -1
  53. package/dist/docx/RibbonMenu.js +10 -3
  54. package/dist/docx/RibbonMenu.js.map +2 -2
  55. package/dist/docx/RibbonOverflow.d.ts +3 -0
  56. package/dist/docx/RibbonOverflow.js +24 -1
  57. package/dist/docx/RibbonOverflow.js.map +2 -2
  58. package/dist/docx/index.cjs +38 -38
  59. package/dist/docx/signatures/SignatureFields.d.ts +3 -1
  60. package/dist/docx/signatures/SignatureFields.js +17 -8
  61. package/dist/docx/signatures/SignatureFields.js.map +2 -2
  62. package/dist/index.cjs +50 -50
  63. package/dist/styles.css +1 -1
  64. package/dist/workflow-canvas/index.cjs +9 -9
  65. package/node_modules/@arbidocs/coedit/package.json +1 -1
  66. package/package.json +5 -5
  67. package/src/docx/styles.css +94 -0
  68. package/dist/chunk-A3T3IC3K.cjs.map +0 -1
  69. package/dist/chunk-CIHERNDO.cjs +0 -18
  70. package/dist/chunk-M6IKVKU5.cjs.map +0 -1
  71. package/dist/chunk-X5LANJDZ.cjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkIW7CDJTA_cjs = require('./chunk-IW7CDJTA.cjs');
5
- var chunkX5LANJDZ_cjs = require('./chunk-X5LANJDZ.cjs');
4
+ var chunkCOD5ENHK_cjs = require('./chunk-COD5ENHK.cjs');
5
+ var chunkVGCTYTEW_cjs = require('./chunk-VGCTYTEW.cjs');
6
6
  var react = require('@arbidocs/react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
 
@@ -10,13 +10,13 @@ function ConnectedNativeDocxComparison({
10
10
  fontBaseUrl,
11
11
  ...props
12
12
  }) {
13
- const adapter = chunkX5LANJDZ_cjs.useConnectedNativeDocxAdapter(fontBaseUrl);
13
+ const adapter = chunkVGCTYTEW_cjs.useConnectedNativeDocxAdapter(fontBaseUrl);
14
14
  const { data: documents, isLoading } = react.useDocuments();
15
15
  const morePages = react.useDocumentsLoading();
16
16
  if (isLoading || morePages)
17
17
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-error", role: "status", children: "Comparing Word documents\u2026" });
18
18
  return /* @__PURE__ */ jsxRuntime.jsx(
19
- chunkIW7CDJTA_cjs.NativeDocxComparison,
19
+ chunkCOD5ENHK_cjs.NativeDocxComparison,
20
20
  {
21
21
  ...props,
22
22
  adapter,
@@ -27,5 +27,5 @@ function ConnectedNativeDocxComparison({
27
27
  }
28
28
 
29
29
  exports.ConnectedNativeDocxComparison = ConnectedNativeDocxComparison;
30
- //# sourceMappingURL=chunk-ZTXQIIFV.cjs.map
31
- //# sourceMappingURL=chunk-ZTXQIIFV.cjs.map
30
+ //# sourceMappingURL=chunk-QHOHDNBU.cjs.map
31
+ //# sourceMappingURL=chunk-QHOHDNBU.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/connection/docx/ConnectedNativeDocxComparison.tsx"],"names":["useConnectedNativeDocxAdapter","useDocuments","useDocumentsLoading","jsx","NativeDocxComparison"],"mappings":";;;;;;;AAYO,SAAS,6BAAA,CAA8B;AAAA,EAC5C,WAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,MAAM,OAAA,GAAUA,gDAA8B,WAAW,CAAA;AACzD,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,SAAA,KAAcC,kBAAA,EAAa;AAEpD,EAAA,MAAM,YAAYC,yBAAA,EAAoB;AAEtC,EAAA,IAAI,SAAA,IAAa,SAAA;AACf,IAAA,sCACG,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,IAAA,EAAK,UAAS,QAAA,EAAA,gCAAA,EAEjD,CAAA;AAEJ,EAAA,uBACEC,cAAA;AAAA,IAACC,sCAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,OAAA,CAAQ;AAAA;AAAA,GACtB;AAEJ","file":"chunk-ZTXQIIFV.cjs","sourcesContent":["import { useDocuments, useDocumentsLoading } from '@arbidocs/react'\nimport {\n NativeDocxComparison,\n type NativeDocxComparisonProps,\n} from '../../docx/NativeDocxComparison'\nimport { useConnectedNativeDocxAdapter } from './ConnectedNativeDocxEditor'\n\n/**\n * The Word redline of two documents or versions, on the signed-in session. The unedited redline\n * saved earlier from the same versions is opened again (found in the workspace's documents, once\n * all their pages are read), so opening a comparison saves at most one.\n */\nexport function ConnectedNativeDocxComparison({\n fontBaseUrl,\n ...props\n}: Omit<NativeDocxComparisonProps, 'adapter' | 'onCompared' | 'documents'> & {\n fontBaseUrl?: string\n}) {\n const adapter = useConnectedNativeDocxAdapter(fontBaseUrl)\n const { data: documents, isLoading } = useDocuments()\n // Every page: the first holds only the oldest documents, and a redline is often newer.\n const morePages = useDocumentsLoading()\n // Until the documents are read, a saved redline can't be found: wait rather than save another.\n if (isLoading || morePages)\n return (\n <div className=\"native-docx-error\" role=\"status\">\n Comparing Word documents…\n </div>\n )\n return (\n <NativeDocxComparison\n {...props}\n adapter={adapter}\n documents={documents}\n onCompared={adapter.onVersionSaved}\n />\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/connection/docx/ConnectedNativeDocxComparison.tsx"],"names":["useConnectedNativeDocxAdapter","useDocuments","useDocumentsLoading","jsx","NativeDocxComparison"],"mappings":";;;;;;;AAYO,SAAS,6BAAA,CAA8B;AAAA,EAC5C,WAAA;AAAA,EACA,GAAG;AACL,CAAA,EAEG;AACD,EAAA,MAAM,OAAA,GAAUA,gDAA8B,WAAW,CAAA;AACzD,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,SAAA,KAAcC,kBAAA,EAAa;AAEpD,EAAA,MAAM,YAAYC,yBAAA,EAAoB;AAEtC,EAAA,IAAI,SAAA,IAAa,SAAA;AACf,IAAA,sCACG,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,IAAA,EAAK,UAAS,QAAA,EAAA,gCAAA,EAEjD,CAAA;AAEJ,EAAA,uBACEC,cAAA;AAAA,IAACC,sCAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,OAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAY,OAAA,CAAQ;AAAA;AAAA,GACtB;AAEJ","file":"chunk-QHOHDNBU.cjs","sourcesContent":["import { useDocuments, useDocumentsLoading } from '@arbidocs/react'\nimport {\n NativeDocxComparison,\n type NativeDocxComparisonProps,\n} from '../../docx/NativeDocxComparison'\nimport { useConnectedNativeDocxAdapter } from './ConnectedNativeDocxEditor'\n\n/**\n * The Word redline of two documents or versions, on the signed-in session. The unedited redline\n * saved earlier from the same versions is opened again (found in the workspace's documents, once\n * all their pages are read), so opening a comparison saves at most one.\n */\nexport function ConnectedNativeDocxComparison({\n fontBaseUrl,\n ...props\n}: Omit<NativeDocxComparisonProps, 'adapter' | 'onCompared' | 'documents'> & {\n fontBaseUrl?: string\n}) {\n const adapter = useConnectedNativeDocxAdapter(fontBaseUrl)\n const { data: documents, isLoading } = useDocuments()\n // Every page: the first holds only the oldest documents, and a redline is often newer.\n const morePages = useDocumentsLoading()\n // Until the documents are read, a saved redline can't be found: wait rather than save another.\n if (isLoading || morePages)\n return (\n <div className=\"native-docx-error\" role=\"status\">\n Comparing Word documents…\n </div>\n )\n return (\n <NativeDocxComparison\n {...props}\n adapter={adapter}\n documents={documents}\n onCompared={adapter.onVersionSaved}\n />\n )\n}\n"]}
@@ -7,7 +7,7 @@ var chunkYGXOKB5Z_cjs = require('./chunk-YGXOKB5Z.cjs');
7
7
  var chunkKXIRVKCJ_cjs = require('./chunk-KXIRVKCJ.cjs');
8
8
  var chunkTT4IF52H_cjs = require('./chunk-TT4IF52H.cjs');
9
9
  var chunkNNUK5ZM7_cjs = require('./chunk-NNUK5ZM7.cjs');
10
- var chunkX5LANJDZ_cjs = require('./chunk-X5LANJDZ.cjs');
10
+ var chunkVGCTYTEW_cjs = require('./chunk-VGCTYTEW.cjs');
11
11
  var chunkYYPZOEED_cjs = require('./chunk-YYPZOEED.cjs');
12
12
  var chunkGNZAH6UI_cjs = require('./chunk-GNZAH6UI.cjs');
13
13
  var chunkJH6JTI76_cjs = require('./chunk-JH6JTI76.cjs');
@@ -389,26 +389,30 @@ function useViewedDocument(documentId) {
389
389
  hasParsedContent
390
390
  };
391
391
  }
392
+ var offlineCopies = /* @__PURE__ */ new WeakSet();
392
393
  function useViewerBlobs(documentId, doc) {
393
394
  const { documentData, isArtifact, isDocx, isXlsx, isDownloadOnly, isWebmFile } = doc;
394
395
  const { setWebmHasVideoTrack } = doc;
395
396
  const { client, saveFile } = documentTools.useDocumentTools();
396
397
  const { notify } = chunkTKHCIHE2_cjs.useBlocksEnvironment();
397
398
  const currentVersion = documentData?.current_version ?? 1;
399
+ const snapshot = !!artifacts.parseVersionRef(documentId).version;
398
400
  const name = documentData?.file_name;
399
401
  const original = ui.isImageFile(name) || ui.isVideoFile(name) || ui.isAudioFile(name);
400
- const fallback = documentData && !artifacts.parseVersionRef(documentId).version ? () => react.loadOfflineDocument(documentData.external_id) : void 0;
402
+ const fallback = documentData && !snapshot ? async () => {
403
+ const blob = await react.loadOfflineDocument(documentData.external_id);
404
+ if (blob) offlineCopies.add(blob);
405
+ return blob;
406
+ } : void 0;
401
407
  const pdf = documentTools.useDocumentBytes(documentId, {
402
408
  version: currentVersion,
403
409
  kind: original ? "original" : "pdf",
404
- enabled: !isArtifact && !!documentData && !isDownloadOnly && (!isDocx || documentData.status === "completed" || documentData.status === "low-content"),
410
+ enabled: (!isArtifact || isDocx && !doc.isDraft && !doc.isStreaming && !doc.liveKind) && !!documentData && !isDownloadOnly && (!isDocx || snapshot || documentData.status === "completed" || documentData.status === "low-content"),
405
411
  fallback
406
412
  });
407
- const [pdfBlob, setPdfBlob] = React.useState(null);
408
- React.useEffect(() => setPdfBlob(null), [documentId]);
409
- React.useEffect(() => {
410
- if (pdf.data) setPdfBlob(pdf.data);
411
- }, [pdf.data]);
413
+ const pdfReady = !isDocx || snapshot || ["completed", "low-content"].includes(documentData?.status || "");
414
+ const pdfBlob = pdfReady && !pdf.isPlaceholderData ? pdf.data ?? null : null;
415
+ const pdfVerified = !!pdfBlob && !offlineCopies.has(pdfBlob);
412
416
  React.useEffect(() => {
413
417
  if (!isWebmFile || !pdfBlob) return;
414
418
  let cancelled = false;
@@ -433,6 +437,8 @@ function useViewerBlobs(documentId, doc) {
433
437
  }, [client, saveFile, notify, documentId, documentData?.file_name]);
434
438
  return {
435
439
  pdfBlob,
440
+ pdfVerified,
441
+ retryPdf: pdf.refetch,
436
442
  isPdfLoading: pdf.isLoading,
437
443
  pdfError: pdf.error,
438
444
  xlsxBlob: xlsx.data ?? null,
@@ -444,6 +450,8 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
444
450
  const {
445
451
  documentData,
446
452
  isArtifact,
453
+ isDraft,
454
+ isStreaming,
447
455
  isDocx,
448
456
  isXlsx,
449
457
  isEmail,
@@ -548,6 +556,14 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
548
556
  tooltip: liveKind ? "Code" : "Editor",
549
557
  label: tabLabel("edit", liveKind ? "Code" : "Document")
550
558
  },
559
+ ...!liveKind && !isDraft && !isStreaming && isDocx ? [
560
+ {
561
+ id: "pdf",
562
+ icon: /* @__PURE__ */ jsxRuntime.jsx(react.PdfIcon, { size: 20 }),
563
+ tooltip: "PDF",
564
+ label: tabLabel("pdf", "PDF")
565
+ }
566
+ ] : [],
551
567
  versionsTab
552
568
  ] : [
553
569
  ...isDocx ? [
@@ -611,6 +627,39 @@ function useViewerVersions(docId) {
611
627
  }, [documents, plainId]);
612
628
  return { versions, translations };
613
629
  }
630
+ function VersionDropdown({
631
+ versions,
632
+ activeId,
633
+ isSnapshot,
634
+ onOpen,
635
+ onHistory
636
+ }) {
637
+ const active = versions.find((version) => version.id === activeId);
638
+ const pendingVersion = activeId?.match(/@v([1-9]\d*)$/)?.[1];
639
+ return /* @__PURE__ */ jsxRuntime.jsxs(
640
+ "select",
641
+ {
642
+ "aria-label": "Active document version",
643
+ "data-testid": "document-version-dropdown",
644
+ className: "max-w-44 rounded border border-input bg-background px-2 py-1 text-sm",
645
+ value: active?.id ?? "",
646
+ onChange: (event) => {
647
+ const id = event.currentTarget.value;
648
+ if (id === "__history") onHistory();
649
+ else if (versions.some((version) => version.id === id)) onOpen(id);
650
+ },
651
+ children: [
652
+ !active && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: pendingVersion ? `v${pendingVersion} \xB7 ${isSnapshot ? "Read only" : "Current"}` : "Version unavailable" }),
653
+ [...versions].sort((a, b) => b.number - a.number).map((version) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: version.id, children: [
654
+ "v",
655
+ version.number,
656
+ version.isCurrent ? " \xB7 Current" : " \xB7 Read only"
657
+ ] }, version.id)),
658
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "__history", children: "Version history\u2026" })
659
+ ]
660
+ }
661
+ );
662
+ }
614
663
 
615
664
  // src/connection/viewer/parsed/document-tags.ts
616
665
  function isDocumentTag(tag) {
@@ -1785,9 +1834,12 @@ function ViewerPdfPane({
1785
1834
  }
1786
1835
  const loadingLabel = isVideo ? "Loading video..." : isAudio ? "Loading audio..." : isImage ? "Loading image..." : !documentData ? "Loading document..." : ui.friendlyFileType(documentData.file_type, documentData.file_name) === "Text" ? "Loading text..." : "Loading PDF...";
1787
1836
  const errorLabel = isVideo ? "Failed to load video" : isAudio ? "Failed to load audio" : isImage ? "Failed to load image" : "Failed to load PDF";
1788
- if (isDocx && documentData && !["completed", "low-content", "failed"].includes(documentData.status || "")) {
1837
+ if (isDocx && !pdfSnapshotNumber && documentData && !["completed", "low-content", "failed"].includes(documentData.status || "")) {
1789
1838
  return /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.ViewerMessage, { children: "PDF and search indexing are processing. Open the DOCX tab to edit now." });
1790
1839
  }
1840
+ if (isDocx && !pdfSnapshotNumber && documentData?.status === "failed") {
1841
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.ViewerMessage, { children: "PDF conversion failed. Open the Word editor or download the document." });
1842
+ }
1791
1843
  if (isPdfLoading) return /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.ViewerMessage, { children: loadingLabel });
1792
1844
  if (pdfError) {
1793
1845
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1879,12 +1931,12 @@ function ViewerPdfPane({
1879
1931
  return /* @__PURE__ */ jsxRuntime.jsx(SessionPdfViewer, { ...viewerProps, file: pdfBlob });
1880
1932
  }
1881
1933
  var StreamedWordArtifact = React.lazy(
1882
- () => import('./ConnectedStreamedWordArtifact-2RTCHVPI.cjs').then((m) => ({
1934
+ () => import('./ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs').then((m) => ({
1883
1935
  default: m.ConnectedStreamedWordArtifact
1884
1936
  }))
1885
1937
  );
1886
1938
  var NativeDocxComparison = React.lazy(
1887
- () => import('./ConnectedNativeDocxComparison-YXMYJWXY.cjs').then((m) => ({
1939
+ () => import('./ConnectedNativeDocxComparison-546ILGLW.cjs').then((m) => ({
1888
1940
  default: m.ConnectedNativeDocxComparison
1889
1941
  }))
1890
1942
  );
@@ -1987,10 +2039,15 @@ function DocumentViewerContent({
1987
2039
  const threadTitle = (id) => conversations.find((c) => c.external_id === id)?.title?.trim() || "Its thread";
1988
2040
  const madeInId = documentData?.conversation_ext_id ?? null;
1989
2041
  const madeIn = madeInId ? { id: madeInId, title: threadTitle(madeInId) } : null;
1990
- const pdfSnapshotId = snapshotDocumentId && !isDocx && !isArtifact ? snapshotDocumentId : null;
2042
+ const pdfSnapshotId = snapshotDocumentId && (!isArtifact || isDocx) ? snapshotDocumentId : null;
1991
2043
  const shownDocumentId = pdfSnapshotId || documentId;
1992
2044
  const blobs = useViewerBlobs(shownDocumentId, doc);
1993
- const { pdfBlob, xlsxBlob, xlsxError, handleDirectDownload } = blobs;
2045
+ const [minimumPdfVersion, setMinimumPdfVersion] = React.useState(null);
2046
+ React.useEffect(() => setMinimumPdfVersion(null), [documentId]);
2047
+ const versionReady = !!pdfSnapshotId || minimumPdfVersion === null || (documentData?.current_version ?? 0) >= minimumPdfVersion;
2048
+ const { xlsxBlob, xlsxError, handleDirectDownload } = blobs;
2049
+ const pdfBlob = versionReady ? blobs.pdfBlob : null;
2050
+ const pdfVerified = !!pdfBlob && blobs.pdfVerified !== false;
1994
2051
  const [annotating, setAnnotating] = React.useState(false);
1995
2052
  const [sharingFile, setSharingFile] = React.useState(false);
1996
2053
  React.useEffect(() => setAnnotating(false), [documentId]);
@@ -1998,7 +2055,52 @@ function DocumentViewerContent({
1998
2055
  null
1999
2056
  );
2000
2057
  const hasHistory = versions.length > 1 || (documentData?.current_version ?? 1) > 1 || translations.length > 0;
2001
- const { activeTab, handleTabChange, viewerTabs } = useViewerTabs(doc, isCompact, hasHistory);
2058
+ const {
2059
+ activeTab,
2060
+ handleTabChange: changeTab,
2061
+ viewerTabs
2062
+ } = useViewerTabs(doc, isCompact, hasHistory);
2063
+ const saveWordRef = React.useRef(null);
2064
+ const transitionPending = React.useRef(false);
2065
+ const transitionKey = JSON.stringify([openedId, doc.workspaceId]);
2066
+ const transitionScope = React.useRef({ key: transitionKey, generation: 0 });
2067
+ if (transitionScope.current.key !== transitionKey) {
2068
+ transitionScope.current = {
2069
+ key: transitionKey,
2070
+ generation: transitionScope.current.generation + 1
2071
+ };
2072
+ }
2073
+ React.useEffect(
2074
+ () => () => {
2075
+ transitionScope.current.generation += 1;
2076
+ },
2077
+ []
2078
+ );
2079
+ const requestViewerTransition = async (transition) => {
2080
+ if (transitionPending.current) return false;
2081
+ const leavingWord = isDocx && !isDraft && !isStreaming && !snapshotDocumentId && (activeTab === "docx" || isArtifact && !liveKind && activeTab === "edit");
2082
+ if (leavingWord) {
2083
+ transitionPending.current = true;
2084
+ const generation = transitionScope.current.generation;
2085
+ try {
2086
+ const saved = saveWordRef.current && await saveWordRef.current();
2087
+ if (!saved) {
2088
+ notify("Could not save the current document. Stay in the editor and try again.", "error");
2089
+ return false;
2090
+ }
2091
+ if (generation !== transitionScope.current.generation) return false;
2092
+ if (typeof saved === "number") setMinimumPdfVersion(saved);
2093
+ } finally {
2094
+ transitionPending.current = false;
2095
+ }
2096
+ }
2097
+ transition();
2098
+ return true;
2099
+ };
2100
+ const handleTabChange = (tab) => {
2101
+ if (tab === activeTab) return;
2102
+ void requestViewerTransition(() => changeTab(tab));
2103
+ };
2002
2104
  const crop = useImageCrop(
2003
2105
  documentId,
2004
2106
  documentData?.file_name,
@@ -2008,15 +2110,31 @@ function DocumentViewerContent({
2008
2110
  const [placingSignature, setPlacingSignature] = React.useState(false);
2009
2111
  const [signAppearance, setSignAppearance] = React.useState();
2010
2112
  const [isSignOpen, setIsSignOpen] = React.useState(false);
2011
- React.useEffect(() => setPlacingSignature(false), [documentId, snapshotDocumentId]);
2113
+ const signingScope = JSON.stringify([
2114
+ documentId,
2115
+ snapshotDocumentId,
2116
+ documentData?.current_version
2117
+ ]);
2118
+ const signingScopeRef = React.useRef(signingScope);
2119
+ const signingScopeMatches = signingScopeRef.current === signingScope;
2120
+ React.useEffect(() => {
2121
+ setPlacingSignature(false);
2122
+ setIsSignOpen(false);
2123
+ setSignAppearance(void 0);
2124
+ signingScopeRef.current = signingScope;
2125
+ }, [signingScope]);
2012
2126
  const [signatureFlow, setSignatureFlow] = React.useState(null);
2013
- React.useEffect(() => setSignatureFlow(null), [documentId, snapshotDocumentId]);
2014
- const { data: signatureStatus } = documentTools.useDocumentSignatures(shownDocumentId, !isDraft && !liveKind);
2127
+ React.useEffect(() => setSignatureFlow(null), [signingScope]);
2128
+ const signatureDocumentId = pdfSnapshotId || (documentData?.current_version ? `${documentId}@v${documentData.current_version}` : documentId);
2129
+ const { data: signatureStatus } = documentTools.useDocumentSignatures(
2130
+ signatureDocumentId,
2131
+ !isDraft && !liveKind
2132
+ );
2015
2133
  const isCoEditing = !snapshotDocumentId && !compareDocumentId && !isDraft && (activeTab === "docx" && isDocx || activeTab === "edit" && isArtifact && !liveKind && !isStreaming);
2016
2134
  const currentVersionLabel = isCoEditing ? void 0 : !snapshotDocumentId && !compareDocumentId && (isDocx || isArtifact && !liveKind) ? "Live" : artifacts.versionLabel(versions, snapshotDocumentId || documentId);
2017
2135
  const compareVersionLabel = artifacts.versionLabel(versions, compareDocumentId);
2018
2136
  const snapshotNumber = artifacts.findVersion(versions, snapshotDocumentId)?.number;
2019
- const pdfSnapshotNumber = pdfSnapshotId ? snapshotNumber : void 0;
2137
+ const pdfSnapshotNumber = pdfSnapshotId ? artifacts.parseVersionRef(pdfSnapshotId).version ?? void 0 : void 0;
2020
2138
  const isSigned = !!signatureStatus?.signed;
2021
2139
  const markup = documentTools.useDocumentMarkup(documentData, pdfSnapshotNumber, isSigned);
2022
2140
  React.useEffect(() => {
@@ -2096,12 +2214,37 @@ function DocumentViewerContent({
2096
2214
  // A draft's kind replaces the tabs: neither Versions nor the text view means anything
2097
2215
  // before the first save.
2098
2216
  /* @__PURE__ */ jsxRuntime.jsx(ViewerDraftKind, { documentId })
2099
- ) : /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.ViewerTabBar, { tabs: viewerTabs, activeId: activeTab, onChange: handleTabChange }),
2217
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2218
+ /* @__PURE__ */ jsxRuntime.jsx(
2219
+ chunkNNUK5ZM7_cjs.ViewerTabBar,
2220
+ {
2221
+ tabs: viewerTabs.filter((tab) => tab.id !== "versions"),
2222
+ activeId: activeTab,
2223
+ onChange: handleTabChange
2224
+ }
2225
+ ),
2226
+ (isArtifact || isDocx || hasHistory) && !liveKind && !isComparing && /* @__PURE__ */ jsxRuntime.jsx(
2227
+ VersionDropdown,
2228
+ {
2229
+ versions,
2230
+ activeId: snapshotDocumentId ?? (currentVersionId === documentId && documentData?.current_version ? `${documentId}@v${documentData.current_version}` : currentVersionId),
2231
+ isSnapshot: !!snapshotDocumentId,
2232
+ onOpen: (id) => {
2233
+ void requestViewerTransition(() => {
2234
+ setSnapshotDocumentId(id === currentVersionId ? null : id);
2235
+ if (activeTab === "versions")
2236
+ setActiveTab(isArtifact ? "edit" : isDocx ? "docx" : "pdf");
2237
+ });
2238
+ },
2239
+ onHistory: () => handleTabChange("versions")
2240
+ }
2241
+ )
2242
+ ] }),
2100
2243
  !isCompact && titleBlock
2101
2244
  ] });
2102
2245
  const annotatable = documentTools.canAnnotate({
2103
2246
  activeTab,
2104
- hasPdf: !!pdfBlob,
2247
+ hasPdf: pdfVerified,
2105
2248
  isImage,
2106
2249
  isVideo,
2107
2250
  isAudio,
@@ -2117,14 +2260,18 @@ function DocumentViewerContent({
2117
2260
  documentId,
2118
2261
  hidden: !!signatureFlow,
2119
2262
  onSign: (request) => {
2120
- setAnnotating(false);
2121
- setPlacingSignature(false);
2122
- if (activeTab !== "pdf") handleTabChange("pdf");
2123
- setSignatureFlow({ kind: "sign", request });
2263
+ void requestViewerTransition(() => {
2264
+ setAnnotating(false);
2265
+ setPlacingSignature(false);
2266
+ if (activeTab !== "pdf") changeTab("pdf");
2267
+ setSignatureFlow({ kind: "sign", request });
2268
+ });
2124
2269
  },
2125
2270
  onEditDraft: (draft) => {
2126
- if (activeTab !== "pdf") handleTabChange("pdf");
2127
- setSignatureFlow({ kind: "prepare", draft });
2271
+ void requestViewerTransition(() => {
2272
+ if (activeTab !== "pdf") changeTab("pdf");
2273
+ setSignatureFlow({ kind: "prepare", draft });
2274
+ });
2128
2275
  }
2129
2276
  }
2130
2277
  );
@@ -2361,7 +2508,7 @@ function DocumentViewerContent({
2361
2508
  ] })
2362
2509
  ] })
2363
2510
  ] }),
2364
- isSignOpen && pdfBlob && /* @__PURE__ */ jsxRuntime.jsx(
2511
+ isSignOpen && pdfBlob && pdfVerified && signingScopeMatches && /* @__PURE__ */ jsxRuntime.jsx(
2365
2512
  chunkJH6JTI76_cjs.SignDocumentDialog,
2366
2513
  {
2367
2514
  open: isSignOpen,
@@ -2436,9 +2583,14 @@ function DocumentViewerContent({
2436
2583
  }
2437
2584
  ) }),
2438
2585
  isCaptureDraft && /* @__PURE__ */ jsxRuntime.jsx(ViewerCaptureDraft, { documentId }),
2439
- !isCaptureDraft && (activeTab === "pdf" || isMedia && activeTab === "html") && !isArtifact && !isComparing && /* @__PURE__ */ jsxRuntime.jsxs(chunkDTMBAFIL_cjs.ViewerPane, { hidden: activeTab !== "pdf", children: [
2586
+ !isCaptureDraft && (activeTab === "pdf" || isMedia && activeTab === "html") && (!isArtifact || isDocx && !isDraft && !isStreaming && !liveKind) && !isComparing && /* @__PURE__ */ jsxRuntime.jsxs(chunkDTMBAFIL_cjs.ViewerPane, { hidden: activeTab !== "pdf", children: [
2440
2587
  /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.DocumentLabelBar, { summaries: labelSummaries }),
2441
2588
  !isMedia && !isImage && signatureBanner,
2589
+ activeTab === "pdf" && pdfBlob && !pdfVerified && /* @__PURE__ */ jsxRuntime.jsxs(chunkNNUK5ZM7_cjs.ViewerMessage, { children: [
2590
+ "Offline copy: its version cannot be verified. Reconnect before signing.",
2591
+ " ",
2592
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => void blobs.retryPdf(), className: "underline", children: "Retry loading the current PDF" })
2593
+ ] }),
2442
2594
  activeTab === "pdf" && !isMedia && !isImage && /* @__PURE__ */ jsxRuntime.jsx(
2443
2595
  chunkYYPZOEED_cjs.MarkupNotices,
2444
2596
  {
@@ -2453,14 +2605,14 @@ function DocumentViewerContent({
2453
2605
  documentId,
2454
2606
  doc,
2455
2607
  pdfBlob,
2456
- isPdfLoading: blobs.isPdfLoading,
2608
+ isPdfLoading: !versionReady || blobs.isPdfLoading,
2457
2609
  pdfError: blobs.pdfError,
2458
2610
  onDownload: () => void handleDirectDownload(),
2459
2611
  viewerProps,
2460
- signatureFlow,
2612
+ signatureFlow: pdfVerified && signingScopeMatches ? signatureFlow : null,
2461
2613
  onSignatureFlow: setSignatureFlow,
2462
2614
  currentUserId,
2463
- placingSignature,
2615
+ placingSignature: pdfVerified && signingScopeMatches && placingSignature,
2464
2616
  onPlacingDone: (appearance) => {
2465
2617
  setPlacingSignature(false);
2466
2618
  if (!appearance) return;
@@ -2489,12 +2641,13 @@ function DocumentViewerContent({
2489
2641
  activeTab === "edit" && isArtifact && !liveKind && !isStreaming && !isComparing && /* @__PURE__ */ jsxRuntime.jsxs(React.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(chunkNNUK5ZM7_cjs.ViewerMessage, { children: "Loading editor\u2026" }), children: [
2490
2642
  isSigned && !snapshotDocumentId && /* @__PURE__ */ jsxRuntime.jsx(chunkYYPZOEED_cjs.SignedEditNote, {}),
2491
2643
  /* @__PURE__ */ jsxRuntime.jsx(
2492
- chunkX5LANJDZ_cjs.ConnectedNativeDocxEditor,
2644
+ chunkVGCTYTEW_cjs.ConnectedNativeDocxEditor,
2493
2645
  {
2494
2646
  documentId: snapshotDocumentId || documentId,
2495
2647
  title: documentTitle,
2496
2648
  draftContent: isDraft ? draftDoc?.content || "" : void 0,
2497
2649
  snapshot: !!snapshotDocumentId,
2650
+ saveRef: saveWordRef,
2498
2651
  onSaved: (id) => {
2499
2652
  if (!isDraft) return;
2500
2653
  session.clearDraftDocument(documentId);
@@ -2534,11 +2687,12 @@ function DocumentViewerContent({
2534
2687
  signatureBanner,
2535
2688
  isSigned && !snapshotDocumentId && /* @__PURE__ */ jsxRuntime.jsx(chunkYYPZOEED_cjs.SignedEditNote, {}),
2536
2689
  /* @__PURE__ */ jsxRuntime.jsx(
2537
- chunkX5LANJDZ_cjs.ConnectedNativeDocxEditor,
2690
+ chunkVGCTYTEW_cjs.ConnectedNativeDocxEditor,
2538
2691
  {
2539
2692
  documentId: snapshotDocumentId || documentId,
2540
2693
  title: documentTitle,
2541
- snapshot: !!snapshotDocumentId
2694
+ snapshot: !!snapshotDocumentId,
2695
+ saveRef: saveWordRef
2542
2696
  },
2543
2697
  `${snapshotDocumentId || documentId}-${snapshotDocumentId ? "snapshot" : "live"}`
2544
2698
  )
@@ -2569,5 +2723,5 @@ function DocumentViewerContent({
2569
2723
  }
2570
2724
 
2571
2725
  exports.ConnectedDocumentViewer = ConnectedDocumentViewer;
2572
- //# sourceMappingURL=chunk-A3T3IC3K.cjs.map
2573
- //# sourceMappingURL=chunk-A3T3IC3K.cjs.map
2726
+ //# sourceMappingURL=chunk-SB4M3ITT.cjs.map
2727
+ //# sourceMappingURL=chunk-SB4M3ITT.cjs.map