@kitsy/pdf 0.0.0-stage → 0.1.0
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/CHANGELOG.md +22 -0
- package/LICENSE +201 -0
- package/NOTICE +16 -0
- package/README.md +229 -2
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/dist/chunk-2K5X7L5J.js +43 -0
- package/dist/chunk-2K5X7L5J.js.map +1 -0
- package/dist/chunk-4EAYBJ6G.js +362 -0
- package/dist/chunk-4EAYBJ6G.js.map +1 -0
- package/dist/chunk-4LBJTDV5.js +165 -0
- package/dist/chunk-4LBJTDV5.js.map +1 -0
- package/dist/chunk-4USCGC24.js +304 -0
- package/dist/chunk-4USCGC24.js.map +1 -0
- package/dist/chunk-5OIMR74G.js +273 -0
- package/dist/chunk-5OIMR74G.js.map +1 -0
- package/dist/chunk-6NFNAKWA.js +257 -0
- package/dist/chunk-6NFNAKWA.js.map +1 -0
- package/dist/chunk-7MTEMQLL.js +47 -0
- package/dist/chunk-7MTEMQLL.js.map +1 -0
- package/dist/chunk-7V4SWTUK.js +83 -0
- package/dist/chunk-7V4SWTUK.js.map +1 -0
- package/dist/chunk-7XH7MFZ4.js +295 -0
- package/dist/chunk-7XH7MFZ4.js.map +1 -0
- package/dist/chunk-BK3MYSUS.js +61 -0
- package/dist/chunk-BK3MYSUS.js.map +1 -0
- package/dist/chunk-BLHNKR3S.js +35 -0
- package/dist/chunk-BLHNKR3S.js.map +1 -0
- package/dist/chunk-CCJ43SIX.js +342 -0
- package/dist/chunk-CCJ43SIX.js.map +1 -0
- package/dist/chunk-CNEDWATL.js +210 -0
- package/dist/chunk-CNEDWATL.js.map +1 -0
- package/dist/chunk-CYTWDJE2.js +152 -0
- package/dist/chunk-CYTWDJE2.js.map +1 -0
- package/dist/chunk-DKVOICYZ.js +45 -0
- package/dist/chunk-DKVOICYZ.js.map +1 -0
- package/dist/chunk-DPEJU4P6.js +79 -0
- package/dist/chunk-DPEJU4P6.js.map +1 -0
- package/dist/chunk-DQPABZTU.js +22 -0
- package/dist/chunk-DQPABZTU.js.map +1 -0
- package/dist/chunk-EKHEY3LI.js +46 -0
- package/dist/chunk-EKHEY3LI.js.map +1 -0
- package/dist/chunk-G467LFKC.js +191 -0
- package/dist/chunk-G467LFKC.js.map +1 -0
- package/dist/chunk-GLYWSVSB.js +250 -0
- package/dist/chunk-GLYWSVSB.js.map +1 -0
- package/dist/chunk-GXBIMUO7.js +135 -0
- package/dist/chunk-GXBIMUO7.js.map +1 -0
- package/dist/chunk-H6EERRCR.js +180 -0
- package/dist/chunk-H6EERRCR.js.map +1 -0
- package/dist/chunk-HDTM3LXD.js +35 -0
- package/dist/chunk-HDTM3LXD.js.map +1 -0
- package/dist/chunk-IGMX56C3.js +180 -0
- package/dist/chunk-IGMX56C3.js.map +1 -0
- package/dist/chunk-J4IRICCJ.js +74 -0
- package/dist/chunk-J4IRICCJ.js.map +1 -0
- package/dist/chunk-JXKQ7S6W.js +331 -0
- package/dist/chunk-JXKQ7S6W.js.map +1 -0
- package/dist/chunk-KY6DXS6S.js +34 -0
- package/dist/chunk-KY6DXS6S.js.map +1 -0
- package/dist/chunk-NOFGCYGS.js +22 -0
- package/dist/chunk-NOFGCYGS.js.map +1 -0
- package/dist/chunk-OSHUJRKD.js +131 -0
- package/dist/chunk-OSHUJRKD.js.map +1 -0
- package/dist/chunk-PMH7OWPF.js +40 -0
- package/dist/chunk-PMH7OWPF.js.map +1 -0
- package/dist/chunk-PRBKSX3A.js +299 -0
- package/dist/chunk-PRBKSX3A.js.map +1 -0
- package/dist/chunk-SVPUX7AM.js +48 -0
- package/dist/chunk-SVPUX7AM.js.map +1 -0
- package/dist/chunk-TR6HJ4NO.js +659 -0
- package/dist/chunk-TR6HJ4NO.js.map +1 -0
- package/dist/chunk-TV3E4YUF.js +69 -0
- package/dist/chunk-TV3E4YUF.js.map +1 -0
- package/dist/chunk-U2ROTOPF.js +256 -0
- package/dist/chunk-U2ROTOPF.js.map +1 -0
- package/dist/chunk-VCTN77K2.js +112 -0
- package/dist/chunk-VCTN77K2.js.map +1 -0
- package/dist/chunk-WEOPDD3P.js +120 -0
- package/dist/chunk-WEOPDD3P.js.map +1 -0
- package/dist/chunk-ZBZ7OC6I.js +228 -0
- package/dist/chunk-ZBZ7OC6I.js.map +1 -0
- package/dist/config-CJYo46X9.d.ts +19 -0
- package/dist/index.d.ts +487 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/react/certificate-sign.d.ts +5 -0
- package/dist/react/certificate-sign.js +14 -0
- package/dist/react/certificate-sign.js.map +1 -0
- package/dist/react/compress.d.ts +5 -0
- package/dist/react/compress.js +8 -0
- package/dist/react/compress.js.map +1 -0
- package/dist/react/fill-form.d.ts +5 -0
- package/dist/react/fill-form.js +8 -0
- package/dist/react/fill-form.js.map +1 -0
- package/dist/react/images-to-pdf.d.ts +5 -0
- package/dist/react/images-to-pdf.js +7 -0
- package/dist/react/images-to-pdf.js.map +1 -0
- package/dist/react/merge.d.ts +5 -0
- package/dist/react/merge.js +8 -0
- package/dist/react/merge.js.map +1 -0
- package/dist/react/metadata.d.ts +5 -0
- package/dist/react/metadata.js +8 -0
- package/dist/react/metadata.js.map +1 -0
- package/dist/react/organize.d.ts +5 -0
- package/dist/react/organize.js +12 -0
- package/dist/react/organize.js.map +1 -0
- package/dist/react/pdf-to-images.d.ts +5 -0
- package/dist/react/pdf-to-images.js +13 -0
- package/dist/react/pdf-to-images.js.map +1 -0
- package/dist/react/protect.d.ts +5 -0
- package/dist/react/protect.js +8 -0
- package/dist/react/protect.js.map +1 -0
- package/dist/react/sign.d.ts +5 -0
- package/dist/react/sign.js +13 -0
- package/dist/react/sign.js.map +1 -0
- package/dist/react/split.d.ts +5 -0
- package/dist/react/split.js +11 -0
- package/dist/react/split.js.map +1 -0
- package/dist/react/verify-signatures.d.ts +5 -0
- package/dist/react/verify-signatures.js +8 -0
- package/dist/react/verify-signatures.js.map +1 -0
- package/dist/react/watermark.d.ts +5 -0
- package/dist/react/watermark.js +10 -0
- package/dist/react/watermark.js.map +1 -0
- package/dist/react.d.ts +40 -0
- package/dist/react.js +40 -0
- package/dist/react.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.js +9 -0
- package/dist/vite.js.map +1 -0
- package/package.json +163 -4
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { readFormFields, fillForm } from './chunk-CYTWDJE2.js';
|
|
2
|
+
import { useSinglePdf } from './chunk-BK3MYSUS.js';
|
|
3
|
+
import { PdfToolPage, PdfToolColumns, SummaryList, SideTips, SelectedPdfCard, FileDropzone, cardClass, StatusBanner, primaryButtonClass, secondaryButtonClass, BackToPdfTools, fieldLabelClass, inputClass } from './chunk-H6EERRCR.js';
|
|
4
|
+
import { downloadBlob, toBaseName, formatBytes } from './chunk-EKHEY3LI.js';
|
|
5
|
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function friendlyName(name) {
|
|
9
|
+
const last = name.split(".").pop() || name;
|
|
10
|
+
return last.replace(/\[\d+\]$/, "").replace(/[_-]+/g, " ").trim() || name;
|
|
11
|
+
}
|
|
12
|
+
function initialValues(fields) {
|
|
13
|
+
return Object.fromEntries(fields.map((field) => [field.name, field.value]));
|
|
14
|
+
}
|
|
15
|
+
function FieldInput({ field, value, onChange, disabled }) {
|
|
16
|
+
const id = `field-${field.name}`;
|
|
17
|
+
const locked = disabled || field.readOnly;
|
|
18
|
+
if (field.kind === "checkbox") {
|
|
19
|
+
return /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "flex items-center gap-3 text-sm text-slate-800 dark:text-slate-200", children: [
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"input",
|
|
22
|
+
{
|
|
23
|
+
id,
|
|
24
|
+
type: "checkbox",
|
|
25
|
+
checked: Boolean(value),
|
|
26
|
+
disabled: locked,
|
|
27
|
+
onChange: (event) => onChange(event.target.checked),
|
|
28
|
+
className: "h-4 w-4 accent-[#1F8CFF]"
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
friendlyName(field.name),
|
|
32
|
+
field.required ? /* @__PURE__ */ jsx("span", { className: "text-rose-600", children: "*" }) : null
|
|
33
|
+
] });
|
|
34
|
+
}
|
|
35
|
+
const label = /* @__PURE__ */ jsxs("span", { className: fieldLabelClass, title: field.name, children: [
|
|
36
|
+
friendlyName(field.name),
|
|
37
|
+
field.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-rose-600", children: "*" }) : null,
|
|
38
|
+
field.readOnly ? /* @__PURE__ */ jsx("span", { className: "ml-2 normal-case tracking-normal text-slate-400", children: "(read-only)" }) : null
|
|
39
|
+
] });
|
|
40
|
+
if (field.kind === "radio") {
|
|
41
|
+
return /* @__PURE__ */ jsxs("fieldset", { disabled: locked, children: [
|
|
42
|
+
/* @__PURE__ */ jsx("legend", { children: label }),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap gap-3", children: [
|
|
44
|
+
field.options.map((option) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-slate-800 dark:text-slate-200", children: [
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
"input",
|
|
47
|
+
{
|
|
48
|
+
type: "radio",
|
|
49
|
+
name: id,
|
|
50
|
+
checked: value === option,
|
|
51
|
+
onChange: () => onChange(option),
|
|
52
|
+
className: "h-4 w-4 accent-[#1F8CFF]"
|
|
53
|
+
}
|
|
54
|
+
),
|
|
55
|
+
option
|
|
56
|
+
] }, option)),
|
|
57
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => onChange(""), className: "text-xs text-slate-500 underline", children: "Clear" })
|
|
58
|
+
] })
|
|
59
|
+
] });
|
|
60
|
+
}
|
|
61
|
+
if (field.kind === "dropdown") {
|
|
62
|
+
return /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "block", children: [
|
|
63
|
+
label,
|
|
64
|
+
/* @__PURE__ */ jsxs("select", { id, value, disabled: locked, onChange: (event) => onChange(event.target.value), className: `mt-2 ${inputClass}`, children: [
|
|
65
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
|
|
66
|
+
field.options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
|
|
67
|
+
] })
|
|
68
|
+
] });
|
|
69
|
+
}
|
|
70
|
+
if (field.kind === "list") {
|
|
71
|
+
return /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "block", children: [
|
|
72
|
+
label,
|
|
73
|
+
/* @__PURE__ */ jsxs(
|
|
74
|
+
"select",
|
|
75
|
+
{
|
|
76
|
+
id,
|
|
77
|
+
multiple: field.multiSelect,
|
|
78
|
+
value: field.multiSelect ? value : value[0] ?? "",
|
|
79
|
+
disabled: locked,
|
|
80
|
+
onChange: (event) => onChange(Array.from(event.target.selectedOptions, (option) => option.value).filter(Boolean)),
|
|
81
|
+
className: `mt-2 ${inputClass}`,
|
|
82
|
+
children: [
|
|
83
|
+
field.multiSelect ? null : /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
|
|
84
|
+
field.options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
if (field.kind === "text") {
|
|
91
|
+
const props = {
|
|
92
|
+
id,
|
|
93
|
+
value,
|
|
94
|
+
disabled: locked,
|
|
95
|
+
maxLength: field.maxLength,
|
|
96
|
+
onChange: (event) => onChange(event.target.value),
|
|
97
|
+
className: `mt-2 ${inputClass}`
|
|
98
|
+
};
|
|
99
|
+
return /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "block", children: [
|
|
100
|
+
label,
|
|
101
|
+
field.multiline ? /* @__PURE__ */ jsx("textarea", { rows: 3, ...props }) : /* @__PURE__ */ jsx("input", { type: "text", ...props }),
|
|
102
|
+
field.maxLength ? /* @__PURE__ */ jsxs("span", { className: "mt-1 block text-right text-[11px] text-slate-400", children: [
|
|
103
|
+
String(value).length,
|
|
104
|
+
"/",
|
|
105
|
+
field.maxLength
|
|
106
|
+
] }) : null
|
|
107
|
+
] });
|
|
108
|
+
}
|
|
109
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
110
|
+
label,
|
|
111
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: field.kind === "signature" ? "Signature field: use Sign PDF to add a visible signature." : "Button: nothing to fill." })
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
function FillPdfForm() {
|
|
115
|
+
const [fields, setFields] = useState([]);
|
|
116
|
+
const [values, setValues] = useState({});
|
|
117
|
+
const [hasXfa, setHasXfa] = useState(false);
|
|
118
|
+
const [flatten, setFlatten] = useState(false);
|
|
119
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
120
|
+
const [status, setStatus] = useState({
|
|
121
|
+
tone: "info",
|
|
122
|
+
text: "Add a PDF form to fill in its fields."
|
|
123
|
+
});
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
document.title = "Fill PDF Forms | Apps";
|
|
126
|
+
}, []);
|
|
127
|
+
const onError = useCallback((text) => setStatus({ tone: "error", text }), []);
|
|
128
|
+
const onLoaded = useCallback(async ({ file, bytes }) => {
|
|
129
|
+
try {
|
|
130
|
+
const result = await readFormFields(bytes);
|
|
131
|
+
setFields(result.fields);
|
|
132
|
+
setValues(initialValues(result.fields));
|
|
133
|
+
setHasXfa(result.hasXfa);
|
|
134
|
+
setStatus(
|
|
135
|
+
result.fields.length ? { tone: "success", text: `${file.name} has ${result.fields.length} field${result.fields.length === 1 ? "" : "s"}. Fill them in and download.` } : { tone: "info", text: `${file.name} has no fillable form fields. Use Sign PDF or Watermark to add text instead.` }
|
|
136
|
+
);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
setStatus({ tone: "error", text: error?.message || "Could not read this PDF." });
|
|
139
|
+
}
|
|
140
|
+
}, []);
|
|
141
|
+
const pdf = useSinglePdf({ onError, onLoaded });
|
|
142
|
+
const groups = useMemo(() => {
|
|
143
|
+
const byPage = /* @__PURE__ */ new Map();
|
|
144
|
+
for (const field of fields) {
|
|
145
|
+
const key = field.page ?? 0;
|
|
146
|
+
if (!byPage.has(key)) byPage.set(key, []);
|
|
147
|
+
byPage.get(key).push(field);
|
|
148
|
+
}
|
|
149
|
+
return [...byPage.entries()].sort(([a], [b]) => (a || Infinity) - (b || Infinity));
|
|
150
|
+
}, [fields]);
|
|
151
|
+
const editable = fields.filter((field) => !field.readOnly && field.kind !== "button" && field.kind !== "signature");
|
|
152
|
+
const missingRequired = editable.filter((field) => {
|
|
153
|
+
const value = values[field.name];
|
|
154
|
+
return field.required && (Array.isArray(value) ? !value.length : !value);
|
|
155
|
+
});
|
|
156
|
+
const clearFile = () => {
|
|
157
|
+
pdf.clear();
|
|
158
|
+
setFields([]);
|
|
159
|
+
setValues({});
|
|
160
|
+
setHasXfa(false);
|
|
161
|
+
};
|
|
162
|
+
const handleSave = async (event) => {
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
if (!pdf.bytes || !editable.length) return;
|
|
165
|
+
setIsSaving(true);
|
|
166
|
+
setStatus({ tone: "info", text: "Filling your PDF..." });
|
|
167
|
+
try {
|
|
168
|
+
const bytes = await fillForm(pdf.bytes, values, { flatten });
|
|
169
|
+
const blob = new Blob([bytes], { type: "application/pdf" });
|
|
170
|
+
downloadBlob(blob, `${toBaseName(pdf.file.name, "form")}-filled.pdf`);
|
|
171
|
+
setStatus({
|
|
172
|
+
tone: "success",
|
|
173
|
+
text: `Saved (${formatBytes(blob.size)})${flatten ? " with answers locked in" : ""}. Your download has started.${missingRequired.length ? ` Note: ${missingRequired.length} required field${missingRequired.length === 1 ? " is" : "s are"} still empty.` : ""}`
|
|
174
|
+
});
|
|
175
|
+
} catch (error) {
|
|
176
|
+
setStatus({ tone: "error", text: `Could not fill the form: ${error?.message || "Please try again."}` });
|
|
177
|
+
} finally {
|
|
178
|
+
setIsSaving(false);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const busy = isSaving || pdf.isReading;
|
|
182
|
+
return /* @__PURE__ */ jsx(
|
|
183
|
+
PdfToolPage,
|
|
184
|
+
{
|
|
185
|
+
title: "Fill PDF Forms",
|
|
186
|
+
description: "Fill in the text boxes, checkboxes, and choices of a PDF form, then download it, optionally locked so answers can't be changed. Runs in your browser; your answers never leave your device.",
|
|
187
|
+
stats: [
|
|
188
|
+
{ value: fields.length || "-", label: "Fields" },
|
|
189
|
+
{ value: pdf.pageCount || "-", label: "Pages" }
|
|
190
|
+
],
|
|
191
|
+
children: /* @__PURE__ */ jsx(
|
|
192
|
+
PdfToolColumns,
|
|
193
|
+
{
|
|
194
|
+
main: /* @__PURE__ */ jsxs("form", { onSubmit: handleSave, children: [
|
|
195
|
+
pdf.file ? /* @__PURE__ */ jsx(
|
|
196
|
+
SelectedPdfCard,
|
|
197
|
+
{
|
|
198
|
+
signed: pdf.signed,
|
|
199
|
+
file: pdf.file,
|
|
200
|
+
pageCount: pdf.pageCount,
|
|
201
|
+
onRemove: clearFile,
|
|
202
|
+
disabled: isSaving
|
|
203
|
+
}
|
|
204
|
+
) : /* @__PURE__ */ jsx(
|
|
205
|
+
FileDropzone,
|
|
206
|
+
{
|
|
207
|
+
accept: ".pdf,application/pdf",
|
|
208
|
+
disabled: busy,
|
|
209
|
+
onFiles: pdf.selectFiles,
|
|
210
|
+
title: "Drag and drop a PDF form here",
|
|
211
|
+
hint: "or click to browse from your device"
|
|
212
|
+
}
|
|
213
|
+
),
|
|
214
|
+
hasXfa ? /* @__PURE__ */ jsx("p", { className: "mt-4 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200", children: "This form also contains an XFA (Adobe LiveCycle) version. It is removed when you save so every viewer shows the answers you enter here." }) : null,
|
|
215
|
+
groups.map(([page, pageFields]) => /* @__PURE__ */ jsxs("section", { className: `mt-5 ${cardClass}`, children: [
|
|
216
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: page ? `Page ${page}` : "Not on a page" }),
|
|
217
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 grid gap-4 sm:grid-cols-2", children: pageFields.map((field) => /* @__PURE__ */ jsx("div", { className: field.multiline || field.kind === "radio" ? "sm:col-span-2" : "", children: /* @__PURE__ */ jsx(
|
|
218
|
+
FieldInput,
|
|
219
|
+
{
|
|
220
|
+
field,
|
|
221
|
+
value: values[field.name],
|
|
222
|
+
disabled: busy,
|
|
223
|
+
onChange: (value) => setValues((current) => ({ ...current, [field.name]: value }))
|
|
224
|
+
}
|
|
225
|
+
) }, field.name)) })
|
|
226
|
+
] }, page)),
|
|
227
|
+
fields.length ? /* @__PURE__ */ jsxs("label", { className: "mt-5 flex items-start gap-3 text-sm text-slate-700 dark:text-slate-300", children: [
|
|
228
|
+
/* @__PURE__ */ jsx(
|
|
229
|
+
"input",
|
|
230
|
+
{
|
|
231
|
+
type: "checkbox",
|
|
232
|
+
checked: flatten,
|
|
233
|
+
onChange: (event) => setFlatten(event.target.checked),
|
|
234
|
+
disabled: busy,
|
|
235
|
+
className: "mt-0.5 h-4 w-4 accent-[#1F8CFF]"
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
239
|
+
"Lock answers (flatten)",
|
|
240
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xs text-slate-500 dark:text-slate-400", children: "Draws your answers into the page and removes the form, so they can't be edited." })
|
|
241
|
+
] })
|
|
242
|
+
] }) : null,
|
|
243
|
+
/* @__PURE__ */ jsx(StatusBanner, { status }),
|
|
244
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-5 flex flex-wrap gap-3", children: [
|
|
245
|
+
/* @__PURE__ */ jsxs("button", { type: "submit", disabled: busy || !editable.length, className: primaryButtonClass, children: [
|
|
246
|
+
/* @__PURE__ */ jsx("i", { className: `fa-solid ${isSaving ? "fa-spinner fa-spin" : "fa-pen-to-square"}` }),
|
|
247
|
+
isSaving ? "Saving..." : "Fill & Download"
|
|
248
|
+
] }),
|
|
249
|
+
/* @__PURE__ */ jsxs(
|
|
250
|
+
"button",
|
|
251
|
+
{
|
|
252
|
+
type: "button",
|
|
253
|
+
onClick: () => setValues(initialValues(fields)),
|
|
254
|
+
disabled: busy || !fields.length,
|
|
255
|
+
className: secondaryButtonClass,
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ jsx("i", { className: "fa-solid fa-arrow-rotate-left" }),
|
|
258
|
+
"Reset"
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
),
|
|
262
|
+
/* @__PURE__ */ jsx(BackToPdfTools, {})
|
|
263
|
+
] })
|
|
264
|
+
] }),
|
|
265
|
+
side: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
266
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-slate-900 dark:text-slate-100", children: "Summary" }),
|
|
267
|
+
/* @__PURE__ */ jsx(
|
|
268
|
+
SummaryList,
|
|
269
|
+
{
|
|
270
|
+
items: [
|
|
271
|
+
{ label: "Fillable fields", value: pdf.file ? editable.length : "-" },
|
|
272
|
+
{ label: "Required, still empty", value: pdf.file ? missingRequired.length : "-" }
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
),
|
|
276
|
+
/* @__PURE__ */ jsx(
|
|
277
|
+
SideTips,
|
|
278
|
+
{
|
|
279
|
+
tips: [
|
|
280
|
+
"Hover a field label to see its full internal name.",
|
|
281
|
+
"Answers use Helvetica, so basic Latin characters only.",
|
|
282
|
+
"Scanned forms without real fields can be filled with Sign PDF \u2192 Type."
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
)
|
|
286
|
+
] })
|
|
287
|
+
}
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export { FillPdfForm };
|
|
294
|
+
//# sourceMappingURL=chunk-7XH7MFZ4.js.map
|
|
295
|
+
//# sourceMappingURL=chunk-7XH7MFZ4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/FillPdfForm.tsx"],"names":[],"mappings":"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","file":"chunk-7XH7MFZ4.js","sourcesContent":["import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { downloadBlob, formatBytes, toBaseName } from \"../shared/files\";\nimport {\n BackToPdfTools,\n FileDropzone,\n PdfToolColumns,\n PdfToolPage,\n SelectedPdfCard,\n SideTips,\n StatusBanner,\n SummaryList,\n cardClass,\n fieldLabelClass,\n inputClass,\n primaryButtonClass,\n secondaryButtonClass,\n} from \"../shared/ToolLayout\";\nimport { useSinglePdf } from \"../shared/useSinglePdf\";\nimport { fillForm, readFormFields } from \"./fillFormCore\";\n\n/** \"topmostSubform[0].Page1[0].FirstName[0]\" -> \"FirstName\". */\nfunction friendlyName(name) {\n const last = name.split(\".\").pop() || name;\n return last.replace(/\\[\\d+\\]$/, \"\").replace(/[_-]+/g, \" \").trim() || name;\n}\n\nfunction initialValues(fields) {\n return Object.fromEntries(fields.map((field) => [field.name, field.value]));\n}\n\nfunction FieldInput({ field, value, onChange, disabled }) {\n const id = `field-${field.name}`;\n const locked = disabled || field.readOnly;\n\n if (field.kind === \"checkbox\") {\n return (\n <label htmlFor={id} className=\"flex items-center gap-3 text-sm text-slate-800 dark:text-slate-200\">\n <input\n id={id}\n type=\"checkbox\"\n checked={Boolean(value)}\n disabled={locked}\n onChange={(event) => onChange(event.target.checked)}\n className=\"h-4 w-4 accent-[#1F8CFF]\"\n />\n {friendlyName(field.name)}\n {field.required ? <span className=\"text-rose-600\">*</span> : null}\n </label>\n );\n }\n\n const label = (\n <span className={fieldLabelClass} title={field.name}>\n {friendlyName(field.name)}\n {field.required ? <span className=\"ml-1 text-rose-600\">*</span> : null}\n {field.readOnly ? <span className=\"ml-2 normal-case tracking-normal text-slate-400\">(read-only)</span> : null}\n </span>\n );\n\n if (field.kind === \"radio\") {\n return (\n <fieldset disabled={locked}>\n <legend>{label}</legend>\n <div className=\"mt-2 flex flex-wrap gap-3\">\n {field.options.map((option) => (\n <label key={option} className=\"flex items-center gap-2 text-sm text-slate-800 dark:text-slate-200\">\n <input\n type=\"radio\"\n name={id}\n checked={value === option}\n onChange={() => onChange(option)}\n className=\"h-4 w-4 accent-[#1F8CFF]\"\n />\n {option}\n </label>\n ))}\n <button type=\"button\" onClick={() => onChange(\"\")} className=\"text-xs text-slate-500 underline\">\n Clear\n </button>\n </div>\n </fieldset>\n );\n }\n\n if (field.kind === \"dropdown\") {\n return (\n <label htmlFor={id} className=\"block\">\n {label}\n <select id={id} value={value} disabled={locked} onChange={(event) => onChange(event.target.value)} className={`mt-2 ${inputClass}`}>\n <option value=\"\">—</option>\n {field.options.map((option) => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.kind === \"list\") {\n return (\n <label htmlFor={id} className=\"block\">\n {label}\n <select\n id={id}\n multiple={field.multiSelect}\n value={field.multiSelect ? value : value[0] ?? \"\"}\n disabled={locked}\n onChange={(event) =>\n onChange(Array.from(event.target.selectedOptions, (option) => option.value).filter(Boolean))\n }\n className={`mt-2 ${inputClass}`}\n >\n {field.multiSelect ? null : <option value=\"\">—</option>}\n {field.options.map((option) => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.kind === \"text\") {\n const props = {\n id,\n value,\n disabled: locked,\n maxLength: field.maxLength,\n onChange: (event) => onChange(event.target.value),\n className: `mt-2 ${inputClass}`,\n };\n return (\n <label htmlFor={id} className=\"block\">\n {label}\n {field.multiline ? <textarea rows={3} {...props} /> : <input type=\"text\" {...props} />}\n {field.maxLength ? (\n <span className=\"mt-1 block text-right text-[11px] text-slate-400\">\n {String(value).length}/{field.maxLength}\n </span>\n ) : null}\n </label>\n );\n }\n\n return (\n <div>\n {label}\n <p className=\"mt-1 text-xs text-slate-500 dark:text-slate-400\">\n {field.kind === \"signature\"\n ? \"Signature field: use Sign PDF to add a visible signature.\"\n : \"Button: nothing to fill.\"}\n </p>\n </div>\n );\n}\n\nexport default function FillPdfForm() {\n const [fields, setFields] = useState([]);\n const [values, setValues] = useState({});\n const [hasXfa, setHasXfa] = useState(false);\n const [flatten, setFlatten] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [status, setStatus] = useState({\n tone: \"info\",\n text: \"Add a PDF form to fill in its fields.\",\n });\n\n useEffect(() => {\n document.title = \"Fill PDF Forms | Apps\";\n }, []);\n\n const onError = useCallback((text) => setStatus({ tone: \"error\", text }), []);\n const onLoaded = useCallback(async ({ file, bytes }) => {\n try {\n const result = await readFormFields(bytes);\n setFields(result.fields);\n setValues(initialValues(result.fields));\n setHasXfa(result.hasXfa);\n setStatus(\n result.fields.length\n ? { tone: \"success\", text: `${file.name} has ${result.fields.length} field${result.fields.length === 1 ? \"\" : \"s\"}. Fill them in and download.` }\n : { tone: \"info\", text: `${file.name} has no fillable form fields. Use Sign PDF or Watermark to add text instead.` }\n );\n } catch (error) {\n setStatus({ tone: \"error\", text: error?.message || \"Could not read this PDF.\" });\n }\n }, []);\n const pdf = useSinglePdf({ onError, onLoaded });\n\n const groups = useMemo(() => {\n const byPage = new Map();\n for (const field of fields) {\n const key = field.page ?? 0;\n if (!byPage.has(key)) byPage.set(key, []);\n byPage.get(key).push(field);\n }\n return [...byPage.entries()].sort(([a], [b]) => (a || Infinity) - (b || Infinity));\n }, [fields]);\n\n const editable = fields.filter((field) => !field.readOnly && field.kind !== \"button\" && field.kind !== \"signature\");\n const missingRequired = editable.filter((field) => {\n const value = values[field.name];\n return field.required && (Array.isArray(value) ? !value.length : !value);\n });\n\n const clearFile = () => {\n pdf.clear();\n setFields([]);\n setValues({});\n setHasXfa(false);\n };\n\n const handleSave = async (event) => {\n event.preventDefault();\n if (!pdf.bytes || !editable.length) return;\n setIsSaving(true);\n setStatus({ tone: \"info\", text: \"Filling your PDF...\" });\n try {\n const bytes = await fillForm(pdf.bytes, values, { flatten });\n const blob = new Blob([bytes as BlobPart], { type: \"application/pdf\" });\n downloadBlob(blob, `${toBaseName(pdf.file.name, \"form\")}-filled.pdf`);\n setStatus({\n tone: \"success\",\n text: `Saved (${formatBytes(blob.size)})${flatten ? \" with answers locked in\" : \"\"}. Your download has started.${\n missingRequired.length ? ` Note: ${missingRequired.length} required field${missingRequired.length === 1 ? \" is\" : \"s are\"} still empty.` : \"\"\n }`,\n });\n } catch (error) {\n setStatus({ tone: \"error\", text: `Could not fill the form: ${error?.message || \"Please try again.\"}` });\n } finally {\n setIsSaving(false);\n }\n };\n\n const busy = isSaving || pdf.isReading;\n\n return (\n <PdfToolPage\n title=\"Fill PDF Forms\"\n description=\"Fill in the text boxes, checkboxes, and choices of a PDF form, then download it, optionally locked so answers can't be changed. Runs in your browser; your answers never leave your device.\"\n stats={[\n { value: fields.length || \"-\", label: \"Fields\" },\n { value: pdf.pageCount || \"-\", label: \"Pages\" },\n ]}\n >\n <PdfToolColumns\n main={\n <form onSubmit={handleSave}>\n {pdf.file ? (\n <SelectedPdfCard\n signed={pdf.signed} file={pdf.file} pageCount={pdf.pageCount} onRemove={clearFile} disabled={isSaving} />\n ) : (\n <FileDropzone\n accept=\".pdf,application/pdf\"\n disabled={busy}\n onFiles={pdf.selectFiles}\n title=\"Drag and drop a PDF form here\"\n hint=\"or click to browse from your device\"\n />\n )}\n\n {hasXfa ? (\n <p className=\"mt-4 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200\">\n This form also contains an XFA (Adobe LiveCycle) version. It is removed when you save so every viewer shows\n the answers you enter here.\n </p>\n ) : null}\n\n {groups.map(([page, pageFields]) => (\n <section key={page} className={`mt-5 ${cardClass}`}>\n <h3 className=\"text-sm font-semibold text-slate-900 dark:text-slate-100\">\n {page ? `Page ${page}` : \"Not on a page\"}\n </h3>\n <div className=\"mt-3 grid gap-4 sm:grid-cols-2\">\n {pageFields.map((field) => (\n <div key={field.name} className={field.multiline || field.kind === \"radio\" ? \"sm:col-span-2\" : \"\"}>\n <FieldInput\n field={field}\n value={values[field.name]}\n disabled={busy}\n onChange={(value) => setValues((current) => ({ ...current, [field.name]: value }))}\n />\n </div>\n ))}\n </div>\n </section>\n ))}\n\n {fields.length ? (\n <label className=\"mt-5 flex items-start gap-3 text-sm text-slate-700 dark:text-slate-300\">\n <input\n type=\"checkbox\"\n checked={flatten}\n onChange={(event) => setFlatten(event.target.checked)}\n disabled={busy}\n className=\"mt-0.5 h-4 w-4 accent-[#1F8CFF]\"\n />\n <span>\n Lock answers (flatten)\n <span className=\"block text-xs text-slate-500 dark:text-slate-400\">\n Draws your answers into the page and removes the form, so they can't be edited.\n </span>\n </span>\n </label>\n ) : null}\n\n <StatusBanner status={status} />\n\n <div className=\"mt-5 flex flex-wrap gap-3\">\n <button type=\"submit\" disabled={busy || !editable.length} className={primaryButtonClass}>\n <i className={`fa-solid ${isSaving ? \"fa-spinner fa-spin\" : \"fa-pen-to-square\"}`} />\n {isSaving ? \"Saving...\" : \"Fill & Download\"}\n </button>\n <button\n type=\"button\"\n onClick={() => setValues(initialValues(fields))}\n disabled={busy || !fields.length}\n className={secondaryButtonClass}\n >\n <i className=\"fa-solid fa-arrow-rotate-left\" />\n Reset\n </button>\n <BackToPdfTools />\n </div>\n </form>\n }\n side={\n <>\n <h2 className=\"text-base font-semibold text-slate-900 dark:text-slate-100\">Summary</h2>\n <SummaryList\n items={[\n { label: \"Fillable fields\", value: pdf.file ? editable.length : \"-\" },\n { label: \"Required, still empty\", value: pdf.file ? missingRequired.length : \"-\" },\n ]}\n />\n <SideTips\n tips={[\n \"Hover a field label to see its full internal name.\",\n \"Answers use Helvetica, so basic Latin characters only.\",\n \"Scanned forms without real fields can be filled with Sign PDF → Type.\",\n ]}\n />\n </>\n }\n />\n </PdfToolPage>\n );\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { hasDigitalSignatures } from './chunk-7MTEMQLL.js';
|
|
2
|
+
import { isPdfFile, loadPdf } from './chunk-EKHEY3LI.js';
|
|
3
|
+
import { useState, useRef, useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
var MAX_SINGLE_PDF_BYTES = 200 * 1024 * 1024;
|
|
6
|
+
function useSinglePdf({ onError, onLoaded } = {}) {
|
|
7
|
+
const [file, setFile] = useState(null);
|
|
8
|
+
const [bytes, setBytes] = useState(null);
|
|
9
|
+
const [pageCount, setPageCount] = useState(0);
|
|
10
|
+
const [isReading, setIsReading] = useState(false);
|
|
11
|
+
const [signed, setSigned] = useState(false);
|
|
12
|
+
const requestRef = useRef(0);
|
|
13
|
+
const clear = useCallback(() => {
|
|
14
|
+
requestRef.current += 1;
|
|
15
|
+
setFile(null);
|
|
16
|
+
setBytes(null);
|
|
17
|
+
setPageCount(0);
|
|
18
|
+
setSigned(false);
|
|
19
|
+
setIsReading(false);
|
|
20
|
+
}, []);
|
|
21
|
+
const selectFiles = useCallback(
|
|
22
|
+
async (files) => {
|
|
23
|
+
const next = (files || []).find(isPdfFile);
|
|
24
|
+
if (!next) {
|
|
25
|
+
if (files?.length) onError?.("Only PDF files are supported.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (next.size > MAX_SINGLE_PDF_BYTES) {
|
|
29
|
+
onError?.("This PDF is larger than 200 MB.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const request = ++requestRef.current;
|
|
33
|
+
setFile(next);
|
|
34
|
+
setBytes(null);
|
|
35
|
+
setPageCount(0);
|
|
36
|
+
setSigned(false);
|
|
37
|
+
setIsReading(true);
|
|
38
|
+
try {
|
|
39
|
+
const data = await next.arrayBuffer();
|
|
40
|
+
const doc = await loadPdf(data);
|
|
41
|
+
if (request !== requestRef.current) return;
|
|
42
|
+
setBytes(data);
|
|
43
|
+
setPageCount(doc.getPageCount());
|
|
44
|
+
setSigned(hasDigitalSignatures(doc));
|
|
45
|
+
onLoaded?.({ file: next, bytes: data, pageCount: doc.getPageCount() });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (request !== requestRef.current) return;
|
|
48
|
+
setFile(null);
|
|
49
|
+
onError?.(error?.message || "Could not read this PDF.");
|
|
50
|
+
} finally {
|
|
51
|
+
if (request === requestRef.current) setIsReading(false);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
[onError, onLoaded]
|
|
55
|
+
);
|
|
56
|
+
return { file, bytes, pageCount, signed, isReading, selectFiles, clear };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { MAX_SINGLE_PDF_BYTES, useSinglePdf };
|
|
60
|
+
//# sourceMappingURL=chunk-BK3MYSUS.js.map
|
|
61
|
+
//# sourceMappingURL=chunk-BK3MYSUS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/useSinglePdf.ts"],"names":[],"mappings":";;;;AAIO,IAAM,oBAAA,GAAuB,MAAM,IAAA,GAAO;AAW1C,SAAS,aAAa,EAAE,OAAA,EAAS,QAAA,EAAS,GAAsB,EAAC,EAAG;AACzE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,IAAI,CAAA;AACrC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,IAAI,CAAA;AACvC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,CAAC,CAAA;AAC5C,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,OAAO,CAAC,CAAA;AAE3B,EAAA,MAAM,KAAA,GAAQ,YAAY,MAAM;AAC9B,IAAA,UAAA,CAAW,OAAA,IAAW,CAAA;AACtB,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,YAAA,CAAa,CAAC,CAAA;AACd,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,WAAA,GAAc,WAAA;AAAA,IAClB,OAAO,KAAA,KAAU;AACf,MAAA,MAAM,IAAA,GAAA,CAAQ,KAAA,IAAS,EAAC,EAAG,KAAK,SAAS,CAAA;AACzC,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,IAAI,KAAA,EAAO,MAAA,EAAQ,OAAA,GAAU,+BAA+B,CAAA;AAC5D,QAAA;AAAA,MACF;AACA,MAAA,IAAI,IAAA,CAAK,OAAO,oBAAA,EAAsB;AACpC,QAAA,OAAA,GAAU,iCAAiC,CAAA;AAC3C,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,OAAA,GAAU,EAAE,UAAA,CAAW,OAAA;AAC7B,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,YAAA,CAAa,CAAC,CAAA;AACd,MAAA,SAAA,CAAU,KAAK,CAAA;AACf,MAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,WAAA,EAAY;AACpC,QAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,IAAI,CAAA;AAC9B,QAAA,IAAI,OAAA,KAAY,WAAW,OAAA,EAAS;AACpC,QAAA,QAAA,CAAS,IAAI,CAAA;AACb,QAAA,YAAA,CAAa,GAAA,CAAI,cAAc,CAAA;AAC/B,QAAA,SAAA,CAAU,oBAAA,CAAqB,GAAG,CAAC,CAAA;AACnC,QAAA,QAAA,GAAW,EAAE,MAAM,IAAA,EAAM,KAAA,EAAO,MAAM,SAAA,EAAW,GAAA,CAAI,YAAA,EAAa,EAAG,CAAA;AAAA,MACvE,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,OAAA,KAAY,WAAW,OAAA,EAAS;AACpC,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA,OAAA,GAAU,KAAA,EAAO,WAAW,0BAA0B,CAAA;AAAA,MACxD,CAAA,SAAE;AACA,QAAA,IAAI,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,YAAA,CAAa,KAAK,CAAA;AAAA,MACxD;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAS,QAAQ;AAAA,GACpB;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,WAAW,MAAA,EAAQ,SAAA,EAAW,aAAa,KAAA,EAAM;AACzE","file":"chunk-BK3MYSUS.js","sourcesContent":["import { useCallback, useRef, useState } from \"react\";\nimport { isPdfFile, loadPdf } from \"./files\";\nimport { hasDigitalSignatures } from \"./signatureFields\";\n\nexport const MAX_SINGLE_PDF_BYTES = 200 * 1024 * 1024;\n\n/**\n * Holds one selected PDF: the File, its bytes and page count once read, or a\n * read error. A newer selection always wins over a slower earlier read.\n */\ntype SinglePdfOptions = {\n onError?: (message: string) => void;\n onLoaded?: (loaded: { file: File; bytes: ArrayBuffer; pageCount: number }) => void;\n};\n\nexport function useSinglePdf({ onError, onLoaded }: SinglePdfOptions = {}) {\n const [file, setFile] = useState(null);\n const [bytes, setBytes] = useState(null);\n const [pageCount, setPageCount] = useState(0);\n const [isReading, setIsReading] = useState(false);\n const [signed, setSigned] = useState(false);\n const requestRef = useRef(0);\n\n const clear = useCallback(() => {\n requestRef.current += 1;\n setFile(null);\n setBytes(null);\n setPageCount(0);\n setSigned(false);\n setIsReading(false);\n }, []);\n\n const selectFiles = useCallback(\n async (files) => {\n const next = (files || []).find(isPdfFile);\n if (!next) {\n if (files?.length) onError?.(\"Only PDF files are supported.\");\n return;\n }\n if (next.size > MAX_SINGLE_PDF_BYTES) {\n onError?.(\"This PDF is larger than 200 MB.\");\n return;\n }\n\n const request = ++requestRef.current;\n setFile(next);\n setBytes(null);\n setPageCount(0);\n setSigned(false);\n setIsReading(true);\n\n try {\n const data = await next.arrayBuffer();\n const doc = await loadPdf(data);\n if (request !== requestRef.current) return;\n setBytes(data);\n setPageCount(doc.getPageCount());\n setSigned(hasDigitalSignatures(doc));\n onLoaded?.({ file: next, bytes: data, pageCount: doc.getPageCount() });\n } catch (error) {\n if (request !== requestRef.current) return;\n setFile(null);\n onError?.(error?.message || \"Could not read this PDF.\");\n } finally {\n if (request === requestRef.current) setIsReading(false);\n }\n },\n [onError, onLoaded]\n );\n\n return { file, bytes, pageCount, signed, isReading, selectFiles, clear };\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/shared/pageRanges.ts
|
|
2
|
+
function parseRangePart(part, pageCount) {
|
|
3
|
+
const match = part.match(/^(\d*)\s*(?:(-)\s*(\d*))?$/);
|
|
4
|
+
if (!match || !match[1] && !match[3]) {
|
|
5
|
+
throw new Error(`Invalid page range "${part}".`);
|
|
6
|
+
}
|
|
7
|
+
const start = match[1] ? Number(match[1]) : 1;
|
|
8
|
+
const end = match[2] ? match[3] ? Number(match[3]) : pageCount : start;
|
|
9
|
+
if (start < 1 || end < 1 || start > pageCount || end > pageCount) {
|
|
10
|
+
throw new Error(`Page range "${part}" is outside 1-${pageCount}.`);
|
|
11
|
+
}
|
|
12
|
+
const indices = [];
|
|
13
|
+
const step = start <= end ? 1 : -1;
|
|
14
|
+
for (let page = start; step > 0 ? page <= end : page >= end; page += step) {
|
|
15
|
+
indices.push(page - 1);
|
|
16
|
+
}
|
|
17
|
+
return indices;
|
|
18
|
+
}
|
|
19
|
+
function parsePageGroups(selection, pageCount) {
|
|
20
|
+
const groups = (selection || "").split(",").map((part) => part.trim()).filter(Boolean).map((part) => parseRangePart(part, pageCount));
|
|
21
|
+
if (!groups.length) {
|
|
22
|
+
throw new Error("Page selection is empty.");
|
|
23
|
+
}
|
|
24
|
+
return groups;
|
|
25
|
+
}
|
|
26
|
+
function parsePageSelection(selection, pageCount) {
|
|
27
|
+
if (!(selection || "").trim()) {
|
|
28
|
+
return Array.from({ length: pageCount }, (_, index) => index);
|
|
29
|
+
}
|
|
30
|
+
return parsePageGroups(selection, pageCount).flat();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { parsePageGroups, parsePageSelection };
|
|
34
|
+
//# sourceMappingURL=chunk-BLHNKR3S.js.map
|
|
35
|
+
//# sourceMappingURL=chunk-BLHNKR3S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/pageRanges.ts"],"names":[],"mappings":";AAAA,SAAS,cAAA,CAAe,MAAc,SAAA,EAAmB;AACvD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,4BAA4B,CAAA;AACrD,EAAA,IAAI,CAAC,SAAU,CAAC,KAAA,CAAM,CAAC,CAAA,IAAK,CAAC,KAAA,CAAM,CAAC,CAAA,EAAI;AACtC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,IAAI,CAAA,EAAA,CAAI,CAAA;AAAA,EACjD;AAEA,EAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA,GAAI,OAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,CAAA;AAC5C,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,CAAC,CAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,SAAA,GAAa,KAAA;AAEnE,EAAA,IAAI,QAAQ,CAAA,IAAK,GAAA,GAAM,KAAK,KAAA,GAAQ,SAAA,IAAa,MAAM,SAAA,EAAW;AAChE,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,IAAI,CAAA,eAAA,EAAkB,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACnE;AAEA,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,IAAA,GAAO,KAAA,IAAS,GAAA,GAAM,CAAA,GAAI,EAAA;AAChC,EAAA,KAAA,IAAS,IAAA,GAAO,OAAO,IAAA,GAAO,CAAA,GAAI,QAAQ,GAAA,GAAM,IAAA,IAAQ,GAAA,EAAK,IAAA,IAAQ,IAAA,EAAM;AACzE,IAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,eAAA,CAAgB,WAA+B,SAAA,EAAmB;AAChF,EAAA,MAAM,MAAA,GAAA,CAAU,aAAa,EAAA,EAC1B,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,EAAM,CAAA,CACzB,MAAA,CAAO,OAAO,CAAA,CACd,GAAA,CAAI,CAAC,IAAA,KAAS,cAAA,CAAe,IAAA,EAAM,SAAS,CAAC,CAAA;AAEhD,EAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,IAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,EAC5C;AACA,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,kBAAA,CAAmB,WAA+B,SAAA,EAAmB;AACnF,EAAA,IAAI,CAAA,CAAE,SAAA,IAAa,EAAA,EAAI,IAAA,EAAK,EAAG;AAC7B,IAAA,OAAO,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,WAAU,EAAG,CAAC,CAAA,EAAG,KAAA,KAAU,KAAK,CAAA;AAAA,EAC9D;AACA,EAAA,OAAO,eAAA,CAAgB,SAAA,EAAW,SAAS,CAAA,CAAE,IAAA,EAAK;AACpD","file":"chunk-BLHNKR3S.js","sourcesContent":["function parseRangePart(part: string, pageCount: number) {\n const match = part.match(/^(\\d*)\\s*(?:(-)\\s*(\\d*))?$/);\n if (!match || (!match[1] && !match[3])) {\n throw new Error(`Invalid page range \"${part}\".`);\n }\n\n const start = match[1] ? Number(match[1]) : 1;\n const end = match[2] ? (match[3] ? Number(match[3]) : pageCount) : start;\n\n if (start < 1 || end < 1 || start > pageCount || end > pageCount) {\n throw new Error(`Page range \"${part}\" is outside 1-${pageCount}.`);\n }\n\n const indices: number[] = [];\n const step = start <= end ? 1 : -1;\n for (let page = start; step > 0 ? page <= end : page >= end; page += step) {\n indices.push(page - 1);\n }\n return indices;\n}\n\n/**\n * Parse a 1-based page selection (\"1-3, 5, 8-\") into groups of 0-based page\n * indices, one group per comma-separated part, in the order typed.\n */\nexport function parsePageGroups(selection: string | undefined, pageCount: number) {\n const groups = (selection || \"\")\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean)\n .map((part) => parseRangePart(part, pageCount));\n\n if (!groups.length) {\n throw new Error(\"Page selection is empty.\");\n }\n return groups;\n}\n\n/**\n * Parse a 1-based page selection (\"1-3, 5, 8-\") into 0-based page indices,\n * preserving the order the user typed. Empty means every page. Throws on\n * out-of-range or malformed input.\n */\nexport function parsePageSelection(selection: string | undefined, pageCount: number) {\n if (!(selection || \"\").trim()) {\n return Array.from({ length: pageCount }, (_, index) => index);\n }\n return parsePageGroups(selection, pageCount).flat();\n}\n"]}
|