@arbidocs/blocks 0.5.115 → 0.5.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs → ConnectedNativeDocxComparison-546ILGLW.cjs} +8 -8
- package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs.map → ConnectedNativeDocxComparison-546ILGLW.cjs.map} +1 -1
- package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs} +8 -8
- package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs.map → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs.map} +1 -1
- package/dist/{FilesViewerDialog-I5QIHQZT.cjs → FilesViewerDialog-6UKR5WEF.cjs} +6 -6
- package/dist/{FilesViewerDialog-I5QIHQZT.cjs.map → FilesViewerDialog-6UKR5WEF.cjs.map} +1 -1
- package/dist/{NativeDocxEditor-H6TAEVGY.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
- package/dist/{NativeDocxEditor-H6TAEVGY.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
- package/dist/{chunk-M6IKVKU5.cjs → chunk-2CSLFAGF.cjs} +392 -149
- package/dist/chunk-2CSLFAGF.cjs.map +1 -0
- package/dist/{chunk-24EDG4PC.cjs → chunk-B2HNNG25.cjs} +5 -5
- package/dist/{chunk-24EDG4PC.cjs.map → chunk-B2HNNG25.cjs.map} +1 -1
- package/dist/{chunk-IW7CDJTA.cjs → chunk-COD5ENHK.cjs} +4 -4
- package/dist/{chunk-IW7CDJTA.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
- package/dist/chunk-HB2O4THB.cjs +18 -0
- package/dist/{chunk-CIHERNDO.cjs.map → chunk-HB2O4THB.cjs.map} +1 -1
- package/dist/{chunk-WR2SF44W.cjs → chunk-NIE3N6OM.cjs} +4 -4
- package/dist/{chunk-WR2SF44W.cjs.map → chunk-NIE3N6OM.cjs.map} +1 -1
- package/dist/{chunk-ZTXQIIFV.cjs → chunk-QHOHDNBU.cjs} +6 -6
- package/dist/{chunk-ZTXQIIFV.cjs.map → chunk-QHOHDNBU.cjs.map} +1 -1
- package/dist/{chunk-A3T3IC3K.cjs → chunk-SB4M3ITT.cjs} +190 -36
- package/dist/chunk-SB4M3ITT.cjs.map +1 -0
- package/dist/{chunk-X5LANJDZ.cjs → chunk-VGCTYTEW.cjs} +14 -6
- package/dist/chunk-VGCTYTEW.cjs.map +1 -0
- package/dist/{chunk-3A7QWUAW.cjs → chunk-VKH3BEZE.cjs} +3 -3
- package/dist/{chunk-3A7QWUAW.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
- package/dist/{chunk-42TURFHF.cjs → chunk-YGBHY67W.cjs} +5 -5
- package/dist/{chunk-42TURFHF.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
- package/dist/connect/docx.cjs +12 -12
- package/dist/connect/index.cjs +78 -78
- package/dist/connect/viewer.cjs +4 -4
- 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/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 +51 -12
- 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 +3 -1
- package/dist/docx/signatures/SignatureFields.js +17 -8
- package/dist/docx/signatures/SignatureFields.js.map +2 -2
- package/dist/index.cjs +50 -50
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +9 -9
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/src/docx/styles.css +94 -0
- package/dist/chunk-A3T3IC3K.cjs.map +0 -1
- package/dist/chunk-CIHERNDO.cjs +0 -18
- package/dist/chunk-M6IKVKU5.cjs.map +0 -1
- package/dist/chunk-X5LANJDZ.cjs.map +0 -1
|
@@ -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 ? [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/connection/viewer/useViewerTabs.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n { id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) },\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * Tabs of the document viewer: which tabs a document has, the automatic switches when the\n * document's type or parsed content changes, and switching (which ends a comparison when leaving\n * the tab that hosts it). The open tab is the session state's, so whatever opens a document can\n * open it on a tab.\n */\n\nimport { useEffect, useRef } from 'react'\nimport { Code, FileText, History, MonitorPlay } from 'lucide-react'\nimport { friendlyFileType } from '@arbidocs/react/ui'\nimport {\n AudIcon,\n DocIcon,\n EmlIcon,\n HtmlIcon,\n ImgIcon,\n PdfIcon,\n VidIcon,\n XlsIcon,\n useArbiSessionState,\n useArbiSessionStore,\n type ArbiViewerTab,\n} from '@arbidocs/react'\nimport type { ViewerTab } from '../../files/ViewerParts'\nimport { useIsPhone } from '../../lib/use-media-query'\nimport type { ViewedDocument } from './useViewedDocument'\n\n/**\n * @param hasHistory The document has earlier versions (a signed copy, a re-upload): PDF and text\n * documents then get a Versions tab too. Artifacts and Word documents always have one.\n */\nexport function useViewerTabs(doc: ViewedDocument, isCompact: boolean, hasHistory = false) {\n const {\n documentData,\n isArtifact,\n isDraft,\n isStreaming,\n isDocx,\n isXlsx,\n isEmail,\n isVideo,\n isAudio,\n isImage,\n liveKind,\n hasParsedContent,\n isParsedDocLoading,\n } = doc\n const session = useArbiSessionStore()\n const {\n tab: activeTab,\n compareId,\n tabRequest,\n phonePdfChosen,\n } = useArbiSessionState((s) => s.documentViewer)\n const setActiveTab = (tab: ArbiViewerTab) => session.setDocumentViewer({ tab })\n // A plain-text file is still shown as a generated PDF, but the tab names the file the user\n // opened (\"Text\", as the Fields panel does), not the rendering format.\n const isTextFile = friendlyFileType(documentData?.file_type, documentData?.file_name) === 'Text'\n const isPhone = useIsPhone()\n const phoneDefaultDecidedFor = useRef<string | null>(null)\n\n // Switch to the tab that fits the document type. Only on type changes: never over the user's own\n // choice. Keyed on the document and its kind, not on the record: a refreshed record (a new\n // version finishing processing) must not send a user on the PDF tab of a Word document back to\n // the editor.\n const hasDocumentData = !!documentData\n const documentKey = documentData?.external_id\n useEffect(() => {\n // A Word artifact (an AI draft, stored as .docx) has one Word tab, 'edit', not a DOCX tab.\n if (isArtifact && (activeTab === 'pdf' || (!liveKind && activeTab === 'docx'))) {\n setActiveTab(liveKind ? 'preview' : 'edit')\n } else if (isDocx && activeTab === 'pdf') {\n setActiveTab('docx')\n } else if (!liveKind && activeTab === 'preview') {\n setActiveTab(isArtifact ? 'edit' : 'pdf')\n } else if (!isArtifact && documentData && activeTab === 'edit') {\n setActiveTab(isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n } else if (\n !isArtifact &&\n !isDocx &&\n !isXlsx &&\n documentData &&\n (activeTab === 'docx' || activeTab === 'xlsx')\n ) {\n setActiveTab('pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasDocumentData, documentKey, isArtifact, isDocx, isXlsx, liveKind])\n\n // A tab asked for when the document was opened (a signature request opens on the PDF, where it\n // is signed) wins over the type's own tab once that document has loaded, and over the phone's\n // text default. Declared after the type switch above so it has the last word.\n useEffect(() => {\n if (!tabRequest || !documentKey || tabRequest.documentId !== documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n session.setDocumentViewer({ tabRequest: null, tab: tabRequest.tab })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [documentKey, tabRequest])\n\n // Versions of a PDF or text document exist only with history: leave the tab when there is none\n // (another document opened while it was active).\n const hasVersionsTab = isArtifact || isDocx || hasHistory\n useEffect(() => {\n if (activeTab === 'versions' && documentData && !hasVersionsTab) {\n setActiveTab(isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, documentData, hasVersionsTab])\n\n // The text tab exists only with parsed content. When it is open without any (a recording with\n // no transcript, a failed parse), fall back to the natural default once the parsed query\n // settles. Not during a comparison, which uses the text tab. Waits for the record: until it is\n // here the parsed query has not started, so it is not loading yet.\n useEffect(() => {\n if (\n activeTab === 'html' &&\n documentData !== undefined &&\n !isParsedDocLoading &&\n !hasParsedContent &&\n !compareId\n ) {\n setActiveTab(isArtifact ? 'edit' : isDocx ? 'docx' : isXlsx ? 'xlsx' : 'pdf')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n activeTab,\n documentData,\n isParsedDocLoading,\n hasParsedContent,\n compareId,\n isArtifact,\n isDocx,\n isXlsx,\n ])\n\n // Phones open a document on the readable reflowed (text) view: a fit-width PDF on a 390px\n // screen is footnote-sized. Decided once per document, after the parsed query settles, and only\n // over the PDF default (Word, sheets, artifacts and media keep their own tab). A PDF the user\n // picked by hand this session wins.\n useEffect(() => {\n if (!isPhone || !documentKey || isParsedDocLoading) return\n if (phoneDefaultDecidedFor.current === documentKey) return\n phoneDefaultDecidedFor.current = documentKey\n const opensOnPdf =\n !isArtifact && !isDocx && !isXlsx && !isVideo && !isAudio && !isImage && !isEmail\n if (opensOnPdf && hasParsedContent && !compareId && !phonePdfChosen && activeTab === 'pdf') {\n setActiveTab('html')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPhone, documentKey, isParsedDocLoading, hasParsedContent])\n\n const handleTabChange = (tabId: string) => {\n // A comparison is shown on the text tab: leaving it ends the comparison.\n const change: Parameters<typeof session.setDocumentViewer>[0] = { tab: tabId as ArbiViewerTab }\n if (tabId !== 'html' && compareId) change.compareId = null\n // A phone user who goes back to the PDF wants it: stop opening documents on the text view\n // until they pick it again.\n if (isPhone && (tabId === 'pdf' || tabId === 'html')) change.phonePdfChosen = tabId === 'pdf'\n session.setDocumentViewer(change)\n }\n\n const mediaTab = isVideo\n ? { icon: <VidIcon size={20} />, tooltip: 'Video' }\n : isAudio\n ? { icon: <AudIcon size={20} />, tooltip: 'Audio' }\n : isImage\n ? { icon: <ImgIcon size={20} />, tooltip: 'Image' }\n : isEmail\n ? { icon: <EmlIcon size={20} />, tooltip: 'Email' }\n : isTextFile\n ? { icon: <FileText className=\"size-5\" />, tooltip: 'Text' }\n : documentData\n ? { icon: <PdfIcon size={20} />, tooltip: 'PDF' }\n : // The file type is unknown until the record loads: name no guess (a text file\n // would flip from PDF to Text once it arrives).\n { icon: <FileText className=\"size-5\" />, tooltip: 'Document' }\n // Tabs say what they are: in a narrow panel or on a phone only the open tab keeps its name, plus\n // the text view, whose icon is not recognisable. Labelling every tab there would crowd the header.\n const tabLabel = (id: string, label: string) =>\n !isCompact || activeTab === id || id === 'html' ? label : undefined\n\n const versionsTab: ViewerTab = {\n id: 'versions',\n icon: <History className=\"size-5\" />,\n tooltip: 'Versions',\n label: tabLabel('versions', 'Versions'),\n }\n const viewerTabs: ViewerTab[] = [\n ...(isArtifact\n ? [\n ...(liveKind\n ? [\n {\n id: 'preview',\n icon: <MonitorPlay className=\"size-5\" />,\n tooltip: 'Preview',\n label: tabLabel('preview', 'Preview'),\n },\n ]\n : []),\n {\n id: 'edit',\n icon: liveKind ? <Code className=\"size-5\" /> : <FileText className=\"size-5\" />,\n tooltip: liveKind ? 'Code' : 'Editor',\n label: tabLabel('edit', liveKind ? 'Code' : 'Document'),\n },\n ...(!liveKind && !isDraft && !isStreaming && isDocx\n ? [\n {\n id: 'pdf',\n icon: <PdfIcon size={20} />,\n tooltip: 'PDF',\n label: tabLabel('pdf', 'PDF'),\n },\n ]\n : []),\n versionsTab,\n ]\n : [\n ...(isDocx\n ? [\n {\n id: 'docx',\n icon: <DocIcon size={20} />,\n tooltip: 'DOCX (with track changes & comments)',\n label: tabLabel('docx', 'DOCX'),\n },\n ]\n : []),\n ...(isXlsx\n ? [\n {\n id: 'xlsx',\n icon: <XlsIcon size={20} />,\n tooltip: 'Spreadsheet',\n label: tabLabel('xlsx', 'Sheet'),\n },\n ]\n : []),\n { id: 'pdf', ...mediaTab, label: tabLabel('pdf', mediaTab.tooltip) },\n ...(hasVersionsTab ? [versionsTab] : []),\n ]),\n ...((hasParsedContent || compareId) && !liveKind\n ? [\n {\n id: 'html',\n icon: compareId ? <FileText className=\"size-5\" /> : <HtmlIcon size={20} />,\n tooltip: compareId ? 'Word redline' : 'HTML',\n label: tabLabel('html', compareId ? 'Compare' : 'HTML'),\n },\n ]\n : []),\n ]\n\n return { activeTab, handleTabChange, viewerTabs }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type DocxImageGeneration } from './layout/GenerateImage';
|
|
3
|
+
/** One editing menu, with named categories and the existing editor commands. */
|
|
4
|
+
export declare function DocxCommandMenu({ onSave, badge, imageGeneration, }: {
|
|
5
|
+
onSave: () => void;
|
|
6
|
+
badge?: React.ReactNode;
|
|
7
|
+
imageGeneration?: DocxImageGeneration;
|
|
8
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { DocxEditor, useChromeTranslate } from "@docx-editor.dev/react";
|
|
5
|
+
import {
|
|
6
|
+
BookA,
|
|
7
|
+
ChevronDown,
|
|
8
|
+
FilePenLine,
|
|
9
|
+
Home,
|
|
10
|
+
Image,
|
|
11
|
+
LayoutGrid,
|
|
12
|
+
ListChecks,
|
|
13
|
+
Menu,
|
|
14
|
+
Plus,
|
|
15
|
+
Table,
|
|
16
|
+
UsersRound
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import { useDefinedTerms } from "./definitions/DefinedTerms.js";
|
|
19
|
+
import { RibbonMenu } from "./RibbonMenu.js";
|
|
20
|
+
import { NamedCommandList, RibbonItem } from "./RibbonOverflow.js";
|
|
21
|
+
import { StyleGallery } from "./StyleGallery.js";
|
|
22
|
+
import { NoteButtons } from "./WordReferences.js";
|
|
23
|
+
import { CrossReferenceButton, UpdateCrossReferencesButton } from "./references/EditorMenus.js";
|
|
24
|
+
import { LayoutTabContent, LAYOUT_TAB, useContextualTabs } from "./layout/LayoutTabs.js";
|
|
25
|
+
import {
|
|
26
|
+
GenerateImageButton,
|
|
27
|
+
useGenerateImageTarget
|
|
28
|
+
} from "./layout/GenerateImage.js";
|
|
29
|
+
import { QuickParts } from "./template/QuickParts.js";
|
|
30
|
+
import { HouseTemplatePanel } from "./template/HouseTemplatePanel.js";
|
|
31
|
+
import { MySignatureMenu, SignatureFieldMenu } from "./signatures/SignatureFields.js";
|
|
32
|
+
function DefinedTermButton() {
|
|
33
|
+
const terms = useDefinedTerms();
|
|
34
|
+
if (!terms) return null;
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
type: "button",
|
|
39
|
+
className: "native-docx-ribbon-trigger",
|
|
40
|
+
"aria-label": terms.labels.insert,
|
|
41
|
+
title: `${terms.labels.insert} (type @@)`,
|
|
42
|
+
"data-testid": "docx-insert-defined-term",
|
|
43
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
44
|
+
onClick: (event) => terms.openPicker(event.currentTarget),
|
|
45
|
+
children: /* @__PURE__ */ jsx(BookA, { size: 16 })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const categories = [
|
|
50
|
+
{ name: "Home", icon: Home },
|
|
51
|
+
{ name: "Insert", icon: Plus },
|
|
52
|
+
{ name: "Design", icon: FilePenLine },
|
|
53
|
+
{ name: LAYOUT_TAB, icon: LayoutGrid },
|
|
54
|
+
{ name: "References", icon: BookA },
|
|
55
|
+
{ name: "Review", icon: ListChecks }
|
|
56
|
+
];
|
|
57
|
+
function DocxCommandMenu({
|
|
58
|
+
onSave,
|
|
59
|
+
badge,
|
|
60
|
+
imageGeneration
|
|
61
|
+
}) {
|
|
62
|
+
const [selected, setSelected] = useState("Home");
|
|
63
|
+
const contextual = useContextualTabs(selected);
|
|
64
|
+
const tab = contextual.shown;
|
|
65
|
+
const t = useChromeTranslate();
|
|
66
|
+
useGenerateImageTarget();
|
|
67
|
+
const allCategories = [
|
|
68
|
+
...categories,
|
|
69
|
+
...contextual.tabs.map((name) => ({ name, icon: name === "Table" ? Table : Image }))
|
|
70
|
+
];
|
|
71
|
+
return /* @__PURE__ */ jsxs("div", { className: "native-docx-ribbon native-docx-command-menu", children: [
|
|
72
|
+
/* @__PURE__ */ jsxs(DocxEditor.Toolbar, { t, preset: false, onSave, children: [
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
RibbonMenu,
|
|
75
|
+
{
|
|
76
|
+
label: "Editing tools",
|
|
77
|
+
icon: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
78
|
+
/* @__PURE__ */ jsx(Menu, { size: 16 }),
|
|
79
|
+
/* @__PURE__ */ jsx("span", { children: "Editing tools" }),
|
|
80
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: 14 })
|
|
81
|
+
] }),
|
|
82
|
+
className: "native-docx-command-trigger",
|
|
83
|
+
popoverClassName: "native-docx-command-panel",
|
|
84
|
+
keepMounted: true,
|
|
85
|
+
restoreFocus: true,
|
|
86
|
+
children: (close) => /* @__PURE__ */ jsxs("div", { className: "native-docx-command-layout", children: [
|
|
87
|
+
/* @__PURE__ */ jsx("nav", { className: "native-docx-command-categories", "aria-label": "Editing tool categories", children: allCategories.map(({ name, icon: Icon }) => /* @__PURE__ */ jsxs(
|
|
88
|
+
"button",
|
|
89
|
+
{
|
|
90
|
+
type: "button",
|
|
91
|
+
"aria-pressed": tab === name,
|
|
92
|
+
onClick: () => setSelected(name),
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx(Icon, { size: 16, "aria-hidden": "true" }),
|
|
95
|
+
/* @__PURE__ */ jsx("span", { children: name })
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
name
|
|
99
|
+
)) }),
|
|
100
|
+
/* @__PURE__ */ jsx(
|
|
101
|
+
"div",
|
|
102
|
+
{
|
|
103
|
+
className: "native-docx-command-list",
|
|
104
|
+
role: "group",
|
|
105
|
+
"aria-label": `${tab} commands`,
|
|
106
|
+
onClick: (event) => {
|
|
107
|
+
const target = event.target;
|
|
108
|
+
const button = target.closest("button");
|
|
109
|
+
const item = target.closest("[data-ribbon-item]")?.dataset.ribbonItem;
|
|
110
|
+
const direct = /* @__PURE__ */ new Set([
|
|
111
|
+
"home-undo",
|
|
112
|
+
"home-redo",
|
|
113
|
+
"home-save",
|
|
114
|
+
"home-bold",
|
|
115
|
+
"home-italic",
|
|
116
|
+
"home-underline",
|
|
117
|
+
"home-bullets",
|
|
118
|
+
"home-numbers",
|
|
119
|
+
"home-indent",
|
|
120
|
+
"home-outdent",
|
|
121
|
+
"home-strike",
|
|
122
|
+
"home-clear",
|
|
123
|
+
"references-footnote",
|
|
124
|
+
"references-endnote",
|
|
125
|
+
"references-update-cross-references",
|
|
126
|
+
"table-row-above",
|
|
127
|
+
"table-row-below",
|
|
128
|
+
"table-column-left",
|
|
129
|
+
"table-column-right"
|
|
130
|
+
]);
|
|
131
|
+
if ((!button || !button.disabled) && target.closest('[aria-disabled="true"]') === null && (button && item && direct.has(item) || target.closest('[role="gridcell"]') || target.closest('[role="menuitemradio"]') || target.closest('[data-testid="docx-insert-my-signature"]') || target.closest('[data-testid="docx-insert-my-initials"]') || target.closest('.native-docx-style-gallery [role="option"]') || button && button.closest(".native-docx-style-gallery"))) {
|
|
132
|
+
close();
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
children: /* @__PURE__ */ jsxs(NamedCommandList, { children: [
|
|
136
|
+
tab === "Home" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
137
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-undo", label: "Undo", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Undo, {}) }),
|
|
138
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-redo", label: "Redo", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Redo, {}) }),
|
|
139
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-save", label: "Save", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Save, {}) }),
|
|
140
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-style", label: "Styles", children: /* @__PURE__ */ jsx(StyleGallery, {}) }),
|
|
141
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-bold", label: "Bold", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Bold, {}) }),
|
|
142
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-italic", label: "Italic", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Italic, {}) }),
|
|
143
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-underline", label: "Underline", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Underline, {}) }),
|
|
144
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-font-family", label: "Font family", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontFamily, {}) }),
|
|
145
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-font-size", label: "Font size", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontSize, {}) }),
|
|
146
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-font-color", label: "Font color", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.FontColor, {}) }),
|
|
147
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-highlight", label: "Highlight", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Highlight, {}) }),
|
|
148
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-alignment", label: "Alignment", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Alignment, {}) }),
|
|
149
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-bullets", label: "Bulleted list", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.BulletList, {}) }),
|
|
150
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-numbers", label: "Numbered list", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.NumberedList, {}) }),
|
|
151
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-line-spacing", label: "Line spacing", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.LineSpacing, {}) }),
|
|
152
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-indent", label: "Increase indent", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Indent, {}) }),
|
|
153
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-outdent", label: "Decrease indent", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Outdent, {}) }),
|
|
154
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-strike", label: "Strikethrough", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Strike, {}) }),
|
|
155
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "home-clear", label: "Clear formatting", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.ClearFormatting, {}) })
|
|
156
|
+
] }),
|
|
157
|
+
tab === "Insert" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
158
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-table", label: "Table", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableInsert, {}) }),
|
|
159
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-picture", label: "Picture", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageInsert, {}) }),
|
|
160
|
+
imageGeneration && /* @__PURE__ */ jsx(RibbonItem, { id: "insert-generate-image", label: "Generate image", children: /* @__PURE__ */ jsx(GenerateImageButton, { generation: imageGeneration }) }),
|
|
161
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-page-break", label: "Page break", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }) }),
|
|
162
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-link", label: "Link", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Link, {}) }),
|
|
163
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-defined-term", label: "Defined term", children: /* @__PURE__ */ jsx(DefinedTermButton, {}) }),
|
|
164
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-quick-parts", label: "Quick Parts", children: /* @__PURE__ */ jsx(QuickParts, {}) }),
|
|
165
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-signature-field", label: "Signature field", children: /* @__PURE__ */ jsx(SignatureFieldMenu, { onInserted: close }) }),
|
|
166
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-my-signature", label: "My signature", children: /* @__PURE__ */ jsx(MySignatureMenu, {}) }),
|
|
167
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) })
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ jsx(LayoutTabContent, { tab }),
|
|
170
|
+
tab === "Design" && /* @__PURE__ */ jsx(RibbonItem, { id: "design-house-template", label: "House template", children: /* @__PURE__ */ jsx(HouseTemplatePanel, {}) }),
|
|
171
|
+
tab === "References" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
172
|
+
/* @__PURE__ */ jsx(NoteButtons, {}),
|
|
173
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "references-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) }),
|
|
174
|
+
/* @__PURE__ */ jsx(
|
|
175
|
+
RibbonItem,
|
|
176
|
+
{
|
|
177
|
+
id: "references-update-cross-references",
|
|
178
|
+
label: "Update cross-references",
|
|
179
|
+
children: /* @__PURE__ */ jsx(UpdateCrossReferencesButton, {})
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
] }),
|
|
183
|
+
tab === "Review" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
184
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "review-editing-mode", label: "Editing mode", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.EditingMode, {}) }),
|
|
185
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "review-comments", label: "Comments", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Comments, {}) }),
|
|
186
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "review-options", label: "Review options", children: /* @__PURE__ */ jsx(RibbonMenu, { label: "Review options", icon: /* @__PURE__ */ jsx(UsersRound, { size: 16 }), children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Reviewers, {}) }) })
|
|
187
|
+
] })
|
|
188
|
+
] })
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
] })
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
/* @__PURE__ */ jsx(DocxEditor.Toolbar.TableCellFill, { hidden: true })
|
|
195
|
+
] }),
|
|
196
|
+
badge && /* @__PURE__ */ jsx("span", { className: "native-docx-ribbon-badge", "data-testid": "docx-ribbon-badge", children: badge })
|
|
197
|
+
] });
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
DocxCommandMenu
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=DocxCommandMenu.js.map
|