@zerohive/hive-viewer 0.2.5 → 0.2.6
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/index.cjs +182 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +183 -225
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -225
- package/dist/styles.css +66 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,222 +55,122 @@ function sanitizeHtml(html) {
|
|
|
55
55
|
// src/editors/RichTextEditor.tsx
|
|
56
56
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
57
57
|
var PAGE_H = 1122;
|
|
58
|
-
var RichTextEditor = (0, import_react.forwardRef)(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (props.fileType === "docx") {
|
|
79
|
-
const res = await import_mammoth.default.convertToHtml({
|
|
80
|
-
arrayBuffer: props.arrayBuffer
|
|
81
|
-
});
|
|
82
|
-
if (!cancelled) {
|
|
83
|
-
setHtml(sanitizeHtml(res.value || "<p><br/></p>"));
|
|
58
|
+
var RichTextEditor = (0, import_react.forwardRef)(
|
|
59
|
+
(props, ref) => {
|
|
60
|
+
const readOnly = props.mode === "view";
|
|
61
|
+
const md = (0, import_react.useMemo)(
|
|
62
|
+
() => new import_markdown_it.default({ html: false, linkify: true, breaks: true }),
|
|
63
|
+
[]
|
|
64
|
+
);
|
|
65
|
+
const scrollerRef = (0, import_react.useRef)(null);
|
|
66
|
+
const editorRef = (0, import_react.useRef)(null);
|
|
67
|
+
const captureRef = (0, import_react.useRef)(null);
|
|
68
|
+
const initialized = (0, import_react.useRef)(false);
|
|
69
|
+
(0, import_react.useEffect)(() => {
|
|
70
|
+
if (initialized.current) return;
|
|
71
|
+
(async () => {
|
|
72
|
+
if (props.mode === "create") {
|
|
73
|
+
editorRef.current.innerHTML = "<p><br/></p>";
|
|
74
|
+
initialized.current = true;
|
|
75
|
+
return;
|
|
84
76
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
if (!props.arrayBuffer) return;
|
|
78
|
+
if (props.fileType === "docx") {
|
|
79
|
+
const res = await import_mammoth.default.convertToHtml({
|
|
80
|
+
arrayBuffer: props.arrayBuffer
|
|
81
|
+
});
|
|
82
|
+
editorRef.current.innerHTML = sanitizeHtml(
|
|
83
|
+
res.value || "<p><br/></p>"
|
|
84
|
+
);
|
|
89
85
|
} else {
|
|
90
|
-
|
|
86
|
+
const text = new TextDecoder().decode(props.arrayBuffer);
|
|
87
|
+
editorRef.current.innerHTML = props.fileType === "md" ? sanitizeHtml(md.render(text)) : `<pre>${escapeHtml(text)}</pre>`;
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}, [html, props.headerFooterEnabled]);
|
|
109
|
-
function exec(cmd) {
|
|
110
|
-
if (readOnly) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
document.execCommand(cmd);
|
|
114
|
-
}
|
|
115
|
-
function onClick(e) {
|
|
116
|
-
if (!props.armedSignatureUrl) {
|
|
117
|
-
return;
|
|
89
|
+
initialized.current = true;
|
|
90
|
+
})();
|
|
91
|
+
}, [props.arrayBuffer, props.fileType, props.mode, md]);
|
|
92
|
+
(0, import_react.useEffect)(() => {
|
|
93
|
+
const el = scrollerRef.current;
|
|
94
|
+
if (!el) return;
|
|
95
|
+
const recompute = () => props.onPageCount(Math.max(1, Math.ceil(el.scrollHeight / PAGE_H)));
|
|
96
|
+
recompute();
|
|
97
|
+
const ro = new ResizeObserver(recompute);
|
|
98
|
+
ro.observe(el);
|
|
99
|
+
return () => ro.disconnect();
|
|
100
|
+
}, [props.headerFooterEnabled]);
|
|
101
|
+
function exec(cmd) {
|
|
102
|
+
if (readOnly) return;
|
|
103
|
+
document.execCommand(cmd);
|
|
104
|
+
editorRef.current?.focus();
|
|
118
105
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const scroller = scrollerRef.current;
|
|
133
|
-
const capture = captureRef.current;
|
|
134
|
-
if (!scroller || !capture) {
|
|
135
|
-
return void 0;
|
|
136
|
-
}
|
|
137
|
-
const old = scroller.scrollTop;
|
|
138
|
-
scroller.scrollTop = index * PAGE_H;
|
|
139
|
-
await new Promise((r) => requestAnimationFrame(() => r(null)));
|
|
140
|
-
try {
|
|
141
|
-
const canvas = await (0, import_html2canvas.default)(capture, {
|
|
142
|
-
backgroundColor: null,
|
|
143
|
-
scale: 0.25,
|
|
144
|
-
useCORS: true
|
|
145
|
-
});
|
|
146
|
-
return canvas.toDataURL("image/png");
|
|
147
|
-
} catch {
|
|
148
|
-
return void 0;
|
|
149
|
-
} finally {
|
|
150
|
-
scroller.scrollTop = old;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
async function save(exportPdf) {
|
|
154
|
-
const inner = editorRef.current?.innerHTML ?? html;
|
|
155
|
-
const stitched = `<!doctype html><html><head><meta charset="utf-8" /></head><body>${inner}</body></html>`;
|
|
156
|
-
if (exportPdf) {
|
|
157
|
-
const b642 = btoa(unescape(encodeURIComponent(stitched)));
|
|
158
|
-
props.onSave(b642, {
|
|
159
|
-
fileName: replaceExt(props.fileName, "html"),
|
|
160
|
-
fileType: "txt",
|
|
161
|
-
exportedAsPdf: true,
|
|
162
|
-
annotations: { signaturePlacements: props.signaturePlacements }
|
|
106
|
+
function onClickPage(e) {
|
|
107
|
+
if (!props.armedSignatureUrl) return;
|
|
108
|
+
const scroller = scrollerRef.current;
|
|
109
|
+
if (!scroller) return;
|
|
110
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
111
|
+
const absY = scroller.scrollTop + (e.clientY - rect.top);
|
|
112
|
+
const page = Math.floor(absY / PAGE_H) + 1;
|
|
113
|
+
props.onPlaceSignature({
|
|
114
|
+
page,
|
|
115
|
+
x: (e.clientX - rect.left) / rect.width,
|
|
116
|
+
y: absY % PAGE_H / PAGE_H,
|
|
117
|
+
w: 0.25,
|
|
118
|
+
h: 0.1
|
|
163
119
|
});
|
|
164
|
-
return;
|
|
165
120
|
}
|
|
166
|
-
|
|
121
|
+
async function requestThumbnail(index) {
|
|
122
|
+
const scroller = scrollerRef.current;
|
|
123
|
+
const capture = captureRef.current;
|
|
124
|
+
if (!scroller || !capture) return;
|
|
125
|
+
const old = scroller.scrollTop;
|
|
126
|
+
scroller.scrollTop = index * PAGE_H;
|
|
127
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
167
128
|
try {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
body: JSON.stringify({
|
|
172
|
-
html: stitched,
|
|
173
|
-
fileName: replaceExt(props.fileName, "docx")
|
|
174
|
-
})
|
|
129
|
+
const canvas = await (0, import_html2canvas.default)(capture, {
|
|
130
|
+
scale: 0.25,
|
|
131
|
+
useCORS: true
|
|
175
132
|
});
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const blob = await response.blob();
|
|
180
|
-
const url = window.URL.createObjectURL(blob);
|
|
181
|
-
const a = document.createElement("a");
|
|
182
|
-
a.href = url;
|
|
183
|
-
a.download = replaceExt(props.fileName, "docx");
|
|
184
|
-
document.body.appendChild(a);
|
|
185
|
-
a.click();
|
|
186
|
-
setTimeout(() => {
|
|
187
|
-
window.URL.revokeObjectURL(url);
|
|
188
|
-
a.remove();
|
|
189
|
-
}, 100);
|
|
190
|
-
} catch (err) {
|
|
191
|
-
alert(
|
|
192
|
-
"DOCX export failed: " + (err instanceof Error ? err.message : String(err))
|
|
193
|
-
);
|
|
133
|
+
return canvas.toDataURL("image/png");
|
|
134
|
+
} finally {
|
|
135
|
+
scroller.scrollTop = old;
|
|
194
136
|
}
|
|
195
|
-
return;
|
|
196
137
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
className: "hv-btn",
|
|
221
|
-
onClick: () => exec("italic"),
|
|
222
|
-
disabled: readOnly,
|
|
223
|
-
children: "I"
|
|
224
|
-
}
|
|
225
|
-
),
|
|
226
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
227
|
-
"button",
|
|
228
|
-
{
|
|
229
|
-
className: "hv-btn",
|
|
230
|
-
onClick: () => exec("underline"),
|
|
231
|
-
disabled: readOnly,
|
|
232
|
-
children: "U"
|
|
233
|
-
}
|
|
234
|
-
),
|
|
235
|
-
props.armedSignatureUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-hint", children: "Click to place signature" }) : null
|
|
236
|
-
] }),
|
|
237
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-scroll", ref: scrollerRef, onClick, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hv-pageStage", ref: captureRef, children: [
|
|
238
|
-
props.headerFooterEnabled && props.headerComponent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-letterhead", children: props.headerComponent }) : null,
|
|
239
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
138
|
+
async function save(exportPdf) {
|
|
139
|
+
const html = editorRef.current?.innerHTML ?? "";
|
|
140
|
+
const stitched = `<!doctype html><html><body>${html}</body></html>`;
|
|
141
|
+
const b64 = btoa(unescape(encodeURIComponent(stitched)));
|
|
142
|
+
props.onSave(b64, {
|
|
143
|
+
fileName: props.fileName,
|
|
144
|
+
fileType: props.fileType,
|
|
145
|
+
exportedAsPdf: exportPdf,
|
|
146
|
+
annotations: { signaturePlacements: props.signaturePlacements }
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
150
|
+
save,
|
|
151
|
+
requestThumbnail
|
|
152
|
+
}));
|
|
153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hv-root", children: [
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hv-toolbar", children: [
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => exec("bold"), disabled: readOnly, children: "B" }),
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => exec("italic"), disabled: readOnly, children: "I" }),
|
|
157
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => exec("underline"), disabled: readOnly, children: "U" }),
|
|
158
|
+
props.armedSignatureUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hv-hint", children: "Click page to place signature" })
|
|
159
|
+
] }),
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-scroll", ref: scrollerRef, onClick: onClickPage, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-pageStage", ref: captureRef, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
240
161
|
"div",
|
|
241
162
|
{
|
|
242
163
|
ref: editorRef,
|
|
243
|
-
className: readOnly ? "
|
|
164
|
+
className: `hv-editor ${readOnly ? "ro" : ""}`,
|
|
244
165
|
contentEditable: !readOnly,
|
|
245
|
-
suppressContentEditableWarning: true
|
|
246
|
-
onInput: () => setHtml(editorRef.current?.innerHTML ?? ""),
|
|
247
|
-
dangerouslySetInnerHTML: { __html: html }
|
|
166
|
+
suppressContentEditableWarning: true
|
|
248
167
|
}
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
"img",
|
|
254
|
-
{
|
|
255
|
-
src: s.signatureImageUrl,
|
|
256
|
-
alt: "",
|
|
257
|
-
className: "hv-sign-img"
|
|
258
|
-
}
|
|
259
|
-
),
|
|
260
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
261
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-sign-name", children: s.signedBy }),
|
|
262
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hv-sign-date", children: new Date(s.dateSigned).toLocaleString() })
|
|
263
|
-
] })
|
|
264
|
-
] }, i)) }) : null
|
|
265
|
-
] }) })
|
|
266
|
-
] });
|
|
267
|
-
});
|
|
268
|
-
function replaceExt(name, ext) {
|
|
269
|
-
const base = name.includes(".") ? name.slice(0, name.lastIndexOf(".")) : name;
|
|
270
|
-
return `${base}.${ext}`;
|
|
271
|
-
}
|
|
168
|
+
) }) })
|
|
169
|
+
] });
|
|
170
|
+
}
|
|
171
|
+
);
|
|
272
172
|
function escapeHtml(s) {
|
|
273
|
-
return s.replace(/&/g, "&").replace(/</g, "<")
|
|
173
|
+
return s.replace(/&/g, "&").replace(/</g, "<");
|
|
274
174
|
}
|
|
275
175
|
|
|
276
176
|
// src/editors/SpreadsheetEditor.tsx
|
|
@@ -968,12 +868,12 @@ function Toolbar(props) {
|
|
|
968
868
|
role: "toolbar",
|
|
969
869
|
"aria-label": t("a11y.toolbar", "Document toolbar"),
|
|
970
870
|
children: [
|
|
971
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hv-toolbar__left
|
|
871
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hv-toolbar__left space-x-1", children: [
|
|
972
872
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
973
873
|
"button",
|
|
974
874
|
{
|
|
975
875
|
type: "button",
|
|
976
|
-
className: "hv-btn",
|
|
876
|
+
className: "hv-btn text-sm",
|
|
977
877
|
onClick: props.onToggleThumbnails,
|
|
978
878
|
"aria-pressed": props.showThumbnails,
|
|
979
879
|
children: t("toolbar.thumbs", "Thumbnails")
|
|
@@ -983,7 +883,7 @@ function Toolbar(props) {
|
|
|
983
883
|
"button",
|
|
984
884
|
{
|
|
985
885
|
type: "button",
|
|
986
|
-
className: "hv-btn",
|
|
886
|
+
className: "hv-btn text-sm",
|
|
987
887
|
onClick: props.onToggleSignatures,
|
|
988
888
|
"aria-pressed": props.showSignatures,
|
|
989
889
|
children: t("toolbar.signatures", "Signatures")
|
|
@@ -994,7 +894,7 @@ function Toolbar(props) {
|
|
|
994
894
|
"button",
|
|
995
895
|
{
|
|
996
896
|
type: "button",
|
|
997
|
-
className: props.layout === "single" ? "hv-btn hv-btn--active" : "hv-btn",
|
|
897
|
+
className: props.layout === "single" ? "hv-btn hv-btn--active text-sm" : "hv-btn text-sm",
|
|
998
898
|
onClick: () => props.onChangeLayout("single"),
|
|
999
899
|
children: t("toolbar.layout.single", "Single")
|
|
1000
900
|
}
|
|
@@ -1003,7 +903,7 @@ function Toolbar(props) {
|
|
|
1003
903
|
"button",
|
|
1004
904
|
{
|
|
1005
905
|
type: "button",
|
|
1006
|
-
className: props.layout === "side-by-side" ? "hv-btn hv-btn--active" : "hv-btn",
|
|
906
|
+
className: props.layout === "side-by-side" ? "hv-btn hv-btn--active text-sm" : "hv-btn text-sm",
|
|
1007
907
|
onClick: () => props.onChangeLayout("side-by-side"),
|
|
1008
908
|
children: t("toolbar.layout.two", "Two")
|
|
1009
909
|
}
|
|
@@ -1025,18 +925,26 @@ function Toolbar(props) {
|
|
|
1025
925
|
"button",
|
|
1026
926
|
{
|
|
1027
927
|
type: "button",
|
|
1028
|
-
className: "hv-btn hv-btn--primary",
|
|
928
|
+
className: "hv-btn hv-btn--primary text-sm",
|
|
1029
929
|
onClick: props.onSign,
|
|
1030
930
|
disabled: props.signingDisabled,
|
|
1031
931
|
children: t("toolbar.sign", "Sign Document")
|
|
1032
932
|
}
|
|
1033
933
|
),
|
|
1034
|
-
props.canExportPdf && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
934
|
+
props.canExportPdf && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
935
|
+
"button",
|
|
936
|
+
{
|
|
937
|
+
type: "button",
|
|
938
|
+
className: "hv-btn text-sm",
|
|
939
|
+
onClick: props.onExportPdf,
|
|
940
|
+
children: t("toolbar.exportPdf", "Export as PDF")
|
|
941
|
+
}
|
|
942
|
+
),
|
|
1035
943
|
props.canSave && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1036
944
|
"button",
|
|
1037
945
|
{
|
|
1038
946
|
type: "button",
|
|
1039
|
-
className: "hv-btn hv-btn--primary",
|
|
947
|
+
className: "hv-btn hv-btn--primary text-sm",
|
|
1040
948
|
onClick: props.onSave,
|
|
1041
949
|
children: t("toolbar.save", "Save")
|
|
1042
950
|
}
|
|
@@ -1052,8 +960,13 @@ var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
|
1052
960
|
function DocumentViewer(props) {
|
|
1053
961
|
const mode = props.mode ?? "view";
|
|
1054
962
|
const theme = props.theme ?? "light";
|
|
1055
|
-
const locale = (0, import_react7.useMemo)(
|
|
1056
|
-
|
|
963
|
+
const locale = (0, import_react7.useMemo)(
|
|
964
|
+
() => ({ ...defaultLocale, ...props.locale ?? {} }),
|
|
965
|
+
[props.locale]
|
|
966
|
+
);
|
|
967
|
+
const [layout, setLayout] = (0, import_react7.useState)(
|
|
968
|
+
props.defaultLayout ?? "single"
|
|
969
|
+
);
|
|
1057
970
|
const [showThumbnails, setShowThumbnails] = (0, import_react7.useState)(true);
|
|
1058
971
|
const [showSignatures, setShowSignatures] = (0, import_react7.useState)(true);
|
|
1059
972
|
const [headerFooterEnabled, setHeaderFooterEnabled] = (0, import_react7.useState)(true);
|
|
@@ -1064,10 +977,17 @@ function DocumentViewer(props) {
|
|
|
1064
977
|
const [pageCount, setPageCount] = (0, import_react7.useState)(1);
|
|
1065
978
|
const [currentPage, setCurrentPage] = (0, import_react7.useState)(1);
|
|
1066
979
|
const [thumbs, setThumbs] = (0, import_react7.useState)([]);
|
|
1067
|
-
const [localSignatures, setLocalSignatures] = (0, import_react7.useState)(
|
|
1068
|
-
|
|
980
|
+
const [localSignatures, setLocalSignatures] = (0, import_react7.useState)(
|
|
981
|
+
props.signatures ?? []
|
|
982
|
+
);
|
|
983
|
+
(0, import_react7.useEffect)(
|
|
984
|
+
() => setLocalSignatures(props.signatures ?? []),
|
|
985
|
+
[props.signatures]
|
|
986
|
+
);
|
|
1069
987
|
const [sigPlacements, setSigPlacements] = (0, import_react7.useState)([]);
|
|
1070
|
-
const [armedSignatureUrl, setArmedSignatureUrl] = (0, import_react7.useState)(
|
|
988
|
+
const [armedSignatureUrl, setArmedSignatureUrl] = (0, import_react7.useState)(
|
|
989
|
+
null
|
|
990
|
+
);
|
|
1071
991
|
const editorRef = (0, import_react7.useRef)(null);
|
|
1072
992
|
(0, import_react7.useEffect)(() => {
|
|
1073
993
|
let cancelled = false;
|
|
@@ -1081,7 +1001,10 @@ function DocumentViewer(props) {
|
|
|
1081
1001
|
setArmedSignatureUrl(null);
|
|
1082
1002
|
if (mode === "create") {
|
|
1083
1003
|
const ft = props.fileType ?? "docx";
|
|
1084
|
-
setResolved({
|
|
1004
|
+
setResolved({
|
|
1005
|
+
fileType: ft,
|
|
1006
|
+
fileName: props.fileName ?? `Untitled.${ft}`
|
|
1007
|
+
});
|
|
1085
1008
|
return;
|
|
1086
1009
|
}
|
|
1087
1010
|
try {
|
|
@@ -1095,7 +1018,12 @@ function DocumentViewer(props) {
|
|
|
1095
1018
|
if (cancelled) {
|
|
1096
1019
|
return;
|
|
1097
1020
|
}
|
|
1098
|
-
setResolved({
|
|
1021
|
+
setResolved({
|
|
1022
|
+
fileType: res.fileType,
|
|
1023
|
+
fileName: res.fileName,
|
|
1024
|
+
url: res.url,
|
|
1025
|
+
arrayBuffer: res.arrayBuffer
|
|
1026
|
+
});
|
|
1099
1027
|
} catch (e) {
|
|
1100
1028
|
if (cancelled) {
|
|
1101
1029
|
return;
|
|
@@ -1106,7 +1034,14 @@ function DocumentViewer(props) {
|
|
|
1106
1034
|
return () => {
|
|
1107
1035
|
cancelled = true;
|
|
1108
1036
|
};
|
|
1109
|
-
}, [
|
|
1037
|
+
}, [
|
|
1038
|
+
mode,
|
|
1039
|
+
props.fileUrl,
|
|
1040
|
+
props.base64,
|
|
1041
|
+
props.blob,
|
|
1042
|
+
props.fileName,
|
|
1043
|
+
props.fileType
|
|
1044
|
+
]);
|
|
1110
1045
|
const thumbnails = (0, import_react7.useMemo)(() => {
|
|
1111
1046
|
const n = Math.max(1, pageCount);
|
|
1112
1047
|
return Array.from({ length: n }, (_, i) => ({
|
|
@@ -1132,7 +1067,10 @@ function DocumentViewer(props) {
|
|
|
1132
1067
|
if (!armedSignatureUrl) {
|
|
1133
1068
|
return;
|
|
1134
1069
|
}
|
|
1135
|
-
setSigPlacements((prev) => [
|
|
1070
|
+
setSigPlacements((prev) => [
|
|
1071
|
+
...prev,
|
|
1072
|
+
{ ...p, signatureImageUrl: armedSignatureUrl }
|
|
1073
|
+
]);
|
|
1136
1074
|
setArmedSignatureUrl(null);
|
|
1137
1075
|
}
|
|
1138
1076
|
async function handleSave(exportPdf) {
|
|
@@ -1144,7 +1082,11 @@ function DocumentViewer(props) {
|
|
|
1144
1082
|
return;
|
|
1145
1083
|
}
|
|
1146
1084
|
const b64 = arrayBufferToBase642(resolved.arrayBuffer);
|
|
1147
|
-
props.onSave?.(b64, {
|
|
1085
|
+
props.onSave?.(b64, {
|
|
1086
|
+
fileName: resolved.fileName,
|
|
1087
|
+
fileType: resolved.fileType,
|
|
1088
|
+
annotations: { sigPlacements }
|
|
1089
|
+
});
|
|
1148
1090
|
}
|
|
1149
1091
|
const canSave = mode === "edit" || mode === "create";
|
|
1150
1092
|
const canExportPdf = (mode === "edit" || mode === "create") && (resolved?.fileType === "docx" || resolved?.fileType === "md" || resolved?.fileType === "txt" || resolved?.fileType === "xlsx");
|
|
@@ -1201,10 +1143,16 @@ function DocumentViewer(props) {
|
|
|
1201
1143
|
onCurrentPageChange: setCurrentPage,
|
|
1202
1144
|
onPageCount: (n) => {
|
|
1203
1145
|
setPageCount(n);
|
|
1204
|
-
setThumbs(
|
|
1146
|
+
setThumbs(
|
|
1147
|
+
(prev) => prev.length === n ? prev : Array.from({ length: n }, (_, i) => prev[i])
|
|
1148
|
+
);
|
|
1205
1149
|
},
|
|
1206
1150
|
onThumbs: (t) => setThumbs(t),
|
|
1207
|
-
signatureStamp: armedSignatureUrl ? {
|
|
1151
|
+
signatureStamp: armedSignatureUrl ? {
|
|
1152
|
+
imageUrl: armedSignatureUrl,
|
|
1153
|
+
armed: true,
|
|
1154
|
+
onPlaced: placeSignature
|
|
1155
|
+
} : void 0
|
|
1208
1156
|
}
|
|
1209
1157
|
) : null,
|
|
1210
1158
|
resolved.fileType === "docx" || resolved.fileType === "md" || resolved.fileType === "txt" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
@@ -1223,7 +1171,9 @@ function DocumentViewer(props) {
|
|
|
1223
1171
|
signaturePlacements: sigPlacements,
|
|
1224
1172
|
onPageCount: (n) => {
|
|
1225
1173
|
setPageCount(n);
|
|
1226
|
-
setThumbs(
|
|
1174
|
+
setThumbs(
|
|
1175
|
+
(prev) => prev.length === n ? prev : Array.from({ length: n }, (_, i) => prev[i])
|
|
1176
|
+
);
|
|
1227
1177
|
},
|
|
1228
1178
|
onSave: (b64, meta) => props.onSave?.(b64, meta),
|
|
1229
1179
|
armedSignatureUrl,
|
|
@@ -1250,12 +1200,21 @@ function DocumentViewer(props) {
|
|
|
1250
1200
|
onCurrentPageChange: setCurrentPage,
|
|
1251
1201
|
onSlideCount: (n) => {
|
|
1252
1202
|
setPageCount(n);
|
|
1253
|
-
setThumbs(
|
|
1203
|
+
setThumbs(
|
|
1204
|
+
(prev) => prev.length === n ? prev : Array.from({ length: n }, (_, i) => prev[i])
|
|
1205
|
+
);
|
|
1254
1206
|
},
|
|
1255
1207
|
onThumbs: (t) => setThumbs(t)
|
|
1256
1208
|
}
|
|
1257
1209
|
) : null,
|
|
1258
|
-
resolved.fileType === "png" || resolved.fileType === "jpg" || resolved.fileType === "svg" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1210
|
+
resolved.fileType === "png" || resolved.fileType === "jpg" || resolved.fileType === "svg" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1211
|
+
ImageRenderer,
|
|
1212
|
+
{
|
|
1213
|
+
arrayBuffer: resolved.arrayBuffer,
|
|
1214
|
+
fileType: resolved.fileType,
|
|
1215
|
+
fileName: resolved.fileName
|
|
1216
|
+
}
|
|
1217
|
+
) : null
|
|
1259
1218
|
] }),
|
|
1260
1219
|
mode !== "create" && localSignatures.length ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1261
1220
|
SignaturePanel,
|