@arbidocs/blocks 0.5.114 → 0.5.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConnectedCallDock-2KXEQENS.cjs → ConnectedCallDock-WER7R222.cjs} +21 -21
- package/dist/{ConnectedCallDock-2KXEQENS.cjs.map → ConnectedCallDock-WER7R222.cjs.map} +1 -1
- package/dist/{ConnectedCallRoom-MU3NPNXF.cjs → ConnectedCallRoom-T7OBQTYP.cjs} +14 -14
- package/dist/{ConnectedCallRoom-MU3NPNXF.cjs.map → ConnectedCallRoom-T7OBQTYP.cjs.map} +1 -1
- package/dist/{ConnectedNativeDocxComparison-VH3I65H6.cjs → ConnectedNativeDocxComparison-546ILGLW.cjs} +19 -19
- package/dist/{ConnectedNativeDocxComparison-VH3I65H6.cjs.map → ConnectedNativeDocxComparison-546ILGLW.cjs.map} +1 -1
- package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs → ConnectedProductionSetDialog-LHB4VQWC.cjs} +3 -3
- package/dist/{ConnectedProductionSetDialog-4EAY6KAZ.cjs.map → ConnectedProductionSetDialog-LHB4VQWC.cjs.map} +1 -1
- package/dist/{ConnectedStreamedWordArtifact-KQSHCA75.cjs → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs} +19 -19
- package/dist/{ConnectedStreamedWordArtifact-KQSHCA75.cjs.map → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs.map} +1 -1
- package/dist/{DocumentReviewCard-OCPFVMLD.cjs → DocumentReviewCard-ZSBZBGFK.cjs} +15 -15
- package/dist/{DocumentReviewCard-OCPFVMLD.cjs.map → DocumentReviewCard-ZSBZBGFK.cjs.map} +1 -1
- package/dist/{FilesViewerDialog-BAGOEMXW.cjs → FilesViewerDialog-6UKR5WEF.cjs} +44 -44
- package/dist/{FilesViewerDialog-BAGOEMXW.cjs.map → FilesViewerDialog-6UKR5WEF.cjs.map} +1 -1
- package/dist/{NativeDocxEditor-EJEIJDOC.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
- package/dist/{NativeDocxEditor-EJEIJDOC.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
- package/dist/{WorkspaceTableView-IMAZICIZ.cjs → WorkspaceTableView-J3C6VH4T.cjs} +8 -8
- package/dist/{WorkspaceTableView-IMAZICIZ.cjs.map → WorkspaceTableView-J3C6VH4T.cjs.map} +1 -1
- package/dist/agents/index.cjs +297 -297
- package/dist/{ai-7U4B4CVF.cjs → ai-IM4A23YT.cjs} +24 -24
- package/dist/ai-IM4A23YT.cjs.map +1 -0
- package/dist/calls/index.cjs +121 -121
- package/dist/chat/DraftingDocChip.d.ts +3 -1
- package/dist/chat/DraftingDocChip.js +7 -4
- package/dist/chat/DraftingDocChip.js.map +2 -2
- package/dist/chat/index.cjs +37 -37
- package/dist/{chunk-4ED7CNOX.cjs → chunk-2CSLFAGF.cjs} +430 -150
- package/dist/chunk-2CSLFAGF.cjs.map +1 -0
- package/dist/{chunk-Q6DQGGP4.cjs → chunk-325GVZE6.cjs} +3 -3
- package/dist/{chunk-Q6DQGGP4.cjs.map → chunk-325GVZE6.cjs.map} +1 -1
- package/dist/{chunk-LFRNBT2I.cjs → chunk-557MJ4IH.cjs} +20 -20
- package/dist/{chunk-LFRNBT2I.cjs.map → chunk-557MJ4IH.cjs.map} +1 -1
- package/dist/{chunk-JSQQV23D.cjs → chunk-6UTKM5AB.cjs} +3 -3
- package/dist/{chunk-JSQQV23D.cjs.map → chunk-6UTKM5AB.cjs.map} +1 -1
- package/dist/{chunk-H5OLHP2U.cjs → chunk-7OPOPYV6.cjs} +3 -3
- package/dist/{chunk-H5OLHP2U.cjs.map → chunk-7OPOPYV6.cjs.map} +1 -1
- package/dist/{chunk-AHT6DQNI.cjs → chunk-B2HNNG25.cjs} +50 -50
- package/dist/{chunk-AHT6DQNI.cjs.map → chunk-B2HNNG25.cjs.map} +1 -1
- package/dist/{chunk-WW6LXQY6.cjs → chunk-B3LZITVF.cjs} +12 -12
- package/dist/{chunk-WW6LXQY6.cjs.map → chunk-B3LZITVF.cjs.map} +1 -1
- package/dist/{chunk-V5IMYLYK.cjs → chunk-BQ5RIWWT.cjs} +3 -3
- package/dist/{chunk-V5IMYLYK.cjs.map → chunk-BQ5RIWWT.cjs.map} +1 -1
- package/dist/{chunk-INEPPS4H.cjs → chunk-COD5ENHK.cjs} +4 -4
- package/dist/{chunk-INEPPS4H.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
- package/dist/{chunk-MC4F2URI.cjs → chunk-CPG7II4E.cjs} +28 -28
- package/dist/{chunk-MC4F2URI.cjs.map → chunk-CPG7II4E.cjs.map} +1 -1
- package/dist/{chunk-7XT5B2DZ.cjs → chunk-CPR6EHG7.cjs} +47 -47
- package/dist/{chunk-7XT5B2DZ.cjs.map → chunk-CPR6EHG7.cjs.map} +1 -1
- package/dist/{chunk-3U36VYMD.cjs → chunk-DDIW4HLU.cjs} +27 -27
- package/dist/{chunk-3U36VYMD.cjs.map → chunk-DDIW4HLU.cjs.map} +1 -1
- package/dist/chunk-HB2O4THB.cjs +18 -0
- package/dist/{chunk-ZZA756I4.cjs.map → chunk-HB2O4THB.cjs.map} +1 -1
- package/dist/{chunk-IFOGBMAE.cjs → chunk-KLMNCBLY.cjs} +9 -6
- package/dist/chunk-KLMNCBLY.cjs.map +1 -0
- package/dist/{chunk-TDN33HSK.cjs → chunk-KTQOGT2L.cjs} +6 -6
- package/dist/{chunk-TDN33HSK.cjs.map → chunk-KTQOGT2L.cjs.map} +1 -1
- package/dist/{chunk-UUENH4BJ.cjs → chunk-KXIRVKCJ.cjs} +3 -3
- package/dist/{chunk-UUENH4BJ.cjs.map → chunk-KXIRVKCJ.cjs.map} +1 -1
- package/dist/{chunk-436I7PQL.cjs → chunk-NIE3N6OM.cjs} +9 -9
- package/dist/{chunk-436I7PQL.cjs.map → chunk-NIE3N6OM.cjs.map} +1 -1
- package/dist/{chunk-XKDUPU7B.cjs → chunk-NJCK6V6U.cjs} +4 -4
- package/dist/{chunk-XKDUPU7B.cjs.map → chunk-NJCK6V6U.cjs.map} +1 -1
- package/dist/{chunk-5QUL5BZO.cjs → chunk-NNUK5ZM7.cjs} +4 -4
- package/dist/{chunk-5QUL5BZO.cjs.map → chunk-NNUK5ZM7.cjs.map} +1 -1
- package/dist/{chunk-4NPCDS2X.cjs → chunk-NY3YUCOW.cjs} +3 -3
- package/dist/{chunk-4NPCDS2X.cjs.map → chunk-NY3YUCOW.cjs.map} +1 -1
- package/dist/{chunk-6DCIZA3X.cjs → chunk-OEREKAAP.cjs} +75 -75
- package/dist/{chunk-6DCIZA3X.cjs.map → chunk-OEREKAAP.cjs.map} +1 -1
- package/dist/{chunk-3ODEWSRO.cjs → chunk-P77YTTJ3.cjs} +4 -4
- package/dist/{chunk-3ODEWSRO.cjs.map → chunk-P77YTTJ3.cjs.map} +1 -1
- package/dist/{chunk-3R6YHJ3G.cjs → chunk-QHOHDNBU.cjs} +6 -6
- package/dist/{chunk-3R6YHJ3G.cjs.map → chunk-QHOHDNBU.cjs.map} +1 -1
- package/dist/{chunk-LYTIQQQ2.cjs → chunk-R7CJEIA5.cjs} +3 -3
- package/dist/{chunk-LYTIQQQ2.cjs.map → chunk-R7CJEIA5.cjs.map} +1 -1
- package/dist/{chunk-MGQSLMTC.cjs → chunk-SB4M3ITT.cjs} +239 -85
- package/dist/chunk-SB4M3ITT.cjs.map +1 -0
- package/dist/{chunk-2W5E62EY.cjs → chunk-SGYSDABK.cjs} +6 -6
- package/dist/{chunk-2W5E62EY.cjs.map → chunk-SGYSDABK.cjs.map} +1 -1
- package/dist/{chunk-UNDQYTRF.cjs → chunk-T23UTIRI.cjs} +6 -6
- package/dist/{chunk-UNDQYTRF.cjs.map → chunk-T23UTIRI.cjs.map} +1 -1
- package/dist/{chunk-E4BLRF2L.cjs → chunk-TDO5UWXF.cjs} +5 -5
- package/dist/{chunk-E4BLRF2L.cjs.map → chunk-TDO5UWXF.cjs.map} +1 -1
- package/dist/{chunk-4IOYQLKG.cjs → chunk-TP5PGWIO.cjs} +3 -3
- package/dist/{chunk-4IOYQLKG.cjs.map → chunk-TP5PGWIO.cjs.map} +1 -1
- package/dist/{chunk-7X3FS5HQ.cjs → chunk-TT4IF52H.cjs} +35 -35
- package/dist/{chunk-7X3FS5HQ.cjs.map → chunk-TT4IF52H.cjs.map} +1 -1
- package/dist/{chunk-NHHEMBXQ.cjs → chunk-VGCTYTEW.cjs} +22 -14
- package/dist/chunk-VGCTYTEW.cjs.map +1 -0
- package/dist/{chunk-HM5L4SBC.cjs → chunk-VKH3BEZE.cjs} +3 -3
- package/dist/{chunk-HM5L4SBC.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
- package/dist/{chunk-GQXPNIRE.cjs → chunk-WAV762GP.cjs} +6 -6
- package/dist/{chunk-GQXPNIRE.cjs.map → chunk-WAV762GP.cjs.map} +1 -1
- package/dist/{chunk-MZ2KZXNU.cjs → chunk-WXUU3COI.cjs} +3 -3
- package/dist/{chunk-MZ2KZXNU.cjs.map → chunk-WXUU3COI.cjs.map} +1 -1
- package/dist/{chunk-BW5MF464.cjs → chunk-XKVPSOKP.cjs} +4 -4
- package/dist/{chunk-BW5MF464.cjs.map → chunk-XKVPSOKP.cjs.map} +1 -1
- package/dist/{chunk-57EE6CMW.cjs → chunk-Y24V6HPR.cjs} +15 -15
- package/dist/{chunk-57EE6CMW.cjs.map → chunk-Y24V6HPR.cjs.map} +1 -1
- package/dist/{chunk-ET3NVY27.cjs → chunk-YGBHY67W.cjs} +5 -5
- package/dist/{chunk-ET3NVY27.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
- package/dist/{chunk-7TEUGFIL.cjs → chunk-YGXOKB5Z.cjs} +4 -4
- package/dist/{chunk-7TEUGFIL.cjs.map → chunk-YGXOKB5Z.cjs.map} +1 -1
- package/dist/connect/docx.cjs +23 -23
- package/dist/connect/index.cjs +1231 -1069
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/viewer.cjs +33 -33
- package/dist/connection/conversation/ConnectedConversation.js +143 -55
- package/dist/connection/conversation/ConnectedConversation.js.map +2 -2
- package/dist/connection/conversation/ConversationSendButton.d.ts +1 -0
- package/dist/connection/conversation/ConversationSendButton.js +3 -2
- package/dist/connection/conversation/ConversationSendButton.js.map +2 -2
- package/dist/connection/conversation/DocumentTargetNotice.d.ts +7 -0
- package/dist/connection/conversation/DocumentTargetNotice.js +45 -0
- package/dist/connection/conversation/DocumentTargetNotice.js.map +7 -0
- package/dist/connection/conversation/documentSwitch.d.ts +9 -0
- package/dist/connection/conversation/documentSwitch.js +40 -0
- package/dist/connection/conversation/documentSwitch.js.map +7 -0
- package/dist/connection/docx/ConnectedNativeDocxEditor.js +10 -2
- package/dist/connection/docx/ConnectedNativeDocxEditor.js.map +2 -2
- package/dist/connection/viewer/ConnectedDocumentViewer.js +124 -21
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/VersionDropdown.d.ts +9 -0
- package/dist/connection/viewer/VersionDropdown.js +39 -0
- package/dist/connection/viewer/VersionDropdown.js.map +7 -0
- package/dist/connection/viewer/ViewerPdfPane.js +4 -1
- package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
- package/dist/connection/viewer/useViewerBlobs.d.ts +3 -1
- package/dist/connection/viewer/useViewerBlobs.js +14 -8
- package/dist/connection/viewer/useViewerBlobs.js.map +2 -2
- package/dist/connection/viewer/useViewerTabs.js +10 -0
- package/dist/connection/viewer/useViewerTabs.js.map +2 -2
- package/dist/dashboards/index.cjs +1 -1
- package/dist/docx/DocxCommandMenu.d.ts +8 -0
- package/dist/docx/DocxCommandMenu.js +202 -0
- package/dist/docx/DocxCommandMenu.js.map +7 -0
- package/dist/docx/NativeDocxEditor.d.ts +4 -2
- package/dist/docx/NativeDocxEditor.js +54 -13
- package/dist/docx/NativeDocxEditor.js.map +2 -2
- package/dist/docx/RibbonMenu.d.ts +3 -1
- package/dist/docx/RibbonMenu.js +10 -3
- package/dist/docx/RibbonMenu.js.map +2 -2
- package/dist/docx/RibbonOverflow.d.ts +3 -0
- package/dist/docx/RibbonOverflow.js +24 -1
- package/dist/docx/RibbonOverflow.js.map +2 -2
- package/dist/docx/index.cjs +38 -38
- package/dist/docx/signatures/SignatureFields.d.ts +5 -1
- package/dist/docx/signatures/SignatureFields.js +57 -10
- package/dist/docx/signatures/SignatureFields.js.map +2 -2
- package/dist/embed/index.cjs +38 -38
- package/dist/files/index.cjs +224 -224
- package/dist/index.cjs +1731 -1731
- package/dist/settings/index.cjs +147 -147
- package/dist/shell/index.cjs +90 -90
- package/dist/site/index.cjs +5 -5
- package/dist/studio/index.cjs +27 -27
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +54 -54
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/src/docx/styles.css +94 -0
- package/dist/ai-7U4B4CVF.cjs.map +0 -1
- package/dist/chunk-4ED7CNOX.cjs.map +0 -1
- package/dist/chunk-IFOGBMAE.cjs.map +0 -1
- package/dist/chunk-MGQSLMTC.cjs.map +0 -1
- package/dist/chunk-NHHEMBXQ.cjs.map +0 -1
- package/dist/chunk-ZZA756I4.cjs +0 -18
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/connection/viewer/ConnectedDocumentViewer.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * The whole document viewer on the signed-in session: a document (or one of its versions, read\n * only) as its PDF, its text, the Word editor, a sheet, an image, a recording or a live artifact;\n * its versions and comparisons; markup, signing and signature requests; sharing, Email, Translate\n * and Finalise. Runs under any host (`useConnectedWorkspace`): the open document, tab and comparison\n * are the session state's, navigation the `BlocksEnvironment`'s, and what only the host knows comes\n * as its host config's `viewer`.\n */\n\nimport { lazy, Suspense, useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport {\n ChevronDown,\n Languages,\n Mail,\n MessageSquare,\n MessageSquarePlus,\n PenLine,\n Users,\n} from 'lucide-react'\nimport {\n DEFAULT_ASPECT_OPTIONS,\n ImageCropModal,\n useArbi,\n useArbiSessionState,\n useArbiSessionStore,\n} from '@arbidocs/react'\nimport { findVersion, parseVersionRef, versionLabel } from '@arbidocs/react/artifacts'\nimport {\n SIGNED_LOCKED_REASON,\n canAnnotate,\n useDocumentMarkup,\n useDocumentSignatures,\n useDocumentTools,\n type SignatureAppearance,\n} from '@arbidocs/react/document-tools'\nimport { XlsxViewer, cycleZoom } from '@arbidocs/react/viewers'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n getEntityLabel,\n} from '@arbidocs/react/ui'\nimport {\n ArtifactCodeView,\n ArtifactCompareBar,\n ArtifactPreview,\n VersionTimeline,\n} from '../../artifacts'\nimport { latestThreadOfDocument, useRegisterOpenDocument } from '@arbidocs/react/shell'\nimport { ShareControl } from '../../collaboration/sharing/ShareControl'\nimport {\n ViewerCaptureDraft,\n ViewerDraftKind,\n ViewerDraftTitle,\n ViewerRelatedDocuments,\n} from './drafts'\nimport {\n AnnotateButton,\n DownloadMarkupButton,\n FileShareDialog,\n MarkupNotices,\n MarkupViewNote,\n PlaceMySignatureMenuItems,\n ShowOriginalButton,\n SignDocumentDialog,\n SignedEditNote,\n SignatureRequestBanner,\n SignatureStatus,\n VersionSnapshotBar,\n} from '../../document-tools'\nimport {\n DocumentLabelBar,\n PdfPageNav,\n ViewerControlBar,\n ViewerFrame,\n ViewerHeaderEnd,\n ViewerHeaderStart,\n ViewerImageActions,\n ViewerMessage,\n ViewerPageCounter,\n ViewerPane,\n ViewerStatusNote,\n ViewerTabBar,\n ViewerTitle,\n ViewerZoomControl,\n} from '../../files'\nimport { ErrorBoundary } from '../../components/ErrorBoundary'\nimport { fmtDate } from '../../lib/format'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { TabHeader } from '../../shell'\nimport { useConnectedWorkspace } from '../ConnectionProvider'\nimport { useConnectedConversations } from '../workspaceData'\nimport { ConnectedDocumentToolsProvider } from './ConnectedDocumentToolsProvider'\nimport { FinaliseTranslationButton } from './FinaliseTranslationButton'\nimport { useDocumentViewerSupport } from './support'\nimport { useImageCrop } from './useImageCrop'\nimport { useViewedDocument } from './useViewedDocument'\nimport { useViewerBlobs } from './useViewerBlobs'\nimport { useViewerTabs } from './useViewerTabs'\nimport { useViewerVersions } from './useViewerVersions'\nimport { ParsedTextView } from './parsed/ParsedTextView'\nimport { ViewerPdfPane, type SignatureFlow } from './ViewerPdfPane'\n// The Word editor itself is its own chunk (`docxEditorChunk`), loaded when a Word document shows.\nimport { ConnectedNativeDocxEditor as NativeDocxEditor } from '../docx/ConnectedNativeDocxEditor'\nimport { canChangeVisibility } from '../../files/permissions'\n\nconst StreamedWordArtifact = lazy(() =>\n import('../docx/ConnectedStreamedWordArtifact').then((m) => ({\n default: m.ConnectedStreamedWordArtifact,\n }))\n)\nconst NativeDocxComparison = lazy(() =>\n import('../docx/ConnectedNativeDocxComparison').then((m) => ({\n default: m.ConnectedNativeDocxComparison,\n }))\n)\n\nconst UPLOADED_NO_VERSIONS =\n 'No earlier versions yet. Replacing, editing or signing this file adds a new version here.'\n\nexport interface ConnectedDocumentViewerProps {\n /**\n * The document, or a version reference `doc-\u2026@v{n}` (a citation, a \"made from v2\" link): an\n * earlier version opens read-only. Default: the session state's viewing document.\n */\n documentId?: string\n /** Controls at the right end of the header (a panel's dock / pop-out switcher). */\n headerActions?: ReactNode\n /** Where html/react artifacts load their sandbox runtime from. */\n artifactRuntimeUrl?: string\n}\n\nexport function ConnectedDocumentViewer(props: ConnectedDocumentViewerProps) {\n const viewing = useArbiSessionState((s) => s.viewingDocument?.id)\n const openedId = props.documentId ?? viewing\n if (!openedId) return null\n // A viewer that throws (a PDF the browser cannot render, say) shows the error here, in the\n // viewer's place, instead of unmounting the whole app.\n return (\n <ErrorBoundary\n resetKey={openedId}\n labels={{ title: \"This document couldn't be displayed\" }}\n testId=\"document-viewer-error\"\n >\n <ConnectedDocumentToolsProvider>\n <DocumentViewerContent {...props} openedId={openedId} />\n </ConnectedDocumentToolsProvider>\n </ErrorBoundary>\n )\n}\n\nfunction DocumentViewerContent({\n openedId,\n headerActions,\n artifactRuntimeUrl = '/artifact-runtime/',\n}: ConnectedDocumentViewerProps & { openedId: string }) {\n const arbi = useArbi()\n const session = useArbiSessionStore()\n const support = useDocumentViewerSupport()\n const formatDate = support.formatDate ?? fmtDate\n const tools = useDocumentTools()\n const { openConversation, openNewConversation, notify } = useBlocksEnvironment()\n const { userId: currentUserId } = useConnectedWorkspace()\n // A document keeps one id for its whole life; its versions are inside it.\n const documentId = parseVersionRef(openedId).docId\n const [totalPages, setTotalPages] = useState<number>(0)\n const [isCompact, setIsCompact] = useState(false)\n // Zoom of the PDF (canvas scale) / text, as a multiplier of fit width; pinch, double-tap and the\n // zoom button all drive it. The text view's size is a reading preference for every document.\n const [pdfZoom, setPdfZoom] = useState(1)\n const {\n tab: zoomTab,\n textScale,\n compareId: compareDocumentId,\n } = useArbiSessionState((s) => s.documentViewer)\n const zoom = zoomTab === 'html' ? textScale : pdfZoom\n const setZoom = useCallback(\n (next: number | ((z: number) => number)) => {\n const value = typeof next === 'function' ? next(zoom) : next\n if (zoomTab === 'html') session.setDocumentViewer({ textScale: value })\n else setPdfZoom(value)\n },\n [zoomTab, session, zoom]\n )\n const [scrollTrigger, setScrollTrigger] = useState(0) // Incremented to scroll the viewers\n const containerRef = useRef<HTMLDivElement>(null)\n\n const viewingDocumentPage = useArbiSessionState((s) => s.viewingDocument?.page ?? null)\n const setViewingDocumentPage = (page: number) =>\n session.setViewingDocument({ id: openedId, page })\n const setViewingDocumentId = (id: string) => session.setViewingDocument({ id })\n const setActiveTab = (tab: Parameters<typeof session.setDocumentViewer>[0]['tab']) =>\n session.setDocumentViewer({ tab })\n const setCompareDocumentId = (id: string | null) => session.setDocumentViewer({ compareId: id })\n const { data: conversations } = useConnectedConversations()\n\n // An earlier version opened read-only (`doc-\u2026@v{n}`) from the Versions tab, a citation or a\n // \"made from\" link. Word documents show it in the Word editor, artifacts in theirs, everything\n // else as its PDF. The version on screen is the session's viewing id, not local state: the\n // viewer remounts when its panel moves to a new window, and the version must come along.\n const snapshotRef = parseVersionRef(openedId).version ? openedId : null\n // Every version of the document, oldest first. Every version of an artifact shares one name, so\n // both sides of a comparison get the timeline's \"v1/v2/v3\" label.\n const { versions, translations } = useViewerVersions(documentId)\n const currentVersionId = versions.find((v) => v.isCurrent)?.id ?? documentId\n // Opening the current version is the live document itself, not a read-only copy of it.\n const snapshotDocumentId = snapshotRef && snapshotRef !== currentVersionId ? snapshotRef : null\n const doc = useViewedDocument(documentId)\n const setSnapshotDocumentId = (ref: string | null) => setViewingDocumentId(ref ?? documentId)\n // Drafting mode: a thread bound to the open document (or the one it was made in) drafts in it,\n // also while an earlier version of it is on screen; a turn sent then brings the live document\n // back, where the assistant's edits appear. Being open binds no chat to it.\n useRegisterOpenDocument({\n documentId: doc.savedDocumentId,\n shownId: openedId,\n showLive: () => setViewingDocumentId(documentId),\n workspaceId: doc.workspaceId,\n conversationId: doc.documentData?.conversation_ext_id ?? null,\n })\n const {\n documentData,\n streamingDoc,\n isStreaming,\n draftDoc,\n isDraft,\n isCaptureDraft,\n labelSummaries,\n isImage,\n isVideo,\n isAudio,\n isMedia,\n isArtifact,\n liveKind,\n liveSource,\n isDocx,\n isXlsx,\n isDownloadOnly,\n } = doc\n // The thread bound to this document: its latest one, else a new chat bound to it. The document\n // stays on screen beside it.\n const chatAboutDocument = () => {\n const savedId = doc.savedDocumentId\n if (!savedId) return\n const latest = latestThreadOfDocument(conversations, savedId)\n if (latest) {\n openConversation(latest, { keepDocumentOpen: true })\n return\n }\n // Opening a new chat starts it unbound; it is bound after.\n openNewConversation({ keepDocumentOpen: true })\n session.setNewChatDocumentId(savedId)\n }\n // A thread by its title, for the threads a document (and each version) was made in.\n const threadTitle = (id: string) =>\n conversations.find((c) => c.external_id === id)?.title?.trim() || 'Its thread'\n // The thread a generated document was made in (none for an upload).\n const madeInId = documentData?.conversation_ext_id ?? null\n const madeIn = madeInId ? { id: madeInId, title: threadTitle(madeInId) } : null\n const pdfSnapshotId = snapshotDocumentId && !isDocx && !isArtifact ? snapshotDocumentId : null\n // The document on screen: an earlier version when one is open, else the current one.\n const shownDocumentId = pdfSnapshotId || documentId\n const blobs = useViewerBlobs(shownDocumentId, doc)\n const { pdfBlob, xlsxBlob, xlsxError, handleDirectDownload } = blobs\n // Annotation mode for the PDF view; off for every newly opened document.\n const [annotating, setAnnotating] = useState(false)\n const [sharingFile, setSharingFile] = useState(false)\n useEffect(() => setAnnotating(false), [documentId])\n // My signature: one's saved signature or initials, to place as a picture stamp in the markup.\n const [placeMark, setPlaceMark] = useState<{ image: string; label: string; key: number } | null>(\n null\n )\n // Translations are listed with the versions (each is its own document), so they open the tab too.\n const hasHistory =\n versions.length > 1 || (documentData?.current_version ?? 1) > 1 || translations.length > 0\n const { activeTab, handleTabChange, viewerTabs } = useViewerTabs(doc, isCompact, hasHistory)\n const crop = useImageCrop(\n documentId,\n documentData?.file_name,\n pdfBlob,\n documentData?.workspace_ext_id\n )\n // Signing: choose where the signature goes (placing), then the Sign dialog.\n const [placingSignature, setPlacingSignature] = useState(false)\n const [signAppearance, setSignAppearance] = useState<SignatureAppearance | undefined>()\n const [isSignOpen, setIsSignOpen] = useState(false)\n // Leaving the placement when another version opens or returns: it belongs to the copy on screen.\n useEffect(() => setPlacingSignature(false), [documentId, snapshotDocumentId])\n // A signature request: the author placing fields ('prepare'), or a signer walked through theirs.\n const [signatureFlow, setSignatureFlow] = useState<SignatureFlow>(null)\n useEffect(() => setSignatureFlow(null), [documentId, snapshotDocumentId])\n const { data: signatureStatus } = useDocumentSignatures(shownDocumentId, !isDraft && !liveKind)\n\n // The Word editor on the current version: the editor's own ribbon says \"Co-edit mode\", so the\n // header carries no version label and, when narrow, no title row above the ribbon.\n const isCoEditing =\n !snapshotDocumentId &&\n !compareDocumentId &&\n !isDraft &&\n ((activeTab === 'docx' && isDocx) ||\n (activeTab === 'edit' && isArtifact && !liveKind && !isStreaming))\n const currentVersionLabel = isCoEditing\n ? undefined\n : !snapshotDocumentId && !compareDocumentId && (isDocx || (isArtifact && !liveKind))\n ? 'Live'\n : versionLabel(versions, snapshotDocumentId || documentId)\n const compareVersionLabel = versionLabel(versions, compareDocumentId)\n const snapshotNumber = findVersion(versions, snapshotDocumentId)?.number\n // The markup of the version on screen: the default view when it has any (\"Show original\" hides).\n const pdfSnapshotNumber = pdfSnapshotId ? snapshotNumber : undefined\n // A signed version is locked: only a further signature changes it. Its marks stay in the markup\n // layer (never in its PDF), and editing its content saves a new, unsigned version.\n const isSigned = !!signatureStatus?.signed\n const markup = useDocumentMarkup(documentData, pdfSnapshotNumber, isSigned)\n\n // Detect container width changes (640px = the sm: breakpoint).\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) setIsCompact(entry.contentRect.width < 640)\n })\n resizeObserver.observe(container)\n return () => resizeObserver.disconnect()\n }, [])\n\n const handleLoadSuccess = useCallback((numPages: number) => setTotalPages(numPages), [])\n\n // Go to a page: the counter, or one step from the arrows.\n const goToPage = (page: number) => {\n setViewingDocumentPage(page)\n setScrollTrigger((prev) => prev + 1)\n }\n const stepPage = (delta: number) => {\n const next = (viewingDocumentPage || 1) + delta\n if (next >= 1 && next <= totalPages) goToPage(next)\n }\n\n const documentTitle =\n streamingDoc?.title ||\n draftDoc?.title ||\n documentData?.doc_metadata?.title ||\n documentData?.file_name ||\n 'Document'\n\n // The page / zoom controls, shared by the PDF and the text view. They sit in the control bar\n // under the body, so they never cover the text being read.\n const pageNav = totalPages > 0 && (\n <>\n <ViewerZoomControl zoom={zoom} onCycle={() => setZoom(cycleZoom(zoom))} />\n <PdfPageNav\n canPrev={(viewingDocumentPage || 1) > 1}\n canNext={(viewingDocumentPage || 1) < totalPages}\n onPrev={() => stepPage(-1)}\n onNext={() => stepPage(1)}\n counter={\n <ViewerPageCounter page={viewingDocumentPage || 1} total={totalPages} onGoTo={goToPage} />\n }\n />\n </>\n )\n\n // Compare: a \"Compare vs. [doc]\" row of its own below the tab/title bar (a docked panel is\n // narrow), with the flip-direction arrow and the way out.\n const isComparing = !!compareDocumentId\n const compareTarget = compareDocumentId ? parseVersionRef(compareDocumentId).docId : null\n const compareIndicator = isComparing && compareTarget && (\n <ArtifactCompareBar\n compareTarget={support.renderDocumentPill?.(compareTarget) ?? compareTarget}\n versionLabel={compareVersionLabel}\n mode=\"flip\"\n showTrackChanges={false}\n onToggleTrackChanges={() => {}}\n onFlip={() => {\n setViewingDocumentId(compareDocumentId!)\n setCompareDocumentId(documentId)\n }}\n onStop={() => setCompareDocumentId(null)}\n />\n )\n\n // Document name block: the name, related documents and status notes. Roomy headers keep it on\n // the tab row; a narrow (phone / docked) header gives it a row of its own so the name is never\n // cut down to a couple of letters by the tabs and actions.\n const titleBlock = (\n <>\n {/* A draft gets an editable name + auto-name toggle instead of the plain read-only name. */}\n {isDraft ? (\n <ViewerDraftTitle documentId={documentId} />\n ) : (\n <ViewerTitle\n title={documentTitle}\n versionLabel={currentVersionLabel}\n shrink={!!liveKind || isCompact}\n />\n )}\n {/* The narrow header's Share is icon-only, so the state is spelled out here as text. */}\n {isCompact && !isDraft && documentData?.shared && (\n <ViewerStatusNote testId=\"document-shared-status\">\n Shared with the workspace\n </ViewerStatusNote>\n )}\n {/* Likewise \"Show original\" is a bare page icon there: say which view is on screen. */}\n {isCompact &&\n activeTab === 'pdf' &&\n pdfBlob &&\n markup.hasMarkup &&\n !annotating &&\n !placingSignature && (\n <MarkupViewNote\n showOriginal={markup.showOriginal}\n onToggle={() => markup.setShowOriginal((on) => !on)}\n />\n )}\n {/* Related documents, except during a comparison (its own row says which). */}\n {!isComparing && !liveKind && documentData && (\n <ViewerRelatedDocuments document={documentData} />\n )}\n {isStreaming && <ViewerStatusNote pulse>streaming...</ViewerStatusNote>}\n {/* Nothing is generating: this document simply does not exist on the backend yet. */}\n {isDraft && (\n <ViewerStatusNote testId=\"draft-unsaved-indicator\">Draft \u2014 not saved</ViewerStatusNote>\n )}\n {signatureStatus?.signed && (\n <SignatureStatus status={signatureStatus} formatDate={formatDate} />\n )}\n </>\n )\n\n const leftContent = (\n <ViewerHeaderStart>\n {isDraft ? (\n // A draft's kind replaces the tabs: neither Versions nor the text view means anything\n // before the first save.\n <ViewerDraftKind documentId={documentId} />\n ) : (\n <ViewerTabBar tabs={viewerTabs} activeId={activeTab} onChange={handleTabChange} />\n )}\n {!isCompact && titleBlock}\n </ViewerHeaderStart>\n )\n\n const annotatable = canAnnotate({\n activeTab,\n hasPdf: !!pdfBlob,\n isImage,\n isVideo,\n isAudio,\n isDownloadOnly,\n isDraft,\n isStreaming,\n isSnapshot: !!snapshotDocumentId,\n isComparing,\n })\n\n // A request waiting for this user's signature, or their own in flight: shown over the PDF and\n // the Word editor alike; signing happens on the PDF.\n const signatureBanner = !isDraft && !liveKind && !snapshotDocumentId && (\n <SignatureRequestBanner\n documentId={documentId}\n hidden={!!signatureFlow}\n onSign={(request) => {\n setAnnotating(false)\n setPlacingSignature(false)\n if (activeTab !== 'pdf') handleTabChange('pdf')\n setSignatureFlow({ kind: 'sign', request })\n }}\n onEditDraft={(draft) => {\n if (activeTab !== 'pdf') handleTabChange('pdf')\n setSignatureFlow({ kind: 'prepare', draft })\n }}\n />\n )\n\n const share = () => {\n const name = (liveKind ? documentTitle : documentData?.file_name) || undefined\n if (support.share) {\n support.share({ id: documentId, name, isPrivate: !documentData?.shared })\n return\n }\n void arbi.documents\n .update([{ external_id: documentId, shared: !documentData?.shared }])\n .then(() => tools.onDocumentsChanged?.([documentId], 'markup'))\n .catch(() => notify(\"Couldn't change who can see this document\", 'error'))\n }\n const shownRef = snapshotDocumentId || documentId\n\n const rightContent = (\n <ViewerHeaderEnd isCompact={isCompact}>\n {/* Annotate: only for a PDF on screen (text and Word files are shown as a PDF too). Marks\n sit in a layer beside the document; Freeze saves a separate copy with them built in. */}\n {annotatable && (\n <AnnotateButton\n active={annotating}\n compact={isCompact}\n onClick={() => {\n setPlacingSignature(false)\n markup.setShowOriginal(false)\n setAnnotating((on) => !on)\n }}\n />\n )}\n {/* The markup is the default view; \"Show original\" shows the untouched file. */}\n {activeTab === 'pdf' && pdfBlob && !placingSignature && (markup.hasMarkup || annotating) && (\n <ShowOriginalButton\n active={markup.showOriginal}\n compact={isCompact}\n onClick={() => {\n setAnnotating(false)\n markup.setShowOriginal((on) => !on)\n }}\n />\n )}\n {activeTab === 'pdf' && markup.hasMarkup && !annotating && (\n <DownloadMarkupButton\n onClick={() => void markup.downloadMarkup()}\n // A signed version is locked: Download serves the signed file as it is.\n disabledReason={isSigned ? SIGNED_LOCKED_REASON : undefined}\n />\n )}\n {/* Image actions: start a generation from this image, or crop it into a new document. */}\n {activeTab === 'pdf' && isImage && pdfBlob && (\n <ViewerImageActions\n compact={isCompact}\n onUseAsReference={\n support.useImageAsReference ? () => support.useImageAsReference!(documentId) : undefined\n }\n onCrop={crop.handleOpenCrop}\n />\n )}\n {/* The thread it was made in: open it at the answer that made it. */}\n {madeIn && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n onClick={() =>\n openConversation(madeIn.id, {\n messageId: documentData?.source_message_ext_id ?? undefined,\n })\n }\n title={`Open the thread it was made in: ${madeIn.title}`}\n aria-label={`Open the thread it was made in: ${madeIn.title}`}\n data-testid=\"document-open-thread\"\n >\n <MessageSquare className=\"size-4\" />\n {!isCompact && <span className=\"max-w-[10rem] truncate\">{madeIn.title}</span>}\n </Button>\n )}\n {documentId && documentData && !isDraft && !isStreaming && (\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setSharingFile(true)}\n data-testid=\"share-file-button\"\n >\n Share file\n </Button>\n <FileShareDialog\n open={sharingFile}\n onOpenChange={setSharingFile}\n documentId={documentId}\n version={pdfSnapshotNumber ?? documentData.current_version ?? 1}\n />\n </>\n )}\n {/* Chat about this document: the thread bound to it (its questions edit it), the latest one\n or a new one. Only such a thread drafts in a document: one merely open binds no chat. */}\n {doc.savedDocumentId && !snapshotDocumentId && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n onClick={chatAboutDocument}\n title=\"Chat about this document: a thread that works in it, with edits as tracked changes\"\n aria-label=\"Chat about this document\"\n data-testid=\"document-chat-about\"\n className=\"pointer-coarse:min-h-11\"\n >\n <MessageSquarePlus className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Chat</span>}\n </Button>\n )}\n {/* Share always asks first (the host's share dialog), so a click never changes who can see\n the file by surprise. */}\n {documentId && doc.workspaceId && (\n <ShareControl\n state={documentData?.shared ? 'shared' : 'private'}\n onToggle={share}\n disabled={!canChangeVisibility(documentData, currentUserId)}\n disabledTooltip=\"Only the owner can change visibility\"\n tooltip={\n documentData?.shared\n ? 'Shared with the workspace \u2014 click to share with specific people'\n : 'Share with the workspace, then optionally notify specific people by email'\n }\n variant=\"outline\"\n compact={isCompact}\n showState={!isCompact}\n labels={{\n shared: getEntityLabel('WORKSPACE'),\n private: 'Only you',\n mixed: 'Partly shared',\n }}\n testId=\"share-document-button\"\n stateTestId=\"document-title-shared-indicator\"\n />\n )}\n {/* Email: the host's mail composer with the document on screen attached. The divider keeps\n it apart from Share, which changes who can see the file rather than sending it. */}\n {tools.emailDocument && !isDraft && !isStreaming && documentData?.file_name && (\n <>\n <span className=\"mx-1 h-5 w-px bg-border\" aria-hidden=\"true\" />\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n title=\"Email this document\"\n aria-label=\"Email\"\n data-testid=\"email-document-button\"\n className=\"pointer-coarse:min-h-11\"\n onClick={() => tools.emailDocument?.(shownRef)}\n >\n <Mail className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Email</span>}\n </Button>\n </>\n )}\n {/* Translate: a new, editable document with the original and translation side by side. */}\n {support.translate &&\n !isDraft &&\n !isStreaming &&\n !liveKind &&\n !isImage &&\n documentData?.file_name && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n title=\"Translate into another language: a new editable document, original and translation side by side\"\n aria-label=\"Translate\"\n data-testid=\"translate-document-button\"\n className=\"pointer-coarse:min-h-11\"\n onClick={() => support.translate!(shownRef)}\n >\n <Languages className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Translate</span>}\n </Button>\n )}\n {/* Finalise (a translation): its current version saved as a new labelled PDF. */}\n {!isStreaming && !snapshotDocumentId && (\n <FinaliseTranslationButton document={documentData ?? undefined} isCompact={isCompact} />\n )}\n {/* Every signing action starts in one menu: sign yourself, save/place a mark, or request\n signatures from others. */}\n {annotatable && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant={\n placingSignature || signatureFlow?.kind === 'prepare' ? 'default' : 'outline'\n }\n size={isCompact ? 'icon' : 'sm'}\n aria-label=\"Sign\"\n title=\"Sign or request signatures\"\n data-testid=\"signing-menu-trigger\"\n className=\"pointer-coarse:min-h-11\"\n >\n <PenLine className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Sign</span>}\n <ChevronDown className=\"ml-1 size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" forceMount>\n <DropdownMenuItem\n data-testid=\"sign-document-button\"\n onSelect={() => {\n setAnnotating(false)\n if (isSigned) {\n setSignatureFlow(null)\n setPlacingSignature((on) => !on)\n } else {\n setPlacingSignature(false)\n setSignatureFlow({ kind: 'prepare', self: true })\n }\n }}\n >\n <PenLine className=\"mr-2 size-4\" /> Sign this document\n </DropdownMenuItem>\n {!isSigned && (\n <>\n <PlaceMySignatureMenuItems\n onPlace={(mark) => {\n setPlacingSignature(false)\n setSignatureFlow(null)\n markup.setShowOriginal(false)\n setAnnotating(true)\n setPlaceMark({ ...mark, key: Date.now() })\n }}\n />\n <DropdownMenuItem\n data-testid=\"request-signatures-button\"\n onSelect={() => {\n setAnnotating(false)\n setPlacingSignature(false)\n setSignatureFlow(signatureFlow?.kind === 'prepare' ? null : { kind: 'prepare' })\n }}\n >\n <Users className=\"mr-2 size-4\" /> Ask someone to sign\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {isSignOpen && pdfBlob && (\n <SignDocumentDialog\n open={isSignOpen}\n onOpenChange={setIsSignOpen}\n documentId={documentId}\n pdfBlob={pdfBlob}\n // The PDF on screen is the current version's (an earlier one cannot be signed): the\n // server refuses if another version has landed since.\n version={documentData?.current_version ?? undefined}\n appearance={signAppearance}\n />\n )}\n {headerActions}\n </ViewerHeaderEnd>\n )\n\n const viewerProps = {\n currentPage: viewingDocumentPage || undefined,\n onLoadSuccess: handleLoadSuccess,\n scrollTrigger,\n zoom,\n onZoomChange: setZoom,\n }\n\n return (\n <ViewerFrame\n frameRef={containerRef}\n contentId={documentId}\n header={\n <>\n <TabHeader\n tabs={[]}\n activeTabId={activeTab}\n onTabChange={handleTabChange}\n leftContent={leftContent}\n rightContent={rightContent}\n variant=\"underline\"\n />\n {isCompact && !isCoEditing && (\n <div data-slot=\"viewer-title-row\" className=\"flex min-w-0 items-center gap-2 px-3 pb-2\">\n {titleBlock}\n </div>\n )}\n {/* In the sticky header, not the content area: the PDF view scrolls its first page into\n view, which scrolls a bar above it out of sight. */}\n {snapshotDocumentId && (\n <VersionSnapshotBar\n versionNumber={snapshotNumber}\n live={isDocx || isArtifact}\n onAsk={\n support.askAboutVersion\n ? () => support.askAboutVersion!(snapshotDocumentId)\n : undefined\n }\n onReturn={() => setSnapshotDocumentId(null)}\n />\n )}\n </>\n }\n compareRow={isComparing ? compareIndicator || undefined : undefined}\n footer={\n // Crop to a new document. Full resolution (no maxSize): a crop frames, it never downscales.\n <ImageCropModal\n open={crop.cropImageUrl !== null}\n image={crop.cropImageUrl}\n title=\"Crop image\"\n saveLabel=\"Save as a copy\"\n aspectOptions={DEFAULT_ASPECT_OPTIONS}\n output={{ mimeType: 'image/png' }}\n onComplete={crop.handleCropComplete}\n onCancel={crop.closeCrop}\n />\n }\n >\n {isComparing && (\n <Suspense fallback={<ViewerMessage>Loading comparison\u2026</ViewerMessage>}>\n <NativeDocxComparison\n baseId={compareDocumentId!}\n revisedId={documentId}\n title={documentTitle}\n />\n </Suspense>\n )}\n {/* A capture draft (photo/video/audio) has no backend document at all until it is saved:\n its recorder takes over the whole content area. */}\n {isCaptureDraft && <ViewerCaptureDraft documentId={documentId} />}\n\n {/* Media stay mounted (hidden) on the text tab, so playback goes on while reading the\n transcript. */}\n {!isCaptureDraft &&\n (activeTab === 'pdf' || (isMedia && activeTab === 'html')) &&\n !isArtifact &&\n !isComparing && (\n <ViewerPane hidden={activeTab !== 'pdf'}>\n {/* The labels are the document's, whichever view it is read in: the PDF gets the\n chips without the passage stepper (no parsed passages to walk here). */}\n <DocumentLabelBar summaries={labelSummaries} />\n {!isMedia && !isImage && signatureBanner}\n {activeTab === 'pdf' && !isMedia && !isImage && (\n <MarkupNotices\n legacyPrompt={markup.legacyPrompt}\n olderNote={markup.olderNote}\n onOpenVersion={(n) => setSnapshotDocumentId(`${documentId}@v${n}`)}\n />\n )}\n <ViewerControlBar controls={activeTab === 'pdf' && pageNav}>\n <ViewerPdfPane\n documentId={documentId}\n doc={doc}\n pdfBlob={pdfBlob}\n isPdfLoading={blobs.isPdfLoading}\n pdfError={blobs.pdfError}\n onDownload={() => void handleDirectDownload()}\n viewerProps={viewerProps}\n signatureFlow={signatureFlow}\n onSignatureFlow={setSignatureFlow}\n currentUserId={currentUserId}\n placingSignature={placingSignature}\n onPlacingDone={(appearance) => {\n setPlacingSignature(false)\n if (!appearance) return\n setSignAppearance(appearance)\n setIsSignOpen(true)\n }}\n annotating={annotating}\n markup={markup}\n pdfSnapshotNumber={pdfSnapshotNumber}\n isSigned={isSigned}\n placeMark={placeMark}\n />\n </ViewerControlBar>\n </ViewerPane>\n )}\n\n {activeTab === 'preview' && isArtifact && liveKind && (\n // The preview loads its JSX compiler on first use, so it stays out of the main bundle.\n <ArtifactPreview\n kind={liveKind}\n source={liveSource}\n isStreaming={isStreaming}\n runtimeUrl={artifactRuntimeUrl}\n />\n )}\n\n {activeTab === 'edit' && isArtifact && liveKind && (\n <ArtifactCodeView source={liveSource} fileName={documentData?.file_name ?? undefined} />\n )}\n\n {/* A document draft is stored as DOCX: once generation ends the Word editor opens the stored\n document. Only a draft still being generated shows the streamed preview. */}\n {activeTab === 'edit' && isArtifact && !liveKind && !isStreaming && !isComparing && (\n <Suspense fallback={<ViewerMessage>Loading editor\u2026</ViewerMessage>}>\n {isSigned && !snapshotDocumentId && <SignedEditNote />}\n <NativeDocxEditor\n key={`${snapshotDocumentId || documentId}-${snapshotDocumentId ? 'snapshot' : 'live'}`}\n documentId={snapshotDocumentId || documentId}\n title={documentTitle}\n draftContent={isDraft ? draftDoc?.content || '' : undefined}\n snapshot={!!snapshotDocumentId}\n onSaved={(id) => {\n if (!isDraft) return\n session.clearDraftDocument(documentId)\n setViewingDocumentId(id)\n }}\n />\n </Suspense>\n )}\n\n {activeTab === 'versions' && (isArtifact || isDocx || hasHistory) && !isComparing && (\n <VersionTimeline\n // Each version made in a thread names it and opens it at the turn that made it.\n versions={versions.map((v) => ({\n ...v,\n madeIn: v.thread\n ? {\n label: threadTitle(v.thread.conversationId),\n onOpen: () =>\n openConversation(v.thread!.conversationId, {\n messageId: v.thread!.messageId ?? undefined,\n }),\n }\n : null,\n }))}\n currentId={currentVersionId}\n live={!!liveKind}\n // An uploaded file is not a draft: its versions come from replacing, editing or signing.\n labels={isArtifact ? undefined : { emptyDocument: UPLOADED_NO_VERSIONS }}\n formatDate={formatDate}\n onOpen={(id) => {\n // The current version is the live document itself, not a read-only copy of it.\n setSnapshotDocumentId(id === currentVersionId ? null : id)\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : 'pdf')\n }}\n onCompare={(id) => session.setDocumentViewer({ compareId: id, tab: 'html' })}\n translations={translations}\n onOpenTranslation={(id) => setViewingDocumentId(id)}\n />\n )}\n\n {activeTab === 'xlsx' &&\n isXlsx &&\n (xlsxBlob ? (\n <XlsxViewer blob={xlsxBlob} />\n ) : (\n <ViewerMessage>\n {xlsxError ? 'Failed to load spreadsheet' : 'Loading spreadsheet...'}\n </ViewerMessage>\n ))}\n\n {activeTab === 'docx' && isDocx && !isComparing && (\n <Suspense fallback={<ViewerMessage>Loading editor\u2026</ViewerMessage>}>\n {signatureBanner}\n {isSigned && !snapshotDocumentId && <SignedEditNote />}\n <NativeDocxEditor\n key={`${snapshotDocumentId || documentId}-${snapshotDocumentId ? 'snapshot' : 'live'}`}\n documentId={snapshotDocumentId || documentId}\n title={documentTitle}\n snapshot={!!snapshotDocumentId}\n />\n </Suspense>\n )}\n\n {streamingDoc &&\n isStreaming &&\n isArtifact &&\n !liveKind &&\n !isComparing &&\n (activeTab === 'html' || activeTab === 'edit') && (\n <Suspense fallback={<ViewerMessage>Opening draft\u2026</ViewerMessage>}>\n <StreamedWordArtifact\n key={documentId}\n documentId={documentId.startsWith('doc-') ? documentId : undefined}\n title={documentTitle}\n content={streamingDoc.content}\n busy={isStreaming}\n />\n </Suspense>\n )}\n\n {!isCaptureDraft &&\n !isComparing &&\n activeTab === 'html' &&\n !(isStreaming && isArtifact && !liveKind) && (\n <ViewerPane>\n <ViewerControlBar controls={pageNav}>\n <ParsedTextView\n documentId={pdfSnapshotId || documentId}\n onLoadSuccess={handleLoadSuccess}\n scrollTrigger={scrollTrigger}\n zoom={zoom}\n onZoomChange={setZoom}\n />\n </ViewerControlBar>\n </ViewerPane>\n )}\n </ViewerFrame>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * The whole document viewer on the signed-in session: a document (or one of its versions, read\n * only) as its PDF, its text, the Word editor, a sheet, an image, a recording or a live artifact;\n * its versions and comparisons; markup, signing and signature requests; sharing, Email, Translate\n * and Finalise. Runs under any host (`useConnectedWorkspace`): the open document, tab and comparison\n * are the session state's, navigation the `BlocksEnvironment`'s, and what only the host knows comes\n * as its host config's `viewer`.\n */\n\nimport { lazy, Suspense, useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport {\n ChevronDown,\n Languages,\n Mail,\n MessageSquare,\n MessageSquarePlus,\n PenLine,\n Users,\n} from 'lucide-react'\nimport {\n DEFAULT_ASPECT_OPTIONS,\n ImageCropModal,\n useArbi,\n useArbiSessionState,\n useArbiSessionStore,\n} from '@arbidocs/react'\nimport { findVersion, parseVersionRef, versionLabel } from '@arbidocs/react/artifacts'\nimport {\n SIGNED_LOCKED_REASON,\n canAnnotate,\n useDocumentMarkup,\n useDocumentSignatures,\n useDocumentTools,\n type SignatureAppearance,\n} from '@arbidocs/react/document-tools'\nimport { XlsxViewer, cycleZoom } from '@arbidocs/react/viewers'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n getEntityLabel,\n} from '@arbidocs/react/ui'\nimport {\n ArtifactCodeView,\n ArtifactCompareBar,\n ArtifactPreview,\n VersionTimeline,\n} from '../../artifacts'\nimport { latestThreadOfDocument, useRegisterOpenDocument } from '@arbidocs/react/shell'\nimport { ShareControl } from '../../collaboration/sharing/ShareControl'\nimport {\n ViewerCaptureDraft,\n ViewerDraftKind,\n ViewerDraftTitle,\n ViewerRelatedDocuments,\n} from './drafts'\nimport {\n AnnotateButton,\n DownloadMarkupButton,\n FileShareDialog,\n MarkupNotices,\n MarkupViewNote,\n PlaceMySignatureMenuItems,\n ShowOriginalButton,\n SignDocumentDialog,\n SignedEditNote,\n SignatureRequestBanner,\n SignatureStatus,\n VersionSnapshotBar,\n} from '../../document-tools'\nimport {\n DocumentLabelBar,\n PdfPageNav,\n ViewerControlBar,\n ViewerFrame,\n ViewerHeaderEnd,\n ViewerHeaderStart,\n ViewerImageActions,\n ViewerMessage,\n ViewerPageCounter,\n ViewerPane,\n ViewerStatusNote,\n ViewerTabBar,\n ViewerTitle,\n ViewerZoomControl,\n} from '../../files'\nimport { ErrorBoundary } from '../../components/ErrorBoundary'\nimport { fmtDate } from '../../lib/format'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { TabHeader } from '../../shell'\nimport { useConnectedWorkspace } from '../ConnectionProvider'\nimport { useConnectedConversations } from '../workspaceData'\nimport { ConnectedDocumentToolsProvider } from './ConnectedDocumentToolsProvider'\nimport { FinaliseTranslationButton } from './FinaliseTranslationButton'\nimport { useDocumentViewerSupport } from './support'\nimport { useImageCrop } from './useImageCrop'\nimport { useViewedDocument } from './useViewedDocument'\nimport { useViewerBlobs } from './useViewerBlobs'\nimport { useViewerTabs } from './useViewerTabs'\nimport { useViewerVersions } from './useViewerVersions'\nimport { VersionDropdown } from './VersionDropdown'\nimport { ParsedTextView } from './parsed/ParsedTextView'\nimport { ViewerPdfPane, type SignatureFlow } from './ViewerPdfPane'\n// The Word editor itself is its own chunk (`docxEditorChunk`), loaded when a Word document shows.\nimport { ConnectedNativeDocxEditor as NativeDocxEditor } from '../docx/ConnectedNativeDocxEditor'\nimport { canChangeVisibility } from '../../files/permissions'\n\nconst StreamedWordArtifact = lazy(() =>\n import('../docx/ConnectedStreamedWordArtifact').then((m) => ({\n default: m.ConnectedStreamedWordArtifact,\n }))\n)\nconst NativeDocxComparison = lazy(() =>\n import('../docx/ConnectedNativeDocxComparison').then((m) => ({\n default: m.ConnectedNativeDocxComparison,\n }))\n)\n\nconst UPLOADED_NO_VERSIONS =\n 'No earlier versions yet. Replacing, editing or signing this file adds a new version here.'\n\nexport interface ConnectedDocumentViewerProps {\n /**\n * The document, or a version reference `doc-\u2026@v{n}` (a citation, a \"made from v2\" link): an\n * earlier version opens read-only. Default: the session state's viewing document.\n */\n documentId?: string\n /** Controls at the right end of the header (a panel's dock / pop-out switcher). */\n headerActions?: ReactNode\n /** Where html/react artifacts load their sandbox runtime from. */\n artifactRuntimeUrl?: string\n}\n\nexport function ConnectedDocumentViewer(props: ConnectedDocumentViewerProps) {\n const viewing = useArbiSessionState((s) => s.viewingDocument?.id)\n const openedId = props.documentId ?? viewing\n if (!openedId) return null\n // A viewer that throws (a PDF the browser cannot render, say) shows the error here, in the\n // viewer's place, instead of unmounting the whole app.\n return (\n <ErrorBoundary\n resetKey={openedId}\n labels={{ title: \"This document couldn't be displayed\" }}\n testId=\"document-viewer-error\"\n >\n <ConnectedDocumentToolsProvider>\n <DocumentViewerContent {...props} openedId={openedId} />\n </ConnectedDocumentToolsProvider>\n </ErrorBoundary>\n )\n}\n\nfunction DocumentViewerContent({\n openedId,\n headerActions,\n artifactRuntimeUrl = '/artifact-runtime/',\n}: ConnectedDocumentViewerProps & { openedId: string }) {\n const arbi = useArbi()\n const session = useArbiSessionStore()\n const support = useDocumentViewerSupport()\n const formatDate = support.formatDate ?? fmtDate\n const tools = useDocumentTools()\n const { openConversation, openNewConversation, notify } = useBlocksEnvironment()\n const { userId: currentUserId } = useConnectedWorkspace()\n // A document keeps one id for its whole life; its versions are inside it.\n const documentId = parseVersionRef(openedId).docId\n const [totalPages, setTotalPages] = useState<number>(0)\n const [isCompact, setIsCompact] = useState(false)\n // Zoom of the PDF (canvas scale) / text, as a multiplier of fit width; pinch, double-tap and the\n // zoom button all drive it. The text view's size is a reading preference for every document.\n const [pdfZoom, setPdfZoom] = useState(1)\n const {\n tab: zoomTab,\n textScale,\n compareId: compareDocumentId,\n } = useArbiSessionState((s) => s.documentViewer)\n const zoom = zoomTab === 'html' ? textScale : pdfZoom\n const setZoom = useCallback(\n (next: number | ((z: number) => number)) => {\n const value = typeof next === 'function' ? next(zoom) : next\n if (zoomTab === 'html') session.setDocumentViewer({ textScale: value })\n else setPdfZoom(value)\n },\n [zoomTab, session, zoom]\n )\n const [scrollTrigger, setScrollTrigger] = useState(0) // Incremented to scroll the viewers\n const containerRef = useRef<HTMLDivElement>(null)\n\n const viewingDocumentPage = useArbiSessionState((s) => s.viewingDocument?.page ?? null)\n const setViewingDocumentPage = (page: number) =>\n session.setViewingDocument({ id: openedId, page })\n const setViewingDocumentId = (id: string) => session.setViewingDocument({ id })\n const setActiveTab = (tab: Parameters<typeof session.setDocumentViewer>[0]['tab']) =>\n session.setDocumentViewer({ tab })\n const setCompareDocumentId = (id: string | null) => session.setDocumentViewer({ compareId: id })\n const { data: conversations } = useConnectedConversations()\n\n // An earlier version opened read-only (`doc-\u2026@v{n}`) from the Versions tab, a citation or a\n // \"made from\" link. Word documents show it in the Word editor, artifacts in theirs, everything\n // else as its PDF. The version on screen is the session's viewing id, not local state: the\n // viewer remounts when its panel moves to a new window, and the version must come along.\n const snapshotRef = parseVersionRef(openedId).version ? openedId : null\n // Every version of the document, oldest first. Every version of an artifact shares one name, so\n // both sides of a comparison get the timeline's \"v1/v2/v3\" label.\n const { versions, translations } = useViewerVersions(documentId)\n const currentVersionId = versions.find((v) => v.isCurrent)?.id ?? documentId\n // Opening the current version is the live document itself, not a read-only copy of it.\n const snapshotDocumentId = snapshotRef && snapshotRef !== currentVersionId ? snapshotRef : null\n const doc = useViewedDocument(documentId)\n const setSnapshotDocumentId = (ref: string | null) => setViewingDocumentId(ref ?? documentId)\n // Drafting mode: a thread bound to the open document (or the one it was made in) drafts in it,\n // also while an earlier version of it is on screen; a turn sent then brings the live document\n // back, where the assistant's edits appear. Being open binds no chat to it.\n useRegisterOpenDocument({\n documentId: doc.savedDocumentId,\n shownId: openedId,\n showLive: () => setViewingDocumentId(documentId),\n workspaceId: doc.workspaceId,\n conversationId: doc.documentData?.conversation_ext_id ?? null,\n })\n const {\n documentData,\n streamingDoc,\n isStreaming,\n draftDoc,\n isDraft,\n isCaptureDraft,\n labelSummaries,\n isImage,\n isVideo,\n isAudio,\n isMedia,\n isArtifact,\n liveKind,\n liveSource,\n isDocx,\n isXlsx,\n isDownloadOnly,\n } = doc\n // The thread bound to this document: its latest one, else a new chat bound to it. The document\n // stays on screen beside it.\n const chatAboutDocument = () => {\n const savedId = doc.savedDocumentId\n if (!savedId) return\n const latest = latestThreadOfDocument(conversations, savedId)\n if (latest) {\n openConversation(latest, { keepDocumentOpen: true })\n return\n }\n // Opening a new chat starts it unbound; it is bound after.\n openNewConversation({ keepDocumentOpen: true })\n session.setNewChatDocumentId(savedId)\n }\n // A thread by its title, for the threads a document (and each version) was made in.\n const threadTitle = (id: string) =>\n conversations.find((c) => c.external_id === id)?.title?.trim() || 'Its thread'\n // The thread a generated document was made in (none for an upload).\n const madeInId = documentData?.conversation_ext_id ?? null\n const madeIn = madeInId ? { id: madeInId, title: threadTitle(madeInId) } : null\n const pdfSnapshotId = snapshotDocumentId && (!isArtifact || isDocx) ? snapshotDocumentId : null\n // The document on screen: an earlier version when one is open, else the current one.\n const shownDocumentId = pdfSnapshotId || documentId\n const blobs = useViewerBlobs(shownDocumentId, doc)\n const [minimumPdfVersion, setMinimumPdfVersion] = useState<number | null>(null)\n useEffect(() => setMinimumPdfVersion(null), [documentId])\n const versionReady =\n !!pdfSnapshotId ||\n minimumPdfVersion === null ||\n (documentData?.current_version ?? 0) >= minimumPdfVersion\n const { xlsxBlob, xlsxError, handleDirectDownload } = blobs\n const pdfBlob = versionReady ? blobs.pdfBlob : null\n const pdfVerified = !!pdfBlob && blobs.pdfVerified !== false\n // Annotation mode for the PDF view; off for every newly opened document.\n const [annotating, setAnnotating] = useState(false)\n const [sharingFile, setSharingFile] = useState(false)\n useEffect(() => setAnnotating(false), [documentId])\n // My signature: one's saved signature or initials, to place as a picture stamp in the markup.\n const [placeMark, setPlaceMark] = useState<{ image: string; label: string; key: number } | null>(\n null\n )\n // Translations are listed with the versions (each is its own document), so they open the tab too.\n const hasHistory =\n versions.length > 1 || (documentData?.current_version ?? 1) > 1 || translations.length > 0\n const {\n activeTab,\n handleTabChange: changeTab,\n viewerTabs,\n } = useViewerTabs(doc, isCompact, hasHistory)\n const saveWordRef = useRef<(() => Promise<boolean | number>) | null>(null)\n const transitionPending = useRef(false)\n const transitionKey = JSON.stringify([openedId, doc.workspaceId])\n const transitionScope = useRef({ key: transitionKey, generation: 0 })\n if (transitionScope.current.key !== transitionKey) {\n transitionScope.current = {\n key: transitionKey,\n generation: transitionScope.current.generation + 1,\n }\n }\n useEffect(\n () => () => {\n transitionScope.current.generation += 1\n },\n []\n )\n const requestViewerTransition = async (transition: () => void): Promise<boolean> => {\n if (transitionPending.current) return false\n const leavingWord =\n isDocx &&\n !isDraft &&\n !isStreaming &&\n !snapshotDocumentId &&\n (activeTab === 'docx' || (isArtifact && !liveKind && activeTab === 'edit'))\n if (leavingWord) {\n transitionPending.current = true\n const generation = transitionScope.current.generation\n try {\n const saved = saveWordRef.current && (await saveWordRef.current())\n if (!saved) {\n notify('Could not save the current document. Stay in the editor and try again.', 'error')\n return false\n }\n if (generation !== transitionScope.current.generation) return false\n if (typeof saved === 'number') setMinimumPdfVersion(saved)\n } finally {\n transitionPending.current = false\n }\n }\n transition()\n return true\n }\n const handleTabChange = (tab: string) => {\n if (tab === activeTab) return\n void requestViewerTransition(() => changeTab(tab))\n }\n const crop = useImageCrop(\n documentId,\n documentData?.file_name,\n pdfBlob,\n documentData?.workspace_ext_id\n )\n // Signing: choose where the signature goes (placing), then the Sign dialog.\n const [placingSignature, setPlacingSignature] = useState(false)\n const [signAppearance, setSignAppearance] = useState<SignatureAppearance | undefined>()\n const [isSignOpen, setIsSignOpen] = useState(false)\n const signingScope = JSON.stringify([\n documentId,\n snapshotDocumentId,\n documentData?.current_version,\n ])\n const signingScopeRef = useRef(signingScope)\n const signingScopeMatches = signingScopeRef.current === signingScope\n // Leaving the placement when another version opens or returns: it belongs to the copy on screen.\n useEffect(() => {\n setPlacingSignature(false)\n setIsSignOpen(false)\n setSignAppearance(undefined)\n signingScopeRef.current = signingScope\n }, [signingScope])\n // A signature request: the author placing fields ('prepare'), or a signer walked through theirs.\n const [signatureFlow, setSignatureFlow] = useState<SignatureFlow>(null)\n useEffect(() => setSignatureFlow(null), [signingScope])\n const signatureDocumentId =\n pdfSnapshotId ||\n (documentData?.current_version ? `${documentId}@v${documentData.current_version}` : documentId)\n const { data: signatureStatus } = useDocumentSignatures(\n signatureDocumentId,\n !isDraft && !liveKind\n )\n\n // The Word editor on the current version: the editor's own ribbon says \"Co-edit mode\", so the\n // header carries no version label and, when narrow, no title row above the ribbon.\n const isCoEditing =\n !snapshotDocumentId &&\n !compareDocumentId &&\n !isDraft &&\n ((activeTab === 'docx' && isDocx) ||\n (activeTab === 'edit' && isArtifact && !liveKind && !isStreaming))\n const currentVersionLabel = isCoEditing\n ? undefined\n : !snapshotDocumentId && !compareDocumentId && (isDocx || (isArtifact && !liveKind))\n ? 'Live'\n : versionLabel(versions, snapshotDocumentId || documentId)\n const compareVersionLabel = versionLabel(versions, compareDocumentId)\n const snapshotNumber = findVersion(versions, snapshotDocumentId)?.number\n // The markup of the version on screen: the default view when it has any (\"Show original\" hides).\n const pdfSnapshotNumber = pdfSnapshotId\n ? (parseVersionRef(pdfSnapshotId).version ?? undefined)\n : undefined\n // A signed version is locked: only a further signature changes it. Its marks stay in the markup\n // layer (never in its PDF), and editing its content saves a new, unsigned version.\n const isSigned = !!signatureStatus?.signed\n const markup = useDocumentMarkup(documentData, pdfSnapshotNumber, isSigned)\n\n // Detect container width changes (640px = the sm: breakpoint).\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) setIsCompact(entry.contentRect.width < 640)\n })\n resizeObserver.observe(container)\n return () => resizeObserver.disconnect()\n }, [])\n\n const handleLoadSuccess = useCallback((numPages: number) => setTotalPages(numPages), [])\n\n // Go to a page: the counter, or one step from the arrows.\n const goToPage = (page: number) => {\n setViewingDocumentPage(page)\n setScrollTrigger((prev) => prev + 1)\n }\n const stepPage = (delta: number) => {\n const next = (viewingDocumentPage || 1) + delta\n if (next >= 1 && next <= totalPages) goToPage(next)\n }\n\n const documentTitle =\n streamingDoc?.title ||\n draftDoc?.title ||\n documentData?.doc_metadata?.title ||\n documentData?.file_name ||\n 'Document'\n\n // The page / zoom controls, shared by the PDF and the text view. They sit in the control bar\n // under the body, so they never cover the text being read.\n const pageNav = totalPages > 0 && (\n <>\n <ViewerZoomControl zoom={zoom} onCycle={() => setZoom(cycleZoom(zoom))} />\n <PdfPageNav\n canPrev={(viewingDocumentPage || 1) > 1}\n canNext={(viewingDocumentPage || 1) < totalPages}\n onPrev={() => stepPage(-1)}\n onNext={() => stepPage(1)}\n counter={\n <ViewerPageCounter page={viewingDocumentPage || 1} total={totalPages} onGoTo={goToPage} />\n }\n />\n </>\n )\n\n // Compare: a \"Compare vs. [doc]\" row of its own below the tab/title bar (a docked panel is\n // narrow), with the flip-direction arrow and the way out.\n const isComparing = !!compareDocumentId\n const compareTarget = compareDocumentId ? parseVersionRef(compareDocumentId).docId : null\n const compareIndicator = isComparing && compareTarget && (\n <ArtifactCompareBar\n compareTarget={support.renderDocumentPill?.(compareTarget) ?? compareTarget}\n versionLabel={compareVersionLabel}\n mode=\"flip\"\n showTrackChanges={false}\n onToggleTrackChanges={() => {}}\n onFlip={() => {\n setViewingDocumentId(compareDocumentId!)\n setCompareDocumentId(documentId)\n }}\n onStop={() => setCompareDocumentId(null)}\n />\n )\n\n // Document name block: the name, related documents and status notes. Roomy headers keep it on\n // the tab row; a narrow (phone / docked) header gives it a row of its own so the name is never\n // cut down to a couple of letters by the tabs and actions.\n const titleBlock = (\n <>\n {/* A draft gets an editable name + auto-name toggle instead of the plain read-only name. */}\n {isDraft ? (\n <ViewerDraftTitle documentId={documentId} />\n ) : (\n <ViewerTitle\n title={documentTitle}\n versionLabel={currentVersionLabel}\n shrink={!!liveKind || isCompact}\n />\n )}\n {/* The narrow header's Share is icon-only, so the state is spelled out here as text. */}\n {isCompact && !isDraft && documentData?.shared && (\n <ViewerStatusNote testId=\"document-shared-status\">\n Shared with the workspace\n </ViewerStatusNote>\n )}\n {/* Likewise \"Show original\" is a bare page icon there: say which view is on screen. */}\n {isCompact &&\n activeTab === 'pdf' &&\n pdfBlob &&\n markup.hasMarkup &&\n !annotating &&\n !placingSignature && (\n <MarkupViewNote\n showOriginal={markup.showOriginal}\n onToggle={() => markup.setShowOriginal((on) => !on)}\n />\n )}\n {/* Related documents, except during a comparison (its own row says which). */}\n {!isComparing && !liveKind && documentData && (\n <ViewerRelatedDocuments document={documentData} />\n )}\n {isStreaming && <ViewerStatusNote pulse>streaming...</ViewerStatusNote>}\n {/* Nothing is generating: this document simply does not exist on the backend yet. */}\n {isDraft && (\n <ViewerStatusNote testId=\"draft-unsaved-indicator\">Draft \u2014 not saved</ViewerStatusNote>\n )}\n {signatureStatus?.signed && (\n <SignatureStatus status={signatureStatus} formatDate={formatDate} />\n )}\n </>\n )\n\n const leftContent = (\n <ViewerHeaderStart>\n {isDraft ? (\n // A draft's kind replaces the tabs: neither Versions nor the text view means anything\n // before the first save.\n <ViewerDraftKind documentId={documentId} />\n ) : (\n <>\n <ViewerTabBar\n tabs={viewerTabs.filter((tab) => tab.id !== 'versions')}\n activeId={activeTab}\n onChange={handleTabChange}\n />\n {(isArtifact || isDocx || hasHistory) && !liveKind && !isComparing && (\n <VersionDropdown\n versions={versions}\n activeId={\n snapshotDocumentId ??\n (currentVersionId === documentId && documentData?.current_version\n ? `${documentId}@v${documentData.current_version}`\n : currentVersionId)\n }\n isSnapshot={!!snapshotDocumentId}\n onOpen={(id) => {\n void requestViewerTransition(() => {\n setSnapshotDocumentId(id === currentVersionId ? null : id)\n if (activeTab === 'versions')\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : 'pdf')\n })\n }}\n onHistory={() => handleTabChange('versions')}\n />\n )}\n </>\n )}\n {!isCompact && titleBlock}\n </ViewerHeaderStart>\n )\n\n const annotatable = canAnnotate({\n activeTab,\n hasPdf: pdfVerified,\n isImage,\n isVideo,\n isAudio,\n isDownloadOnly,\n isDraft,\n isStreaming,\n isSnapshot: !!snapshotDocumentId,\n isComparing,\n })\n\n // A request waiting for this user's signature, or their own in flight: shown over the PDF and\n // the Word editor alike; signing happens on the PDF.\n const signatureBanner = !isDraft && !liveKind && !snapshotDocumentId && (\n <SignatureRequestBanner\n documentId={documentId}\n hidden={!!signatureFlow}\n onSign={(request) => {\n void requestViewerTransition(() => {\n setAnnotating(false)\n setPlacingSignature(false)\n if (activeTab !== 'pdf') changeTab('pdf')\n setSignatureFlow({ kind: 'sign', request })\n })\n }}\n onEditDraft={(draft) => {\n void requestViewerTransition(() => {\n if (activeTab !== 'pdf') changeTab('pdf')\n setSignatureFlow({ kind: 'prepare', draft })\n })\n }}\n />\n )\n\n const share = () => {\n const name = (liveKind ? documentTitle : documentData?.file_name) || undefined\n if (support.share) {\n support.share({ id: documentId, name, isPrivate: !documentData?.shared })\n return\n }\n void arbi.documents\n .update([{ external_id: documentId, shared: !documentData?.shared }])\n .then(() => tools.onDocumentsChanged?.([documentId], 'markup'))\n .catch(() => notify(\"Couldn't change who can see this document\", 'error'))\n }\n const shownRef = snapshotDocumentId || documentId\n\n const rightContent = (\n <ViewerHeaderEnd isCompact={isCompact}>\n {/* Annotate: only for a PDF on screen (text and Word files are shown as a PDF too). Marks\n sit in a layer beside the document; Freeze saves a separate copy with them built in. */}\n {annotatable && (\n <AnnotateButton\n active={annotating}\n compact={isCompact}\n onClick={() => {\n setPlacingSignature(false)\n markup.setShowOriginal(false)\n setAnnotating((on) => !on)\n }}\n />\n )}\n {/* The markup is the default view; \"Show original\" shows the untouched file. */}\n {activeTab === 'pdf' && pdfBlob && !placingSignature && (markup.hasMarkup || annotating) && (\n <ShowOriginalButton\n active={markup.showOriginal}\n compact={isCompact}\n onClick={() => {\n setAnnotating(false)\n markup.setShowOriginal((on) => !on)\n }}\n />\n )}\n {activeTab === 'pdf' && markup.hasMarkup && !annotating && (\n <DownloadMarkupButton\n onClick={() => void markup.downloadMarkup()}\n // A signed version is locked: Download serves the signed file as it is.\n disabledReason={isSigned ? SIGNED_LOCKED_REASON : undefined}\n />\n )}\n {/* Image actions: start a generation from this image, or crop it into a new document. */}\n {activeTab === 'pdf' && isImage && pdfBlob && (\n <ViewerImageActions\n compact={isCompact}\n onUseAsReference={\n support.useImageAsReference ? () => support.useImageAsReference!(documentId) : undefined\n }\n onCrop={crop.handleOpenCrop}\n />\n )}\n {/* The thread it was made in: open it at the answer that made it. */}\n {madeIn && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n onClick={() =>\n openConversation(madeIn.id, {\n messageId: documentData?.source_message_ext_id ?? undefined,\n })\n }\n title={`Open the thread it was made in: ${madeIn.title}`}\n aria-label={`Open the thread it was made in: ${madeIn.title}`}\n data-testid=\"document-open-thread\"\n >\n <MessageSquare className=\"size-4\" />\n {!isCompact && <span className=\"max-w-[10rem] truncate\">{madeIn.title}</span>}\n </Button>\n )}\n {documentId && documentData && !isDraft && !isStreaming && (\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setSharingFile(true)}\n data-testid=\"share-file-button\"\n >\n Share file\n </Button>\n <FileShareDialog\n open={sharingFile}\n onOpenChange={setSharingFile}\n documentId={documentId}\n version={pdfSnapshotNumber ?? documentData.current_version ?? 1}\n />\n </>\n )}\n {/* Chat about this document: the thread bound to it (its questions edit it), the latest one\n or a new one. Only such a thread drafts in a document: one merely open binds no chat. */}\n {doc.savedDocumentId && !snapshotDocumentId && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n onClick={chatAboutDocument}\n title=\"Chat about this document: a thread that works in it, with edits as tracked changes\"\n aria-label=\"Chat about this document\"\n data-testid=\"document-chat-about\"\n className=\"pointer-coarse:min-h-11\"\n >\n <MessageSquarePlus className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Chat</span>}\n </Button>\n )}\n {/* Share always asks first (the host's share dialog), so a click never changes who can see\n the file by surprise. */}\n {documentId && doc.workspaceId && (\n <ShareControl\n state={documentData?.shared ? 'shared' : 'private'}\n onToggle={share}\n disabled={!canChangeVisibility(documentData, currentUserId)}\n disabledTooltip=\"Only the owner can change visibility\"\n tooltip={\n documentData?.shared\n ? 'Shared with the workspace \u2014 click to share with specific people'\n : 'Share with the workspace, then optionally notify specific people by email'\n }\n variant=\"outline\"\n compact={isCompact}\n showState={!isCompact}\n labels={{\n shared: getEntityLabel('WORKSPACE'),\n private: 'Only you',\n mixed: 'Partly shared',\n }}\n testId=\"share-document-button\"\n stateTestId=\"document-title-shared-indicator\"\n />\n )}\n {/* Email: the host's mail composer with the document on screen attached. The divider keeps\n it apart from Share, which changes who can see the file rather than sending it. */}\n {tools.emailDocument && !isDraft && !isStreaming && documentData?.file_name && (\n <>\n <span className=\"mx-1 h-5 w-px bg-border\" aria-hidden=\"true\" />\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n title=\"Email this document\"\n aria-label=\"Email\"\n data-testid=\"email-document-button\"\n className=\"pointer-coarse:min-h-11\"\n onClick={() => tools.emailDocument?.(shownRef)}\n >\n <Mail className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Email</span>}\n </Button>\n </>\n )}\n {/* Translate: a new, editable document with the original and translation side by side. */}\n {support.translate &&\n !isDraft &&\n !isStreaming &&\n !liveKind &&\n !isImage &&\n documentData?.file_name && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size={isCompact ? 'icon' : 'sm'}\n title=\"Translate into another language: a new editable document, original and translation side by side\"\n aria-label=\"Translate\"\n data-testid=\"translate-document-button\"\n className=\"pointer-coarse:min-h-11\"\n onClick={() => support.translate!(shownRef)}\n >\n <Languages className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Translate</span>}\n </Button>\n )}\n {/* Finalise (a translation): its current version saved as a new labelled PDF. */}\n {!isStreaming && !snapshotDocumentId && (\n <FinaliseTranslationButton document={documentData ?? undefined} isCompact={isCompact} />\n )}\n {/* Every signing action starts in one menu: sign yourself, save/place a mark, or request\n signatures from others. */}\n {annotatable && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant={\n placingSignature || signatureFlow?.kind === 'prepare' ? 'default' : 'outline'\n }\n size={isCompact ? 'icon' : 'sm'}\n aria-label=\"Sign\"\n title=\"Sign or request signatures\"\n data-testid=\"signing-menu-trigger\"\n className=\"pointer-coarse:min-h-11\"\n >\n <PenLine className=\"size-4\" />\n {!isCompact && <span className=\"ml-1\">Sign</span>}\n <ChevronDown className=\"ml-1 size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" forceMount>\n <DropdownMenuItem\n data-testid=\"sign-document-button\"\n onSelect={() => {\n setAnnotating(false)\n if (isSigned) {\n setSignatureFlow(null)\n setPlacingSignature((on) => !on)\n } else {\n setPlacingSignature(false)\n setSignatureFlow({ kind: 'prepare', self: true })\n }\n }}\n >\n <PenLine className=\"mr-2 size-4\" /> Sign this document\n </DropdownMenuItem>\n {!isSigned && (\n <>\n <PlaceMySignatureMenuItems\n onPlace={(mark) => {\n setPlacingSignature(false)\n setSignatureFlow(null)\n markup.setShowOriginal(false)\n setAnnotating(true)\n setPlaceMark({ ...mark, key: Date.now() })\n }}\n />\n <DropdownMenuItem\n data-testid=\"request-signatures-button\"\n onSelect={() => {\n setAnnotating(false)\n setPlacingSignature(false)\n setSignatureFlow(signatureFlow?.kind === 'prepare' ? null : { kind: 'prepare' })\n }}\n >\n <Users className=\"mr-2 size-4\" /> Ask someone to sign\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {isSignOpen && pdfBlob && pdfVerified && signingScopeMatches && (\n <SignDocumentDialog\n open={isSignOpen}\n onOpenChange={setIsSignOpen}\n documentId={documentId}\n pdfBlob={pdfBlob}\n // The PDF on screen is the current version's (an earlier one cannot be signed): the\n // server refuses if another version has landed since.\n version={documentData?.current_version ?? undefined}\n appearance={signAppearance}\n />\n )}\n {headerActions}\n </ViewerHeaderEnd>\n )\n\n const viewerProps = {\n currentPage: viewingDocumentPage || undefined,\n onLoadSuccess: handleLoadSuccess,\n scrollTrigger,\n zoom,\n onZoomChange: setZoom,\n }\n\n return (\n <ViewerFrame\n frameRef={containerRef}\n contentId={documentId}\n header={\n <>\n <TabHeader\n tabs={[]}\n activeTabId={activeTab}\n onTabChange={handleTabChange}\n leftContent={leftContent}\n rightContent={rightContent}\n variant=\"underline\"\n />\n {isCompact && !isCoEditing && (\n <div data-slot=\"viewer-title-row\" className=\"flex min-w-0 items-center gap-2 px-3 pb-2\">\n {titleBlock}\n </div>\n )}\n {/* In the sticky header, not the content area: the PDF view scrolls its first page into\n view, which scrolls a bar above it out of sight. */}\n {snapshotDocumentId && (\n <VersionSnapshotBar\n versionNumber={snapshotNumber}\n live={isDocx || isArtifact}\n onAsk={\n support.askAboutVersion\n ? () => support.askAboutVersion!(snapshotDocumentId)\n : undefined\n }\n onReturn={() => setSnapshotDocumentId(null)}\n />\n )}\n </>\n }\n compareRow={isComparing ? compareIndicator || undefined : undefined}\n footer={\n // Crop to a new document. Full resolution (no maxSize): a crop frames, it never downscales.\n <ImageCropModal\n open={crop.cropImageUrl !== null}\n image={crop.cropImageUrl}\n title=\"Crop image\"\n saveLabel=\"Save as a copy\"\n aspectOptions={DEFAULT_ASPECT_OPTIONS}\n output={{ mimeType: 'image/png' }}\n onComplete={crop.handleCropComplete}\n onCancel={crop.closeCrop}\n />\n }\n >\n {isComparing && (\n <Suspense fallback={<ViewerMessage>Loading comparison\u2026</ViewerMessage>}>\n <NativeDocxComparison\n baseId={compareDocumentId!}\n revisedId={documentId}\n title={documentTitle}\n />\n </Suspense>\n )}\n {/* A capture draft (photo/video/audio) has no backend document at all until it is saved:\n its recorder takes over the whole content area. */}\n {isCaptureDraft && <ViewerCaptureDraft documentId={documentId} />}\n\n {/* Media stay mounted (hidden) on the text tab, so playback goes on while reading the\n transcript. */}\n {!isCaptureDraft &&\n (activeTab === 'pdf' || (isMedia && activeTab === 'html')) &&\n (!isArtifact || (isDocx && !isDraft && !isStreaming && !liveKind)) &&\n !isComparing && (\n <ViewerPane hidden={activeTab !== 'pdf'}>\n {/* The labels are the document's, whichever view it is read in: the PDF gets the\n chips without the passage stepper (no parsed passages to walk here). */}\n <DocumentLabelBar summaries={labelSummaries} />\n {!isMedia && !isImage && signatureBanner}\n {activeTab === 'pdf' && pdfBlob && !pdfVerified && (\n <ViewerMessage>\n Offline copy: its version cannot be verified. Reconnect before signing.{' '}\n <button type=\"button\" onClick={() => void blobs.retryPdf()} className=\"underline\">\n Retry loading the current PDF\n </button>\n </ViewerMessage>\n )}\n {activeTab === 'pdf' && !isMedia && !isImage && (\n <MarkupNotices\n legacyPrompt={markup.legacyPrompt}\n olderNote={markup.olderNote}\n onOpenVersion={(n) => setSnapshotDocumentId(`${documentId}@v${n}`)}\n />\n )}\n <ViewerControlBar controls={activeTab === 'pdf' && pageNav}>\n <ViewerPdfPane\n documentId={documentId}\n doc={doc}\n pdfBlob={pdfBlob}\n isPdfLoading={!versionReady || blobs.isPdfLoading}\n pdfError={blobs.pdfError}\n onDownload={() => void handleDirectDownload()}\n viewerProps={viewerProps}\n signatureFlow={pdfVerified && signingScopeMatches ? signatureFlow : null}\n onSignatureFlow={setSignatureFlow}\n currentUserId={currentUserId}\n placingSignature={pdfVerified && signingScopeMatches && placingSignature}\n onPlacingDone={(appearance) => {\n setPlacingSignature(false)\n if (!appearance) return\n setSignAppearance(appearance)\n setIsSignOpen(true)\n }}\n annotating={annotating}\n markup={markup}\n pdfSnapshotNumber={pdfSnapshotNumber}\n isSigned={isSigned}\n placeMark={placeMark}\n />\n </ViewerControlBar>\n </ViewerPane>\n )}\n\n {activeTab === 'preview' && isArtifact && liveKind && (\n // The preview loads its JSX compiler on first use, so it stays out of the main bundle.\n <ArtifactPreview\n kind={liveKind}\n source={liveSource}\n isStreaming={isStreaming}\n runtimeUrl={artifactRuntimeUrl}\n />\n )}\n\n {activeTab === 'edit' && isArtifact && liveKind && (\n <ArtifactCodeView source={liveSource} fileName={documentData?.file_name ?? undefined} />\n )}\n\n {/* A document draft is stored as DOCX: once generation ends the Word editor opens the stored\n document. Only a draft still being generated shows the streamed preview. */}\n {activeTab === 'edit' && isArtifact && !liveKind && !isStreaming && !isComparing && (\n <Suspense fallback={<ViewerMessage>Loading editor\u2026</ViewerMessage>}>\n {isSigned && !snapshotDocumentId && <SignedEditNote />}\n <NativeDocxEditor\n key={`${snapshotDocumentId || documentId}-${snapshotDocumentId ? 'snapshot' : 'live'}`}\n documentId={snapshotDocumentId || documentId}\n title={documentTitle}\n draftContent={isDraft ? draftDoc?.content || '' : undefined}\n snapshot={!!snapshotDocumentId}\n saveRef={saveWordRef}\n onSaved={(id) => {\n if (!isDraft) return\n session.clearDraftDocument(documentId)\n setViewingDocumentId(id)\n }}\n />\n </Suspense>\n )}\n\n {activeTab === 'versions' && (isArtifact || isDocx || hasHistory) && !isComparing && (\n <VersionTimeline\n // Each version made in a thread names it and opens it at the turn that made it.\n versions={versions.map((v) => ({\n ...v,\n madeIn: v.thread\n ? {\n label: threadTitle(v.thread.conversationId),\n onOpen: () =>\n openConversation(v.thread!.conversationId, {\n messageId: v.thread!.messageId ?? undefined,\n }),\n }\n : null,\n }))}\n currentId={currentVersionId}\n live={!!liveKind}\n // An uploaded file is not a draft: its versions come from replacing, editing or signing.\n labels={isArtifact ? undefined : { emptyDocument: UPLOADED_NO_VERSIONS }}\n formatDate={formatDate}\n onOpen={(id) => {\n // The current version is the live document itself, not a read-only copy of it.\n setSnapshotDocumentId(id === currentVersionId ? null : id)\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : 'pdf')\n }}\n onCompare={(id) => session.setDocumentViewer({ compareId: id, tab: 'html' })}\n translations={translations}\n onOpenTranslation={(id) => setViewingDocumentId(id)}\n />\n )}\n\n {activeTab === 'xlsx' &&\n isXlsx &&\n (xlsxBlob ? (\n <XlsxViewer blob={xlsxBlob} />\n ) : (\n <ViewerMessage>\n {xlsxError ? 'Failed to load spreadsheet' : 'Loading spreadsheet...'}\n </ViewerMessage>\n ))}\n\n {activeTab === 'docx' && isDocx && !isComparing && (\n <Suspense fallback={<ViewerMessage>Loading editor\u2026</ViewerMessage>}>\n {signatureBanner}\n {isSigned && !snapshotDocumentId && <SignedEditNote />}\n <NativeDocxEditor\n key={`${snapshotDocumentId || documentId}-${snapshotDocumentId ? 'snapshot' : 'live'}`}\n documentId={snapshotDocumentId || documentId}\n title={documentTitle}\n snapshot={!!snapshotDocumentId}\n saveRef={saveWordRef}\n />\n </Suspense>\n )}\n\n {streamingDoc &&\n isStreaming &&\n isArtifact &&\n !liveKind &&\n !isComparing &&\n (activeTab === 'html' || activeTab === 'edit') && (\n <Suspense fallback={<ViewerMessage>Opening draft\u2026</ViewerMessage>}>\n <StreamedWordArtifact\n key={documentId}\n documentId={documentId.startsWith('doc-') ? documentId : undefined}\n title={documentTitle}\n content={streamingDoc.content}\n busy={isStreaming}\n />\n </Suspense>\n )}\n\n {!isCaptureDraft &&\n !isComparing &&\n activeTab === 'html' &&\n !(isStreaming && isArtifact && !liveKind) && (\n <ViewerPane>\n <ViewerControlBar controls={pageNav}>\n <ParsedTextView\n documentId={pdfSnapshotId || documentId}\n onLoadSuccess={handleLoadSuccess}\n scrollTrigger={scrollTrigger}\n zoom={zoom}\n onZoomChange={setZoom}\n />\n </ViewerControlBar>\n </ViewerPane>\n )}\n </ViewerFrame>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ArtifactVersion } from '@arbidocs/react/artifacts';
|
|
2
|
+
/** The version on screen, with a direct way to open another version. */
|
|
3
|
+
export declare function VersionDropdown({ versions, activeId, isSnapshot, onOpen, onHistory, }: {
|
|
4
|
+
versions: readonly ArtifactVersion[];
|
|
5
|
+
activeId: string | null;
|
|
6
|
+
isSnapshot: boolean;
|
|
7
|
+
onOpen: (id: string) => void;
|
|
8
|
+
onHistory: () => void;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
function VersionDropdown({
|
|
4
|
+
versions,
|
|
5
|
+
activeId,
|
|
6
|
+
isSnapshot,
|
|
7
|
+
onOpen,
|
|
8
|
+
onHistory
|
|
9
|
+
}) {
|
|
10
|
+
const active = versions.find((version) => version.id === activeId);
|
|
11
|
+
const pendingVersion = activeId?.match(/@v([1-9]\d*)$/)?.[1];
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
"select",
|
|
14
|
+
{
|
|
15
|
+
"aria-label": "Active document version",
|
|
16
|
+
"data-testid": "document-version-dropdown",
|
|
17
|
+
className: "max-w-44 rounded border border-input bg-background px-2 py-1 text-sm",
|
|
18
|
+
value: active?.id ?? "",
|
|
19
|
+
onChange: (event) => {
|
|
20
|
+
const id = event.currentTarget.value;
|
|
21
|
+
if (id === "__history") onHistory();
|
|
22
|
+
else if (versions.some((version) => version.id === id)) onOpen(id);
|
|
23
|
+
},
|
|
24
|
+
children: [
|
|
25
|
+
!active && /* @__PURE__ */ jsx("option", { value: "", children: pendingVersion ? `v${pendingVersion} \xB7 ${isSnapshot ? "Read only" : "Current"}` : "Version unavailable" }),
|
|
26
|
+
[...versions].sort((a, b) => b.number - a.number).map((version) => /* @__PURE__ */ jsxs("option", { value: version.id, children: [
|
|
27
|
+
"v",
|
|
28
|
+
version.number,
|
|
29
|
+
version.isCurrent ? " \xB7 Current" : " \xB7 Read only"
|
|
30
|
+
] }, version.id)),
|
|
31
|
+
/* @__PURE__ */ jsx("option", { value: "__history", children: "Version history\u2026" })
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
VersionDropdown
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=VersionDropdown.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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"],
|
|
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
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -68,9 +68,12 @@ function ViewerPdfPane({
|
|
|
68
68
|
}
|
|
69
69
|
const loadingLabel = isVideo ? "Loading video..." : isAudio ? "Loading audio..." : isImage ? "Loading image..." : !documentData ? "Loading document..." : friendlyFileType(documentData.file_type, documentData.file_name) === "Text" ? "Loading text..." : "Loading PDF...";
|
|
70
70
|
const errorLabel = isVideo ? "Failed to load video" : isAudio ? "Failed to load audio" : isImage ? "Failed to load image" : "Failed to load PDF";
|
|
71
|
-
if (isDocx && documentData && !["completed", "low-content", "failed"].includes(documentData.status || "")) {
|
|
71
|
+
if (isDocx && !pdfSnapshotNumber && documentData && !["completed", "low-content", "failed"].includes(documentData.status || "")) {
|
|
72
72
|
return /* @__PURE__ */ jsx(ViewerMessage, { children: "PDF and search indexing are processing. Open the DOCX tab to edit now." });
|
|
73
73
|
}
|
|
74
|
+
if (isDocx && !pdfSnapshotNumber && documentData?.status === "failed") {
|
|
75
|
+
return /* @__PURE__ */ jsx(ViewerMessage, { children: "PDF conversion failed. Open the Word editor or download the document." });
|
|
76
|
+
}
|
|
74
77
|
if (isPdfLoading) return /* @__PURE__ */ jsx(ViewerMessage, { children: loadingLabel });
|
|
75
78
|
if (pdfError) {
|
|
76
79
|
return /* @__PURE__ */ jsx(
|
|
@@ -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 { useViewerIsDetached } from './support'\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)\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 return <KitPdfViewer {...props} onPageChange={onPageChange} disableFontFace={!!isDetached} />\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 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 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 // 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 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 (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 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 // 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 { useViewerIsDetached } from './support'\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)\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 return <KitPdfViewer {...props} onPageChange={onPageChange} disableFontFace={!!isDetached} />\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 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 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 // 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 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 // 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
|
}
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
import type { ViewedDocument } from './useViewedDocument';
|
|
7
7
|
/** `documentId` may be a version reference (`doc-…@v2`). */
|
|
8
8
|
export declare function useViewerBlobs(documentId: string, doc: ViewedDocument): {
|
|
9
|
-
pdfBlob: Blob | null;
|
|
9
|
+
pdfBlob: NoInfer<Blob> | null;
|
|
10
|
+
pdfVerified: boolean;
|
|
11
|
+
retryPdf: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NoInfer<Blob>, Error>>;
|
|
10
12
|
isPdfLoading: boolean;
|
|
11
13
|
pdfError: Error | null;
|
|
12
14
|
xlsxBlob: NoInfer<Blob> | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback, useEffect
|
|
2
|
+
import { useCallback, useEffect } from "react";
|
|
3
3
|
import { hasVideoTrack, loadOfflineDocument } from "@arbidocs/react";
|
|
4
4
|
import { parseVersionRef } from "@arbidocs/react/artifacts";
|
|
5
5
|
import {
|
|
@@ -9,26 +9,30 @@ import {
|
|
|
9
9
|
} from "@arbidocs/react/document-tools";
|
|
10
10
|
import { isAudioFile, isImageFile, isVideoFile } from "@arbidocs/react/ui";
|
|
11
11
|
import { useBlocksEnvironment } from "../../provider/environment.js";
|
|
12
|
+
const offlineCopies = /* @__PURE__ */ new WeakSet();
|
|
12
13
|
function useViewerBlobs(documentId, doc) {
|
|
13
14
|
const { documentData, isArtifact, isDocx, isXlsx, isDownloadOnly, isWebmFile } = doc;
|
|
14
15
|
const { setWebmHasVideoTrack } = doc;
|
|
15
16
|
const { client, saveFile } = useDocumentTools();
|
|
16
17
|
const { notify } = useBlocksEnvironment();
|
|
17
18
|
const currentVersion = documentData?.current_version ?? 1;
|
|
19
|
+
const snapshot = !!parseVersionRef(documentId).version;
|
|
18
20
|
const name = documentData?.file_name;
|
|
19
21
|
const original = isImageFile(name) || isVideoFile(name) || isAudioFile(name);
|
|
20
|
-
const fallback = documentData && !
|
|
22
|
+
const fallback = documentData && !snapshot ? async () => {
|
|
23
|
+
const blob = await loadOfflineDocument(documentData.external_id);
|
|
24
|
+
if (blob) offlineCopies.add(blob);
|
|
25
|
+
return blob;
|
|
26
|
+
} : void 0;
|
|
21
27
|
const pdf = useDocumentBytes(documentId, {
|
|
22
28
|
version: currentVersion,
|
|
23
29
|
kind: original ? "original" : "pdf",
|
|
24
|
-
enabled: !isArtifact && !!documentData && !isDownloadOnly && (!isDocx || documentData.status === "completed" || documentData.status === "low-content"),
|
|
30
|
+
enabled: (!isArtifact || isDocx && !doc.isDraft && !doc.isStreaming && !doc.liveKind) && !!documentData && !isDownloadOnly && (!isDocx || snapshot || documentData.status === "completed" || documentData.status === "low-content"),
|
|
25
31
|
fallback
|
|
26
32
|
});
|
|
27
|
-
const [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (pdf.data) setPdfBlob(pdf.data);
|
|
31
|
-
}, [pdf.data]);
|
|
33
|
+
const pdfReady = !isDocx || snapshot || ["completed", "low-content"].includes(documentData?.status || "");
|
|
34
|
+
const pdfBlob = pdfReady && !pdf.isPlaceholderData ? pdf.data ?? null : null;
|
|
35
|
+
const pdfVerified = !!pdfBlob && !offlineCopies.has(pdfBlob);
|
|
32
36
|
useEffect(() => {
|
|
33
37
|
if (!isWebmFile || !pdfBlob) return;
|
|
34
38
|
let cancelled = false;
|
|
@@ -53,6 +57,8 @@ function useViewerBlobs(documentId, doc) {
|
|
|
53
57
|
}, [client, saveFile, notify, documentId, documentData?.file_name]);
|
|
54
58
|
return {
|
|
55
59
|
pdfBlob,
|
|
60
|
+
pdfVerified,
|
|
61
|
+
retryPdf: pdf.refetch,
|
|
56
62
|
isPdfLoading: pdf.isLoading,
|
|
57
63
|
pdfError: pdf.error,
|
|
58
64
|
xlsxBlob: xlsx.data ?? null,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/connection/viewer/useViewerBlobs.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * The bytes the document viewer shows: the PDF (or, for media, the stored file), with the host's\n * copy kept on the device when the network is down; the stored sheet; the `.webm` track probe; and\n * downloading the stored file.\n */\n\nimport { useCallback, useEffect
|
|
5
|
-
"mappings": ";AAMA,SAAS,aAAa,
|
|
4
|
+
"sourcesContent": ["/**\n * The bytes the document viewer shows: the PDF (or, for media, the stored file), with the host's\n * copy kept on the device when the network is down; the stored sheet; the `.webm` track probe; and\n * downloading the stored file.\n */\n\nimport { useCallback, useEffect } from 'react'\nimport { hasVideoTrack, loadOfflineDocument } from '@arbidocs/react'\nimport { parseVersionRef } from '@arbidocs/react/artifacts'\nimport {\n fetchDocumentFile,\n useDocumentBytes,\n useDocumentTools,\n} from '@arbidocs/react/document-tools'\nimport { isAudioFile, isImageFile, isVideoFile } from '@arbidocs/react/ui'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport type { ViewedDocument } from './useViewedDocument'\n\n// Offline copies predate version metadata; they are useful to read but not safe for signing.\nconst offlineCopies = new WeakSet<Blob>()\n\n/** `documentId` may be a version reference (`doc-\u2026@v2`). */\nexport function useViewerBlobs(documentId: string, doc: ViewedDocument) {\n const { documentData, isArtifact, isDocx, isXlsx, isDownloadOnly, isWebmFile } = doc\n const { setWebmHasVideoTrack } = doc\n const { client, saveFile } = useDocumentTools()\n const { notify } = useBlocksEnvironment()\n const currentVersion = documentData?.current_version ?? 1\n const snapshot = !!parseVersionRef(documentId).version\n\n // Images, video and audio show the stored file; everything else its PDF.\n const name = documentData?.file_name\n const original = isImageFile(name) || isVideoFile(name) || isAudioFile(name)\n // Offline records have no version identity; keep them readable but mark them unverified.\n const fallback =\n documentData && !snapshot\n ? async () => {\n const blob = await loadOfflineDocument(documentData.external_id)\n if (blob) offlineCopies.add(blob)\n return blob\n }\n : undefined\n const pdf = useDocumentBytes(documentId, {\n version: currentVersion,\n kind: original ? 'original' : 'pdf',\n enabled:\n (!isArtifact || (isDocx && !doc.isDraft && !doc.isStreaming && !doc.liveKind)) &&\n !!documentData &&\n !isDownloadOnly &&\n (!isDocx ||\n snapshot ||\n documentData.status === 'completed' ||\n documentData.status === 'low-content'),\n fallback,\n })\n // The query is keyed by version. Never keep an older PDF while the new version processes:\n // the viewer also offers signing actions against the displayed bytes.\n const pdfReady =\n !isDocx || snapshot || ['completed', 'low-content'].includes(documentData?.status || '')\n const pdfBlob = pdfReady && !pdf.isPlaceholderData ? (pdf.data ?? null) : null\n const pdfVerified = !!pdfBlob && !offlineCopies.has(pdfBlob)\n\n // Resolve the ambiguous .webm case once the bytes are here.\n useEffect(() => {\n if (!isWebmFile || !pdfBlob) return\n let cancelled = false\n void hasVideoTrack(pdfBlob).then((result) => {\n if (!cancelled) setWebmHasVideoTrack(result)\n })\n return () => {\n cancelled = true\n }\n }, [isWebmFile, pdfBlob, setWebmHasVideoTrack])\n\n // The stored sheet (all its sheets).\n const xlsx = useDocumentBytes(documentId, {\n version: currentVersion,\n kind: 'original',\n enabled: !isArtifact && !!documentData && isXlsx,\n })\n\n const handleDirectDownload = useCallback(async () => {\n try {\n saveFile(await fetchDocumentFile(client, documentId), documentData?.file_name || 'download')\n } catch {\n notify('Failed to download file', 'error')\n }\n }, [client, saveFile, notify, documentId, documentData?.file_name])\n\n return {\n pdfBlob,\n pdfVerified,\n retryPdf: pdf.refetch,\n isPdfLoading: pdf.isLoading,\n pdfError: pdf.error,\n xlsxBlob: xlsx.data ?? null,\n xlsxError: xlsx.error,\n handleDirectDownload,\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAMA,SAAS,aAAa,iBAAiB;AACvC,SAAS,eAAe,2BAA2B;AACnD,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa,aAAa,mBAAmB;AACtD,SAAS,4BAA4B;AAIrC,MAAM,gBAAgB,oBAAI,QAAc;AAGjC,SAAS,eAAe,YAAoB,KAAqB;AACtE,QAAM,EAAE,cAAc,YAAY,QAAQ,QAAQ,gBAAgB,WAAW,IAAI;AACjF,QAAM,EAAE,qBAAqB,IAAI;AACjC,QAAM,EAAE,QAAQ,SAAS,IAAI,iBAAiB;AAC9C,QAAM,EAAE,OAAO,IAAI,qBAAqB;AACxC,QAAM,iBAAiB,cAAc,mBAAmB;AACxD,QAAM,WAAW,CAAC,CAAC,gBAAgB,UAAU,EAAE;AAG/C,QAAM,OAAO,cAAc;AAC3B,QAAM,WAAW,YAAY,IAAI,KAAK,YAAY,IAAI,KAAK,YAAY,IAAI;AAE3E,QAAM,WACJ,gBAAgB,CAAC,WACb,YAAY;AACV,UAAM,OAAO,MAAM,oBAAoB,aAAa,WAAW;AAC/D,QAAI,KAAM,eAAc,IAAI,IAAI;AAChC,WAAO;AAAA,EACT,IACA;AACN,QAAM,MAAM,iBAAiB,YAAY;AAAA,IACvC,SAAS;AAAA,IACT,MAAM,WAAW,aAAa;AAAA,IAC9B,UACG,CAAC,cAAe,UAAU,CAAC,IAAI,WAAW,CAAC,IAAI,eAAe,CAAC,IAAI,aACpE,CAAC,CAAC,gBACF,CAAC,mBACA,CAAC,UACA,YACA,aAAa,WAAW,eACxB,aAAa,WAAW;AAAA,IAC5B;AAAA,EACF,CAAC;AAGD,QAAM,WACJ,CAAC,UAAU,YAAY,CAAC,aAAa,aAAa,EAAE,SAAS,cAAc,UAAU,EAAE;AACzF,QAAM,UAAU,YAAY,CAAC,IAAI,oBAAqB,IAAI,QAAQ,OAAQ;AAC1E,QAAM,cAAc,CAAC,CAAC,WAAW,CAAC,cAAc,IAAI,OAAO;AAG3D,YAAU,MAAM;AACd,QAAI,CAAC,cAAc,CAAC,QAAS;AAC7B,QAAI,YAAY;AAChB,SAAK,cAAc,OAAO,EAAE,KAAK,CAAC,WAAW;AAC3C,UAAI,CAAC,UAAW,sBAAqB,MAAM;AAAA,IAC7C,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,YAAY,SAAS,oBAAoB,CAAC;AAG9C,QAAM,OAAO,iBAAiB,YAAY;AAAA,IACxC,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS,CAAC,cAAc,CAAC,CAAC,gBAAgB;AAAA,EAC5C,CAAC;AAED,QAAM,uBAAuB,YAAY,YAAY;AACnD,QAAI;AACF,eAAS,MAAM,kBAAkB,QAAQ,UAAU,GAAG,cAAc,aAAa,UAAU;AAAA,IAC7F,QAAQ;AACN,aAAO,2BAA2B,OAAO;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,QAAQ,YAAY,cAAc,SAAS,CAAC;AAElE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,UAAU,IAAI;AAAA,IACd,UAAU,KAAK,QAAQ;AAAA,IACvB,WAAW,KAAK;AAAA,IAChB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,8 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
|
|
|
20
20
|
const {
|
|
21
21
|
documentData,
|
|
22
22
|
isArtifact,
|
|
23
|
+
isDraft,
|
|
24
|
+
isStreaming,
|
|
23
25
|
isDocx,
|
|
24
26
|
isXlsx,
|
|
25
27
|
isEmail,
|
|
@@ -124,6 +126,14 @@ function useViewerTabs(doc, isCompact, hasHistory = false) {
|
|
|
124
126
|
tooltip: liveKind ? "Code" : "Editor",
|
|
125
127
|
label: tabLabel("edit", liveKind ? "Code" : "Document")
|
|
126
128
|
},
|
|
129
|
+
...!liveKind && !isDraft && !isStreaming && isDocx ? [
|
|
130
|
+
{
|
|
131
|
+
id: "pdf",
|
|
132
|
+
icon: /* @__PURE__ */ jsx(PdfIcon, { size: 20 }),
|
|
133
|
+
tooltip: "PDF",
|
|
134
|
+
label: tabLabel("pdf", "PDF")
|
|
135
|
+
}
|
|
136
|
+
] : [],
|
|
127
137
|
versionsTab
|
|
128
138
|
] : [
|
|
129
139
|
...isDocx ? [
|