@arbidocs/blocks 0.4.68 → 0.4.70
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/README.md +85 -1
- package/dist/agents/index.cjs +220 -220
- package/dist/agents/index.js +4 -4
- package/dist/chat/index.cjs +66 -66
- package/dist/chat/index.js +2 -2
- package/dist/chunk-4DVEGXZQ.cjs +72 -0
- package/dist/chunk-4DVEGXZQ.cjs.map +1 -0
- package/dist/{chunk-5ZZCS2EK.cjs → chunk-7M22KND4.cjs} +5 -5
- package/dist/{chunk-5ZZCS2EK.cjs.map → chunk-7M22KND4.cjs.map} +1 -1
- package/dist/{chunk-ZQB7HNE6.js → chunk-BMWZTNZB.js} +3 -3
- package/dist/{chunk-ZQB7HNE6.js.map → chunk-BMWZTNZB.js.map} +1 -1
- package/dist/{chunk-FAVN6VUR.js → chunk-HLMFU7L2.js} +5 -5
- package/dist/{chunk-FAVN6VUR.js.map → chunk-HLMFU7L2.js.map} +1 -1
- package/dist/chunk-ODWCTAH7.js +66 -0
- package/dist/chunk-ODWCTAH7.js.map +1 -0
- package/dist/{chunk-WKNAFILY.cjs → chunk-XNRGCQPZ.cjs} +3 -3
- package/dist/{chunk-WKNAFILY.cjs.map → chunk-XNRGCQPZ.cjs.map} +1 -1
- package/dist/document-tools/DocumentToolButtons.d.ts +29 -0
- package/dist/document-tools/MarkupNotices.d.ts +12 -0
- package/dist/document-tools/MarkupViewNote.d.ts +11 -0
- package/dist/document-tools/SignDocumentDialog.d.ts +20 -0
- package/dist/document-tools/SignatureCertificate.d.ts +26 -0
- package/dist/document-tools/SignatureStatus.d.ts +22 -0
- package/dist/document-tools/VersionSnapshotBar.d.ts +27 -0
- package/dist/document-tools/index.cjs +633 -0
- package/dist/document-tools/index.cjs.map +1 -0
- package/dist/document-tools/index.d.ts +7 -0
- package/dist/document-tools/index.js +619 -0
- package/dist/document-tools/index.js.map +1 -0
- package/dist/document-tools/viewer/AnnotatedPdfViewer.d.ts +54 -0
- package/dist/document-tools/viewer/SignaturePlacementViewer.d.ts +20 -0
- package/dist/document-tools/viewer/index.cjs +273 -0
- package/dist/document-tools/viewer/index.cjs.map +1 -0
- package/dist/document-tools/viewer/index.d.ts +2 -0
- package/dist/document-tools/viewer/index.js +268 -0
- package/dist/document-tools/viewer/index.js.map +1 -0
- package/dist/facts/index.cjs +1 -1
- package/dist/facts/index.js +1 -1
- package/dist/files/cells/DocumentNameCell.d.ts +3 -1
- package/dist/files/index.cjs +38 -67
- package/dist/files/index.cjs.map +1 -1
- package/dist/files/index.js +19 -63
- package/dist/files/index.js.map +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +651 -651
- package/dist/index.js +10 -10
- package/dist/settings/index.cjs +2 -2
- package/dist/settings/index.js +2 -2
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.js +1 -1
- package/package.json +20 -4
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useMemo, useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useAnnotationLayer, redactionLogCsv, AnnotationPageOverlay, AnnotationToolbar, FreezeDialog, createMemoryStore } from '@arbidocs/react/annotations';
|
|
4
|
+
import { freezePdfInBrowser } from '@arbidocs/react/annotations/freeze';
|
|
5
|
+
import { useDocumentTools, useIsOnline, createMarkupStore, fetchMarkupPdf, uploadFrozenCopy, redactionLogName, SIGNED_LOCKED_REASON, isLegibleSignatureBox, toAppearance } from '@arbidocs/react/document-tools';
|
|
6
|
+
import { PdfViewer } from '@arbidocs/react/viewers';
|
|
7
|
+
import { Download } from 'lucide-react';
|
|
8
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
9
|
+
import { Button } from '@arbidocs/react/ui';
|
|
10
|
+
|
|
11
|
+
// src/document-tools/viewer/AnnotatedPdfViewer.tsx
|
|
12
|
+
var MARKUP_AUTOSAVE_MS = 2500;
|
|
13
|
+
var MARKUP_PULL_MS = 2e4;
|
|
14
|
+
var FALLBACK_AUTHOR = "You";
|
|
15
|
+
function viewOnly(controller) {
|
|
16
|
+
return { ...controller, readOnly: true, tool: "select", setTool: () => {
|
|
17
|
+
} };
|
|
18
|
+
}
|
|
19
|
+
function AnnotatedPdfViewer({
|
|
20
|
+
file,
|
|
21
|
+
documentId,
|
|
22
|
+
version,
|
|
23
|
+
fileName,
|
|
24
|
+
shared = false,
|
|
25
|
+
folder,
|
|
26
|
+
editing = true,
|
|
27
|
+
onMarkupChange,
|
|
28
|
+
store: storeOverride,
|
|
29
|
+
viewer: PdfViewer$1 = PdfViewer,
|
|
30
|
+
signed = false,
|
|
31
|
+
...viewerProps
|
|
32
|
+
}) {
|
|
33
|
+
const { client, user, notify, saveFile, uploadDocument, openDocument, onDocumentsChanged } = useDocumentTools();
|
|
34
|
+
const online = useIsOnline();
|
|
35
|
+
const onChangeRef = useRef(onMarkupChange);
|
|
36
|
+
onChangeRef.current = onMarkupChange;
|
|
37
|
+
const store = useMemo(
|
|
38
|
+
() => storeOverride ?? createMarkupStore({
|
|
39
|
+
version,
|
|
40
|
+
client,
|
|
41
|
+
onSaved: (snapshot) => onChangeRef.current?.(snapshot)
|
|
42
|
+
}),
|
|
43
|
+
// A new store per document version: its revision and tombstones belong to that markup.
|
|
44
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
45
|
+
[storeOverride, client, documentId, version]
|
|
46
|
+
);
|
|
47
|
+
const author = user?.name || FALLBACK_AUTHOR;
|
|
48
|
+
const controller = useAnnotationLayer({
|
|
49
|
+
documentId,
|
|
50
|
+
store,
|
|
51
|
+
author,
|
|
52
|
+
autosaveMs: MARKUP_AUTOSAVE_MS,
|
|
53
|
+
online,
|
|
54
|
+
pullMs: MARKUP_PULL_MS,
|
|
55
|
+
// An older version is read-only; the hook also asks the store (a guest cannot write).
|
|
56
|
+
readOnly: version !== void 0
|
|
57
|
+
});
|
|
58
|
+
const shown = useMemo(
|
|
59
|
+
() => editing && !controller.readOnly ? controller : viewOnly(controller),
|
|
60
|
+
[editing, controller]
|
|
61
|
+
);
|
|
62
|
+
const { flush } = controller;
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!editing) void flush();
|
|
65
|
+
}, [editing, flush]);
|
|
66
|
+
const atRisk = controller.dirty && (controller.offline || !!controller.error);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!atRisk) return;
|
|
69
|
+
const warn = (e) => {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
e.returnValue = "";
|
|
72
|
+
};
|
|
73
|
+
window.addEventListener("beforeunload", warn);
|
|
74
|
+
return () => window.removeEventListener("beforeunload", warn);
|
|
75
|
+
}, [atRisk]);
|
|
76
|
+
const [freezeOpen, setFreezeOpen] = useState(false);
|
|
77
|
+
const [busy, setBusy] = useState(false);
|
|
78
|
+
const [progress, setProgress] = useState(null);
|
|
79
|
+
const [error, setError] = useState(null);
|
|
80
|
+
const openFreeze = useCallback(() => {
|
|
81
|
+
setError(null);
|
|
82
|
+
setFreezeOpen(true);
|
|
83
|
+
}, []);
|
|
84
|
+
const downloadWithMarkup = useCallback(async () => {
|
|
85
|
+
try {
|
|
86
|
+
await controller.flush();
|
|
87
|
+
const { blob, fileName: name } = await fetchMarkupPdf(client, documentId, version);
|
|
88
|
+
saveFile(blob, name);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
notify(e instanceof Error ? e.message : "The markup could not be downloaded", "error");
|
|
91
|
+
}
|
|
92
|
+
}, [controller, client, documentId, version, saveFile, notify]);
|
|
93
|
+
const handleFreeze = useCallback(
|
|
94
|
+
async (choices) => {
|
|
95
|
+
setBusy(true);
|
|
96
|
+
setError(null);
|
|
97
|
+
try {
|
|
98
|
+
await controller.flush();
|
|
99
|
+
const log = choices.redactionLog ? redactionLogCsv(controller.layer) : null;
|
|
100
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
101
|
+
const result = await freezePdfInBrowser(bytes, controller.layer, {
|
|
102
|
+
...choices,
|
|
103
|
+
author,
|
|
104
|
+
onProgress: (done, total) => setProgress({ done, total })
|
|
105
|
+
});
|
|
106
|
+
const redacted = result.provenance.redactions.count > 0;
|
|
107
|
+
const newDocId = await uploadFrozenCopy(
|
|
108
|
+
uploadDocument,
|
|
109
|
+
result.bytes,
|
|
110
|
+
{ documentId, fileName, shared, folder },
|
|
111
|
+
redacted
|
|
112
|
+
);
|
|
113
|
+
if (log) saveFile(new Blob([log], { type: "text/csv" }), redactionLogName(fileName));
|
|
114
|
+
if (newDocId) {
|
|
115
|
+
await onDocumentsChanged?.([newDocId], "copy");
|
|
116
|
+
openDocument?.(newDocId);
|
|
117
|
+
}
|
|
118
|
+
notify(
|
|
119
|
+
redacted ? "Redacted copy saved as a new document" : "Annotated copy saved as a new document",
|
|
120
|
+
"success",
|
|
121
|
+
{ description: "The original is unchanged and still in your files." }
|
|
122
|
+
);
|
|
123
|
+
for (const warning of result.warnings) notify(warning, "warning");
|
|
124
|
+
setFreezeOpen(false);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
setError(e instanceof Error ? e.message : "The copy could not be created");
|
|
127
|
+
} finally {
|
|
128
|
+
setBusy(false);
|
|
129
|
+
setProgress(null);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
[
|
|
133
|
+
controller,
|
|
134
|
+
author,
|
|
135
|
+
file,
|
|
136
|
+
fileName,
|
|
137
|
+
documentId,
|
|
138
|
+
shared,
|
|
139
|
+
folder,
|
|
140
|
+
uploadDocument,
|
|
141
|
+
saveFile,
|
|
142
|
+
notify,
|
|
143
|
+
onDocumentsChanged,
|
|
144
|
+
openDocument
|
|
145
|
+
]
|
|
146
|
+
);
|
|
147
|
+
const renderPageOverlay = useCallback(
|
|
148
|
+
({ pageNumber, pageWidthPt }) => /* @__PURE__ */ jsx(AnnotationPageOverlay, { controller: shown, pageNumber, pageWidthPt }),
|
|
149
|
+
[shown]
|
|
150
|
+
);
|
|
151
|
+
const hasMarks = controller.layer.annotations.length > 0;
|
|
152
|
+
return /* @__PURE__ */ jsxs(
|
|
153
|
+
"div",
|
|
154
|
+
{
|
|
155
|
+
className: "flex h-full min-h-0 flex-col",
|
|
156
|
+
"data-testid": "annotated-pdf-viewer",
|
|
157
|
+
"data-mode": editing ? "edit" : "view",
|
|
158
|
+
"data-markup-status": controller.status,
|
|
159
|
+
children: [
|
|
160
|
+
editing && /* @__PURE__ */ jsx(
|
|
161
|
+
AnnotationToolbar,
|
|
162
|
+
{
|
|
163
|
+
controller,
|
|
164
|
+
onFreeze: controller.readOnly ? void 0 : openFreeze,
|
|
165
|
+
actions: hasMarks && !controller.dirty && version === void 0 ? /* @__PURE__ */ jsxs(
|
|
166
|
+
"button",
|
|
167
|
+
{
|
|
168
|
+
type: "button",
|
|
169
|
+
className: "inline-flex items-center gap-1 text-xs text-primary hover:underline disabled:cursor-not-allowed disabled:text-muted-foreground disabled:no-underline pointer-coarse:min-h-11",
|
|
170
|
+
"data-testid": "annotation-download-markup",
|
|
171
|
+
title: signed ? SIGNED_LOCKED_REASON : "Download the PDF with these annotations (opens in Acrobat or Preview)",
|
|
172
|
+
disabled: signed,
|
|
173
|
+
onClick: () => void downloadWithMarkup(),
|
|
174
|
+
children: [
|
|
175
|
+
/* @__PURE__ */ jsx(Download, { size: 14 }),
|
|
176
|
+
"Download with markup"
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
) : null
|
|
180
|
+
}
|
|
181
|
+
),
|
|
182
|
+
!editing && controller.status === "error" && /* @__PURE__ */ jsxs("div", { className: "border-b px-3 py-1.5 text-xs text-destructive", "data-testid": "markup-error", children: [
|
|
183
|
+
"The markup could not be loaded: ",
|
|
184
|
+
controller.error
|
|
185
|
+
] }),
|
|
186
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(PdfViewer$1, { ...viewerProps, file, renderPageOverlay }) }),
|
|
187
|
+
editing && /* @__PURE__ */ jsx(
|
|
188
|
+
FreezeDialog,
|
|
189
|
+
{
|
|
190
|
+
open: freezeOpen,
|
|
191
|
+
onOpenChange: setFreezeOpen,
|
|
192
|
+
controller,
|
|
193
|
+
onConfirm: handleFreeze,
|
|
194
|
+
busy,
|
|
195
|
+
progress,
|
|
196
|
+
error
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
var SIGNATURE_BOX_COLOR = "#1c7ed6";
|
|
204
|
+
function SignaturePlacementViewer({
|
|
205
|
+
file,
|
|
206
|
+
documentId,
|
|
207
|
+
onCancel,
|
|
208
|
+
onContinue,
|
|
209
|
+
viewer: PdfViewer$1 = PdfViewer,
|
|
210
|
+
...viewerProps
|
|
211
|
+
}) {
|
|
212
|
+
const store = useMemo(() => createMemoryStore(), []);
|
|
213
|
+
const controller = useAnnotationLayer({ documentId, store, author: "signature" });
|
|
214
|
+
const boxes = controller.layer.annotations.filter((a) => a.kind === "box");
|
|
215
|
+
const box = boxes.at(-1);
|
|
216
|
+
const isTooSmall = box !== void 0 && !isLegibleSignatureBox(box.rect);
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if (controller.status !== "ready") return;
|
|
219
|
+
controller.setSettings({ colors: { ...controller.settings.colors, box: SIGNATURE_BOX_COLOR } });
|
|
220
|
+
}, [controller.status]);
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
if (controller.status !== "ready") return;
|
|
223
|
+
for (const old of boxes.slice(0, -1)) controller.remove(old.id);
|
|
224
|
+
if (box) {
|
|
225
|
+
controller.select(box.id);
|
|
226
|
+
controller.setTool("select");
|
|
227
|
+
} else {
|
|
228
|
+
controller.setTool("box");
|
|
229
|
+
}
|
|
230
|
+
}, [controller.status, boxes.length, box?.id]);
|
|
231
|
+
const redraw = useCallback(() => {
|
|
232
|
+
if (box) controller.remove(box.id);
|
|
233
|
+
controller.setTool("box");
|
|
234
|
+
}, [box, controller]);
|
|
235
|
+
const renderPageOverlay = useCallback(
|
|
236
|
+
({ pageNumber, pageWidthPt }) => /* @__PURE__ */ jsx(
|
|
237
|
+
AnnotationPageOverlay,
|
|
238
|
+
{
|
|
239
|
+
controller,
|
|
240
|
+
pageNumber,
|
|
241
|
+
pageWidthPt
|
|
242
|
+
}
|
|
243
|
+
),
|
|
244
|
+
[controller]
|
|
245
|
+
);
|
|
246
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-testid": "signature-placement-viewer", children: [
|
|
247
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 text-sm", children: [
|
|
248
|
+
/* @__PURE__ */ jsx("span", { className: "mr-auto text-muted-foreground", "data-testid": "signature-placement-hint", children: isTooSmall ? "This box is small: the signature will print small. Make it larger to keep it legible." : box ? "Move or resize the box, then continue." : "Drag a box where your signature goes, or continue to sign at the end." }),
|
|
249
|
+
box && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: redraw, children: "Redraw" }),
|
|
250
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: onCancel, children: "Cancel" }),
|
|
251
|
+
/* @__PURE__ */ jsx(
|
|
252
|
+
Button,
|
|
253
|
+
{
|
|
254
|
+
type: "button",
|
|
255
|
+
size: "sm",
|
|
256
|
+
onClick: () => onContinue(box ? toAppearance(box) : void 0),
|
|
257
|
+
"data-testid": "signature-placement-continue",
|
|
258
|
+
children: "Continue"
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
] }),
|
|
262
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(PdfViewer$1, { ...viewerProps, file, renderPageOverlay }) })
|
|
263
|
+
] });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { AnnotatedPdfViewer, MARKUP_AUTOSAVE_MS, MARKUP_PULL_MS, SignaturePlacementViewer };
|
|
267
|
+
//# sourceMappingURL=index.js.map
|
|
268
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/document-tools/viewer/AnnotatedPdfViewer.tsx","../../../src/document-tools/viewer/SignaturePlacementViewer.tsx"],"names":["PdfViewer","KitPdfViewer","useMemo","useAnnotationLayer","useEffect","useCallback","jsx","AnnotationPageOverlay","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The PDF viewer with the document's MARKUP on it: toolbar, per-page overlay and the freeze dialog.\n *\n * The original is never touched. The marks are the version's markup on the server (native PDF\n * annotations in its `{doc}-markup.pdf`, see `createMarkupStore` in `@arbidocs/react/document-tools`),\n * with the document's own privacy:\n * a shared document has one markup that owners and collaborators edit and guests read; a private\n * one is its owner's. Edits autosave a few seconds after the last change and when the viewer\n * closes; colleagues' changes are merged in. \"Freeze\" renders a new PDF with the marks built in and\n * saves it as a separate document derived from the original (see `uploadFrozenCopy`). Load it\n * lazily: it brings in pdf-lib, which nothing else needs.\n *\n * Needs a `<DocumentToolsProvider>` (API client, user, notify, open, refresh) inside a React Query\n * `QueryClientProvider`. `viewer` is the PDF viewer to draw on (default: the kit `PdfViewer`); a host\n * passes its own binding of it, e.g. one that reports the visible page.\n *\n * `editing` off is the default reading view: the marks show and comments open, read-only, with no\n * toolbar. Unsaved edits still go out when switching from editing to reading.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType } from 'react'\nimport {\n AnnotationPageOverlay,\n AnnotationToolbar,\n FreezeDialog,\n redactionLogCsv,\n useAnnotationLayer,\n type AnnotationController,\n type AnnotationStore,\n type FreezeChoices,\n} from '@arbidocs/react/annotations'\nimport { freezePdfInBrowser } from '@arbidocs/react/annotations/freeze'\nimport {\n createMarkupStore,\n fetchMarkupPdf,\n SIGNED_LOCKED_REASON,\n redactionLogName,\n uploadFrozenCopy,\n useDocumentTools,\n useIsOnline,\n type MarkupSnapshot,\n} from '@arbidocs/react/document-tools'\nimport { PdfViewer as KitPdfViewer, type PdfViewerProps } from '@arbidocs/react/viewers'\nimport { Download } from 'lucide-react'\n\n/** Autosave this long after the last change (the design's \"a few seconds\"). */\nexport const MARKUP_AUTOSAVE_MS = 2500\n/** Look for colleagues' changes this often while idle. */\nexport const MARKUP_PULL_MS = 20_000\n\n/** The PDF viewer the marks are drawn on: the kit viewer's props, with a page-overlay slot. */\nexport type DocumentPdfViewer = ComponentType<PdfViewerProps>\n\nexport interface AnnotatedPdfViewerProps extends Omit<\n PdfViewerProps,\n 'file' | 'renderPageOverlay'\n> {\n file: Blob\n documentId: string\n /** The version on screen when it is not the current one (its markup is shown, read-only). */\n version?: number\n fileName: string | null | undefined\n /** The original's workspace sharing and folder, which the frozen copy takes. */\n shared?: boolean\n folder?: string | null\n /** Annotate mode (toolbar, tools). Off: the marks are shown read-only. Default on. */\n editing?: boolean\n /** After each save: the markup's revision and how many marks it holds. */\n onMarkupChange?: (snapshot: MarkupSnapshot) => void\n /** Where the layer lives; defaults to the version's markup on the server. */\n store?: AnnotationStore\n /** The PDF viewer to draw on. Default: the kit `PdfViewer` from `@arbidocs/react/viewers`. */\n viewer?: DocumentPdfViewer\n /**\n * The version is signed, so locked: marks still go in the markup layer, but there is no\n * \"Download with markup\" (they are never written into its PDF).\n */\n signed?: boolean\n}\n\nconst FALLBACK_AUTHOR = 'You'\n\n/** The same controller, view only: what the overlay gets outside annotate mode. */\nfunction viewOnly(controller: AnnotationController): AnnotationController {\n return { ...controller, readOnly: true, tool: 'select', setTool: () => {} }\n}\n\nexport function AnnotatedPdfViewer({\n file,\n documentId,\n version,\n fileName,\n shared = false,\n folder,\n editing = true,\n onMarkupChange,\n store: storeOverride,\n viewer: PdfViewer = KitPdfViewer,\n signed = false,\n ...viewerProps\n}: AnnotatedPdfViewerProps) {\n const { client, user, notify, saveFile, uploadDocument, openDocument, onDocumentsChanged } =\n useDocumentTools()\n const online = useIsOnline()\n const onChangeRef = useRef(onMarkupChange)\n onChangeRef.current = onMarkupChange\n const store = useMemo(\n () =>\n storeOverride ??\n createMarkupStore({\n version,\n client,\n onSaved: (snapshot) => onChangeRef.current?.(snapshot),\n }),\n // A new store per document version: its revision and tombstones belong to that markup.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [storeOverride, client, documentId, version]\n )\n const author = user?.name || FALLBACK_AUTHOR\n const controller = useAnnotationLayer({\n documentId,\n store,\n author,\n autosaveMs: MARKUP_AUTOSAVE_MS,\n online,\n pullMs: MARKUP_PULL_MS,\n // An older version is read-only; the hook also asks the store (a guest cannot write).\n readOnly: version !== undefined,\n })\n const shown = useMemo(\n () => (editing && !controller.readOnly ? controller : viewOnly(controller)),\n [editing, controller]\n )\n\n // Leaving annotate mode: write what is still waiting on the autosave timer.\n const { flush } = controller\n useEffect(() => {\n if (!editing) void flush()\n }, [editing, flush])\n\n // Edits that cannot be saved right now (offline, or the server refused): warn before leaving.\n const atRisk = controller.dirty && (controller.offline || !!controller.error)\n useEffect(() => {\n if (!atRisk) return\n const warn = (e: BeforeUnloadEvent) => {\n e.preventDefault()\n e.returnValue = ''\n }\n window.addEventListener('beforeunload', warn)\n return () => window.removeEventListener('beforeunload', warn)\n }, [atRisk])\n\n const [freezeOpen, setFreezeOpen] = useState(false)\n const [busy, setBusy] = useState(false)\n const [progress, setProgress] = useState<{ done: number; total: number } | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n const openFreeze = useCallback(() => {\n setError(null)\n setFreezeOpen(true)\n }, [])\n\n const downloadWithMarkup = useCallback(async () => {\n try {\n await controller.flush()\n const { blob, fileName: name } = await fetchMarkupPdf(client, documentId, version)\n saveFile(blob, name)\n } catch (e) {\n notify(e instanceof Error ? e.message : 'The markup could not be downloaded', 'error')\n }\n }, [controller, client, documentId, version, saveFile, notify])\n\n const handleFreeze = useCallback(\n async (choices: FreezeChoices) => {\n setBusy(true)\n setError(null)\n try {\n await controller.flush()\n // The log is taken from the layer as it is frozen; it never holds the redacted text.\n const log = choices.redactionLog ? redactionLogCsv(controller.layer) : null\n const bytes = new Uint8Array(await file.arrayBuffer())\n const result = await freezePdfInBrowser(bytes, controller.layer, {\n ...choices,\n author,\n onProgress: (done, total) => setProgress({ done, total }),\n })\n const redacted = result.provenance.redactions.count > 0\n const newDocId = await uploadFrozenCopy(\n uploadDocument,\n result.bytes,\n { documentId, fileName, shared, folder },\n redacted\n )\n if (log) saveFile(new Blob([log], { type: 'text/csv' }), redactionLogName(fileName))\n if (newDocId) {\n // The copy joins the list beside the original, which stays where it was.\n await onDocumentsChanged?.([newDocId], 'copy')\n openDocument?.(newDocId)\n }\n notify(\n redacted\n ? 'Redacted copy saved as a new document'\n : 'Annotated copy saved as a new document',\n 'success',\n { description: 'The original is unchanged and still in your files.' }\n )\n for (const warning of result.warnings) notify(warning, 'warning')\n setFreezeOpen(false)\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The copy could not be created')\n } finally {\n setBusy(false)\n setProgress(null)\n }\n },\n [\n controller,\n author,\n file,\n fileName,\n documentId,\n shared,\n folder,\n uploadDocument,\n saveFile,\n notify,\n onDocumentsChanged,\n openDocument,\n ]\n )\n\n const renderPageOverlay = useCallback(\n ({ pageNumber, pageWidthPt }: { pageNumber: number; pageWidthPt: number | undefined }) => (\n <AnnotationPageOverlay controller={shown} pageNumber={pageNumber} pageWidthPt={pageWidthPt} />\n ),\n [shown]\n )\n\n const hasMarks = controller.layer.annotations.length > 0\n\n return (\n <div\n className=\"flex h-full min-h-0 flex-col\"\n data-testid=\"annotated-pdf-viewer\"\n data-mode={editing ? 'edit' : 'view'}\n data-markup-status={controller.status}\n >\n {editing && (\n <AnnotationToolbar\n controller={controller}\n onFreeze={controller.readOnly ? undefined : openFreeze}\n actions={\n hasMarks && !controller.dirty && version === undefined ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 text-xs text-primary hover:underline disabled:cursor-not-allowed disabled:text-muted-foreground disabled:no-underline pointer-coarse:min-h-11\"\n data-testid=\"annotation-download-markup\"\n title={\n signed\n ? SIGNED_LOCKED_REASON\n : 'Download the PDF with these annotations (opens in Acrobat or Preview)'\n }\n disabled={signed}\n onClick={() => void downloadWithMarkup()}\n >\n <Download size={14} />\n Download with markup\n </button>\n ) : null\n }\n />\n )}\n {!editing && controller.status === 'error' && (\n <div className=\"border-b px-3 py-1.5 text-xs text-destructive\" data-testid=\"markup-error\">\n The markup could not be loaded: {controller.error}\n </div>\n )}\n <div className=\"min-h-0 flex-1\">\n <PdfViewer {...viewerProps} file={file} renderPageOverlay={renderPageOverlay} />\n </div>\n {editing && (\n <FreezeDialog\n open={freezeOpen}\n onOpenChange={setFreezeOpen}\n controller={controller}\n onConfirm={handleFreeze}\n busy={busy}\n progress={progress}\n error={error}\n />\n )}\n </div>\n )\n}\n\nexport default AnnotatedPdfViewer\n","/**\n * Choose where a signature goes: the PDF with the annotation overlay's box tool, kept in memory\n * only. The box is not an annotation; it is handed to the Sign dialog, and the backend draws the\n * signature there. Needs no `<DocumentToolsProvider>`.\n */\n\nimport { useCallback, useEffect, useMemo, type ReactElement } from 'react'\nimport {\n AnnotationPageOverlay,\n createMemoryStore,\n useAnnotationLayer,\n type BoxAnnotation,\n} from '@arbidocs/react/annotations'\nimport {\n isLegibleSignatureBox,\n toAppearance,\n type SignatureAppearance,\n} from '@arbidocs/react/document-tools'\nimport { Button } from '@arbidocs/react/ui'\nimport { PdfViewer as KitPdfViewer, type PdfViewerProps } from '@arbidocs/react/viewers'\nimport type { DocumentPdfViewer } from './AnnotatedPdfViewer'\n\nconst SIGNATURE_BOX_COLOR = '#1c7ed6'\n\nexport interface SignaturePlacementViewerProps extends Omit<\n PdfViewerProps,\n 'file' | 'renderPageOverlay'\n> {\n file: Blob\n documentId: string\n onCancel: () => void\n /** The chosen box, or undefined for the default spot (bottom of the last page). */\n onContinue: (appearance: SignatureAppearance | undefined) => void\n /** The PDF viewer to draw on. Default: the kit `PdfViewer` from `@arbidocs/react/viewers`. */\n viewer?: DocumentPdfViewer\n}\n\nexport function SignaturePlacementViewer({\n file,\n documentId,\n onCancel,\n onContinue,\n viewer: PdfViewer = KitPdfViewer,\n ...viewerProps\n}: SignaturePlacementViewerProps): ReactElement {\n const store = useMemo(() => createMemoryStore(), [])\n const controller = useAnnotationLayer({ documentId, store, author: 'signature' })\n const boxes = controller.layer.annotations.filter((a): a is BoxAnnotation => a.kind === 'box')\n const box = boxes.at(-1)\n const isTooSmall = box !== undefined && !isLegibleSignatureBox(box.rect)\n\n // Draw with the box tool; once there is a box, select it so it can be moved or resized.\n useEffect(() => {\n if (controller.status !== 'ready') return\n controller.setSettings({ colors: { ...controller.settings.colors, box: SIGNATURE_BOX_COLOR } })\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once, when the layer is ready\n }, [controller.status])\n useEffect(() => {\n if (controller.status !== 'ready') return\n // One signature box: drawing another replaces it.\n for (const old of boxes.slice(0, -1)) controller.remove(old.id)\n if (box) {\n controller.select(box.id)\n controller.setTool('select')\n } else {\n controller.setTool('box')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- react to the boxes only\n }, [controller.status, boxes.length, box?.id])\n\n const redraw = useCallback(() => {\n if (box) controller.remove(box.id)\n controller.setTool('box')\n }, [box, controller])\n\n const renderPageOverlay = useCallback(\n ({ pageNumber, pageWidthPt }: { pageNumber: number; pageWidthPt: number | undefined }) => (\n <AnnotationPageOverlay\n controller={controller}\n pageNumber={pageNumber}\n pageWidthPt={pageWidthPt}\n />\n ),\n [controller]\n )\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\" data-testid=\"signature-placement-viewer\">\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 text-sm\">\n <span className=\"mr-auto text-muted-foreground\" data-testid=\"signature-placement-hint\">\n {isTooSmall\n ? 'This box is small: the signature will print small. Make it larger to keep it legible.'\n : box\n ? 'Move or resize the box, then continue.'\n : 'Drag a box where your signature goes, or continue to sign at the end.'}\n </span>\n {box && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={redraw}>\n Redraw\n </Button>\n )}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => onContinue(box ? toAppearance(box) : undefined)}\n data-testid=\"signature-placement-continue\"\n >\n Continue\n </Button>\n </div>\n <div className=\"min-h-0 flex-1\">\n <PdfViewer {...viewerProps} file={file} renderPageOverlay={renderPageOverlay} />\n </div>\n </div>\n )\n}\n\nexport default SignaturePlacementViewer\n"]}
|
package/dist/facts/index.cjs
CHANGED
|
@@ -7,9 +7,9 @@ var chunkOUW6G4O2_cjs = require('../chunk-OUW6G4O2.cjs');
|
|
|
7
7
|
var chunkIA7RTPT3_cjs = require('../chunk-IA7RTPT3.cjs');
|
|
8
8
|
var chunk2EI7NCUA_cjs = require('../chunk-2EI7NCUA.cjs');
|
|
9
9
|
var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
|
|
10
|
-
require('../chunk-C54XEN5T.cjs');
|
|
11
10
|
require('../chunk-FX3K6LNZ.cjs');
|
|
12
11
|
var chunkPPCATBOY_cjs = require('../chunk-PPCATBOY.cjs');
|
|
12
|
+
require('../chunk-C54XEN5T.cjs');
|
|
13
13
|
var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
|
|
14
14
|
var chunkMHVNT4J3_cjs = require('../chunk-MHVNT4J3.cjs');
|
|
15
15
|
var lucideReact = require('lucide-react');
|
package/dist/facts/index.js
CHANGED
|
@@ -6,9 +6,9 @@ import { GridView, SelectionBar, SelectionBarAction } from '../chunk-BUHKUKKB.js
|
|
|
6
6
|
import { FilterInput } from '../chunk-YU2KUMGE.js';
|
|
7
7
|
export { DEFAULT_FILTER_INPUT_LABELS as DEFAULT_FACTS_FILTER_INPUT_LABELS, DEFAULT_FILTER_FIELDS as FACTS_SEARCH_FIELD_OPTIONS, FilterInput as FactsFilterInput } from '../chunk-YU2KUMGE.js';
|
|
8
8
|
import { TabHeader } from '../chunk-4WWM3GQ5.js';
|
|
9
|
-
import '../chunk-76JDDMSP.js';
|
|
10
9
|
import '../chunk-SLSBJRWW.js';
|
|
11
10
|
import { observeResize } from '../chunk-NPLYHR2E.js';
|
|
11
|
+
import '../chunk-76JDDMSP.js';
|
|
12
12
|
import { initials } from '../chunk-OXF2IFXG.js';
|
|
13
13
|
import { testIdOr } from '../chunk-7F6CBP3Z.js';
|
|
14
14
|
import { PencilLine, Check, MoreVertical, Pencil, Trash2, CalendarDays, X, Columns3, ChevronDown, RotateCcw, Milestone, CalendarClock, Scale, Lightbulb, ArrowRight, Loader2, Info, Paperclip, Tags, MoreHorizontal, FolderUp, BookMarked, Plus, Search, CheckCircle2, CornerDownLeft, Quote, ChevronLeft, ChevronRight, Table2, CalendarRange, GanttChartSquare } from 'lucide-react';
|
|
@@ -9,12 +9,14 @@ export interface DocumentRowMenuProps {
|
|
|
9
9
|
onDownload: () => void;
|
|
10
10
|
/** "Download with markup": shown when the document's current version has markup. */
|
|
11
11
|
onDownloadMarkup?: () => void;
|
|
12
|
+
/** Why "Download with markup" is off (a signed, locked version): shown under it. */
|
|
13
|
+
downloadMarkupDisabledReason?: string;
|
|
12
14
|
onMove: () => void;
|
|
13
15
|
onDelete: () => void;
|
|
14
16
|
testId?: string;
|
|
15
17
|
}
|
|
16
18
|
/** The row-actions kebab of the grid's document cell (Open, Review, Chat, Rename, ...). */
|
|
17
|
-
export declare function DocumentRowMenu({ canEdit, onOpen, onReview, onDocumentChat, onRename, onDownload, onDownloadMarkup, onMove, onDelete, testId, }: DocumentRowMenuProps): import("react").JSX.Element;
|
|
19
|
+
export declare function DocumentRowMenu({ canEdit, onOpen, onReview, onDocumentChat, onRename, onDownload, onDownloadMarkup, downloadMarkupDisabledReason, onMove, onDelete, testId, }: DocumentRowMenuProps): import("react").JSX.Element;
|
|
18
20
|
export interface DocumentNameCellFrameProps {
|
|
19
21
|
/** Test id on the wrapper, e.g. `open-document-viewer-button-<id>`. */
|
|
20
22
|
testId?: string;
|
package/dist/files/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunk4DVEGXZQ_cjs = require('../chunk-4DVEGXZQ.cjs');
|
|
4
5
|
var chunkZPERNIMP_cjs = require('../chunk-ZPERNIMP.cjs');
|
|
5
6
|
var chunk223D4727_cjs = require('../chunk-223D4727.cjs');
|
|
6
7
|
var chunk3AFWGEDJ_cjs = require('../chunk-3AFWGEDJ.cjs');
|
|
@@ -8,9 +9,9 @@ var chunkIA7RTPT3_cjs = require('../chunk-IA7RTPT3.cjs');
|
|
|
8
9
|
var chunk2EI7NCUA_cjs = require('../chunk-2EI7NCUA.cjs');
|
|
9
10
|
var chunkOB5F4577_cjs = require('../chunk-OB5F4577.cjs');
|
|
10
11
|
var chunkVFUWWH52_cjs = require('../chunk-VFUWWH52.cjs');
|
|
11
|
-
require('../chunk-C54XEN5T.cjs');
|
|
12
12
|
require('../chunk-FX3K6LNZ.cjs');
|
|
13
13
|
require('../chunk-PPCATBOY.cjs');
|
|
14
|
+
require('../chunk-C54XEN5T.cjs');
|
|
14
15
|
var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
|
|
15
16
|
var chunkVLCY46K6_cjs = require('../chunk-VLCY46K6.cjs');
|
|
16
17
|
var chunk2ZTONLT5_cjs = require('../chunk-2ZTONLT5.cjs');
|
|
@@ -1893,63 +1894,6 @@ function ViewerZoomControl({ zoom, onCycle, labels, testIds }) {
|
|
|
1893
1894
|
}
|
|
1894
1895
|
);
|
|
1895
1896
|
}
|
|
1896
|
-
function ViewerHeaderStart({ children }) {
|
|
1897
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1898
|
-
"div",
|
|
1899
|
-
{
|
|
1900
|
-
"data-slot": "viewer-header-start",
|
|
1901
|
-
className: "flex min-w-0 items-center gap-2 overflow-hidden",
|
|
1902
|
-
children
|
|
1903
|
-
}
|
|
1904
|
-
);
|
|
1905
|
-
}
|
|
1906
|
-
function ViewerHeaderEnd({
|
|
1907
|
-
isCompact,
|
|
1908
|
-
children
|
|
1909
|
-
}) {
|
|
1910
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1911
|
-
"div",
|
|
1912
|
-
{
|
|
1913
|
-
"data-slot": "viewer-header-end",
|
|
1914
|
-
className: ui.cn("flex flex-shrink-0 items-center", isCompact ? "gap-1" : "gap-2"),
|
|
1915
|
-
children
|
|
1916
|
-
}
|
|
1917
|
-
);
|
|
1918
|
-
}
|
|
1919
|
-
function ViewerStatusNote({
|
|
1920
|
-
pulse,
|
|
1921
|
-
testId,
|
|
1922
|
-
children
|
|
1923
|
-
}) {
|
|
1924
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1925
|
-
"span",
|
|
1926
|
-
{
|
|
1927
|
-
"data-slot": "viewer-status-note",
|
|
1928
|
-
className: ui.cn("flex-shrink-0 text-sm text-muted-foreground", pulse && "animate-pulse"),
|
|
1929
|
-
"data-testid": testId,
|
|
1930
|
-
children
|
|
1931
|
-
}
|
|
1932
|
-
);
|
|
1933
|
-
}
|
|
1934
|
-
function ViewerPane({
|
|
1935
|
-
hidden,
|
|
1936
|
-
scroll,
|
|
1937
|
-
testId,
|
|
1938
|
-
children
|
|
1939
|
-
}) {
|
|
1940
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1941
|
-
"div",
|
|
1942
|
-
{
|
|
1943
|
-
"data-slot": "viewer-pane",
|
|
1944
|
-
"data-testid": testId,
|
|
1945
|
-
className: ui.cn(hidden ? "hidden" : scroll ? "h-full overflow-auto" : "relative h-full"),
|
|
1946
|
-
children
|
|
1947
|
-
}
|
|
1948
|
-
);
|
|
1949
|
-
}
|
|
1950
|
-
function ViewerRenderedPane({ testId, children }) {
|
|
1951
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "viewer-rendered", className: "p-6", "data-testid": testId, children });
|
|
1952
|
-
}
|
|
1953
1897
|
var DEFAULT_MOVE_TO_FOLDER_LABELS = {
|
|
1954
1898
|
title: "Move to Folder",
|
|
1955
1899
|
cancel: "Cancel",
|
|
@@ -4168,6 +4112,7 @@ function DocumentRowMenu({
|
|
|
4168
4112
|
onRename,
|
|
4169
4113
|
onDownload,
|
|
4170
4114
|
onDownloadMarkup,
|
|
4115
|
+
downloadMarkupDisabledReason,
|
|
4171
4116
|
onMove,
|
|
4172
4117
|
onDelete,
|
|
4173
4118
|
testId = "document-row-menu"
|
|
@@ -4212,10 +4157,21 @@ function DocumentRowMenu({
|
|
|
4212
4157
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "mr-2 h-4 w-4" }),
|
|
4213
4158
|
"Download"
|
|
4214
4159
|
] }),
|
|
4215
|
-
onDownloadMarkup && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4160
|
+
onDownloadMarkup && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4161
|
+
ui.DropdownMenuItem,
|
|
4162
|
+
{
|
|
4163
|
+
onSelect: onDownloadMarkup,
|
|
4164
|
+
disabled: !!downloadMarkupDisabledReason,
|
|
4165
|
+
title: downloadMarkupDisabledReason,
|
|
4166
|
+
"data-testid": "document-row-download-markup",
|
|
4167
|
+
className: downloadMarkupDisabledReason ? "flex-wrap" : void 0,
|
|
4168
|
+
children: [
|
|
4169
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "mr-2 h-4 w-4" }),
|
|
4170
|
+
"Download with markup",
|
|
4171
|
+
downloadMarkupDisabledReason && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 w-full pl-6 text-xs text-muted-foreground", children: downloadMarkupDisabledReason })
|
|
4172
|
+
]
|
|
4173
|
+
}
|
|
4174
|
+
),
|
|
4219
4175
|
canEdit && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onMove, children: [
|
|
4220
4176
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderInput, { className: "mr-2 h-4 w-4" }),
|
|
4221
4177
|
"Move to\u2026"
|
|
@@ -7222,6 +7178,26 @@ function ExplorerDragPreview({ icon, title, count }) {
|
|
|
7222
7178
|
] });
|
|
7223
7179
|
}
|
|
7224
7180
|
|
|
7181
|
+
Object.defineProperty(exports, "ViewerHeaderEnd", {
|
|
7182
|
+
enumerable: true,
|
|
7183
|
+
get: function () { return chunk4DVEGXZQ_cjs.ViewerHeaderEnd; }
|
|
7184
|
+
});
|
|
7185
|
+
Object.defineProperty(exports, "ViewerHeaderStart", {
|
|
7186
|
+
enumerable: true,
|
|
7187
|
+
get: function () { return chunk4DVEGXZQ_cjs.ViewerHeaderStart; }
|
|
7188
|
+
});
|
|
7189
|
+
Object.defineProperty(exports, "ViewerPane", {
|
|
7190
|
+
enumerable: true,
|
|
7191
|
+
get: function () { return chunk4DVEGXZQ_cjs.ViewerPane; }
|
|
7192
|
+
});
|
|
7193
|
+
Object.defineProperty(exports, "ViewerRenderedPane", {
|
|
7194
|
+
enumerable: true,
|
|
7195
|
+
get: function () { return chunk4DVEGXZQ_cjs.ViewerRenderedPane; }
|
|
7196
|
+
});
|
|
7197
|
+
Object.defineProperty(exports, "ViewerStatusNote", {
|
|
7198
|
+
enumerable: true,
|
|
7199
|
+
get: function () { return chunk4DVEGXZQ_cjs.ViewerStatusNote; }
|
|
7200
|
+
});
|
|
7225
7201
|
Object.defineProperty(exports, "DEFAULT_DOCUMENT_VIEW_TOGGLE_LABELS", {
|
|
7226
7202
|
enumerable: true,
|
|
7227
7203
|
get: function () { return chunkZPERNIMP_cjs.DEFAULT_DOCUMENT_VIEW_TOGGLE_LABELS; }
|
|
@@ -7421,16 +7397,11 @@ exports.UrlInputDialogView = UrlInputDialogView;
|
|
|
7421
7397
|
exports.VendorLogo = VendorLogo;
|
|
7422
7398
|
exports.ViewSelectorMenu = ViewSelectorMenu;
|
|
7423
7399
|
exports.ViewerFrame = ViewerFrame;
|
|
7424
|
-
exports.ViewerHeaderEnd = ViewerHeaderEnd;
|
|
7425
|
-
exports.ViewerHeaderStart = ViewerHeaderStart;
|
|
7426
7400
|
exports.ViewerImageActions = ViewerImageActions;
|
|
7427
7401
|
exports.ViewerLoadError = ViewerLoadError;
|
|
7428
7402
|
exports.ViewerMessage = ViewerMessage;
|
|
7429
7403
|
exports.ViewerPageCounter = ViewerPageCounter;
|
|
7430
|
-
exports.ViewerPane = ViewerPane;
|
|
7431
7404
|
exports.ViewerPreviewUnavailable = ViewerPreviewUnavailable;
|
|
7432
|
-
exports.ViewerRenderedPane = ViewerRenderedPane;
|
|
7433
|
-
exports.ViewerStatusNote = ViewerStatusNote;
|
|
7434
7405
|
exports.ViewerTabBar = ViewerTabBar;
|
|
7435
7406
|
exports.ViewerTitle = ViewerTitle;
|
|
7436
7407
|
exports.ViewerZoomControl = ViewerZoomControl;
|