@drvillo/react-browser-e-signing 0.1.0 → 0.1.2
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 +39 -9
- package/dist/index.d.ts +72 -13
- package/dist/index.js +303 -137
- package/dist/index.js.map +1 -1
- package/dist/styles.css +407 -0
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -5,7 +5,49 @@ import SignaturePadLibrary from 'signature_pad';
|
|
|
5
5
|
import fontkit from '@pdf-lib/fontkit';
|
|
6
6
|
import { PDFDocument, StandardFonts } from 'pdf-lib';
|
|
7
7
|
|
|
8
|
-
// src/
|
|
8
|
+
// src/lib/signature-fonts.ts
|
|
9
|
+
var loadedFonts = /* @__PURE__ */ new Set();
|
|
10
|
+
var SIGNATURE_FONTS = [
|
|
11
|
+
"Caveat",
|
|
12
|
+
"Homemade Apple",
|
|
13
|
+
"Reenie Beanie",
|
|
14
|
+
"Mr Dafoe",
|
|
15
|
+
"Pacifico",
|
|
16
|
+
"Qwitcher Grypen"
|
|
17
|
+
];
|
|
18
|
+
function buildGoogleFontsCssUrl(family) {
|
|
19
|
+
const encoded = family.trim().replace(/\s+/g, "+");
|
|
20
|
+
return `https://fonts.googleapis.com/css2?family=${encoded}&display=swap`;
|
|
21
|
+
}
|
|
22
|
+
async function loadCssFromGoogleFonts(url) {
|
|
23
|
+
const response = await fetch(url);
|
|
24
|
+
if (!response.ok) throw new Error(`Unable to load font css from ${url}`);
|
|
25
|
+
return response.text();
|
|
26
|
+
}
|
|
27
|
+
function extractFontSource(cssText) {
|
|
28
|
+
const sourceMatch = cssText.match(/src:\s*url\(([^)]+)\)\s*format\(['"]?([^'")]+)['"]?\)/i);
|
|
29
|
+
if (!sourceMatch) return null;
|
|
30
|
+
return sourceMatch[1].replace(/['"]/g, "");
|
|
31
|
+
}
|
|
32
|
+
async function loadSignatureFont(fontFamily) {
|
|
33
|
+
if (loadedFonts.has(fontFamily)) return;
|
|
34
|
+
if (typeof document === "undefined") return;
|
|
35
|
+
if (typeof FontFace === "undefined") return;
|
|
36
|
+
const cssUrl = buildGoogleFontsCssUrl(fontFamily);
|
|
37
|
+
const cssText = await loadCssFromGoogleFonts(cssUrl);
|
|
38
|
+
const fontSource = extractFontSource(cssText);
|
|
39
|
+
if (!fontSource) throw new Error(`Unable to extract font source for ${fontFamily}`);
|
|
40
|
+
const fontFace = new FontFace(fontFamily, `url(${fontSource})`);
|
|
41
|
+
await fontFace.load();
|
|
42
|
+
const fontSet = document.fonts;
|
|
43
|
+
fontSet.add(fontFace);
|
|
44
|
+
loadedFonts.add(fontFamily);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/lib/cn.ts
|
|
48
|
+
function cn(...values) {
|
|
49
|
+
return values.filter(Boolean).join(" ");
|
|
50
|
+
}
|
|
9
51
|
if (typeof window !== "undefined") {
|
|
10
52
|
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
11
53
|
}
|
|
@@ -19,27 +61,28 @@ function PdfViewer({
|
|
|
19
61
|
onScaleChange,
|
|
20
62
|
onDocumentLoadSuccess,
|
|
21
63
|
onPageDimensions,
|
|
22
|
-
renderOverlay
|
|
64
|
+
renderOverlay,
|
|
65
|
+
className
|
|
23
66
|
}) {
|
|
24
67
|
if (!pdfData)
|
|
25
|
-
return /* @__PURE__ */ jsx("div", {
|
|
26
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
27
|
-
/* @__PURE__ */ jsxs("div", {
|
|
28
|
-
/* @__PURE__ */ jsxs("div", {
|
|
68
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-empty", className: cn(className), children: "Upload a PDF to begin" });
|
|
69
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer", className: cn(className), children: [
|
|
70
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-toolbar", children: [
|
|
71
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-page-count", children: [
|
|
29
72
|
"Pages: ",
|
|
30
73
|
numPages || "\u2014"
|
|
31
74
|
] }),
|
|
32
|
-
/* @__PURE__ */ jsxs("div", {
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-zoom", children: [
|
|
33
76
|
/* @__PURE__ */ jsx(
|
|
34
77
|
"button",
|
|
35
78
|
{
|
|
36
79
|
type: "button",
|
|
37
|
-
|
|
80
|
+
"data-slot": "pdf-viewer-zoom-button",
|
|
38
81
|
onClick: () => onScaleChange(Math.max(MIN_SCALE, Number((scale - SCALE_STEP).toFixed(2)))),
|
|
39
82
|
children: "-"
|
|
40
83
|
}
|
|
41
84
|
),
|
|
42
|
-
/* @__PURE__ */ jsxs("span", {
|
|
85
|
+
/* @__PURE__ */ jsxs("span", { "data-slot": "pdf-viewer-zoom-value", children: [
|
|
43
86
|
Math.round(scale * 100),
|
|
44
87
|
"%"
|
|
45
88
|
] }),
|
|
@@ -47,7 +90,7 @@ function PdfViewer({
|
|
|
47
90
|
"button",
|
|
48
91
|
{
|
|
49
92
|
type: "button",
|
|
50
|
-
|
|
93
|
+
"data-slot": "pdf-viewer-zoom-button",
|
|
51
94
|
onClick: () => onScaleChange(Math.min(MAX_SCALE, Number((scale + SCALE_STEP).toFixed(2)))),
|
|
52
95
|
children: "+"
|
|
53
96
|
}
|
|
@@ -59,25 +102,33 @@ function PdfViewer({
|
|
|
59
102
|
{
|
|
60
103
|
file: pdfData,
|
|
61
104
|
onLoadSuccess: (loadedPdf) => onDocumentLoadSuccess(loadedPdf.numPages),
|
|
62
|
-
loading: /* @__PURE__ */ jsx("div", {
|
|
63
|
-
error: /* @__PURE__ */ jsx("div", {
|
|
64
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
loading: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-loading", children: "Loading PDF..." }),
|
|
106
|
+
error: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-error", children: "Unable to render this PDF." }),
|
|
107
|
+
children: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-pages", children: Array.from({ length: numPages }, (_, pageIndex) => /* @__PURE__ */ jsxs(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
"data-slot": "pdf-viewer-page",
|
|
111
|
+
style: { position: "relative", margin: "0 auto", width: "fit-content" },
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
Page,
|
|
115
|
+
{
|
|
116
|
+
pageNumber: pageIndex + 1,
|
|
117
|
+
scale,
|
|
118
|
+
renderTextLayer: false,
|
|
119
|
+
renderAnnotationLayer: false,
|
|
120
|
+
onLoadSuccess: (page) => onPageDimensions({
|
|
121
|
+
pageIndex,
|
|
122
|
+
widthPt: page.view[2],
|
|
123
|
+
heightPt: page.view[3]
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
),
|
|
127
|
+
renderOverlay?.(pageIndex)
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
`pdf-page-${pageIndex}`
|
|
131
|
+
)) })
|
|
81
132
|
}
|
|
82
133
|
)
|
|
83
134
|
] });
|
|
@@ -95,7 +146,7 @@ function getFieldPreviewText(field, preview) {
|
|
|
95
146
|
if (field.type === "date") return preview.dateText;
|
|
96
147
|
return "";
|
|
97
148
|
}
|
|
98
|
-
function SignatureField({ field, onUpdateField, onRemoveField, preview }) {
|
|
149
|
+
function SignatureField({ field, onUpdateField, onRemoveField, preview, className }) {
|
|
99
150
|
const rootRef = useRef(null);
|
|
100
151
|
const dragStateRef = useRef(null);
|
|
101
152
|
const resizeStateRef = useRef(null);
|
|
@@ -170,49 +221,74 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview }) {
|
|
|
170
221
|
"div",
|
|
171
222
|
{
|
|
172
223
|
ref: rootRef,
|
|
173
|
-
|
|
224
|
+
"data-slot": "signature-field",
|
|
225
|
+
"data-field-type": field.type,
|
|
226
|
+
className: cn(className),
|
|
174
227
|
style: {
|
|
228
|
+
position: "absolute",
|
|
175
229
|
left: `${field.xPercent}%`,
|
|
176
230
|
top: `${field.yPercent}%`,
|
|
177
231
|
width: `${field.widthPercent}%`,
|
|
178
|
-
height: `${field.heightPercent}
|
|
232
|
+
height: `${field.heightPercent}%`,
|
|
233
|
+
userSelect: "none"
|
|
179
234
|
},
|
|
180
235
|
onPointerDown: handleDragPointerDown,
|
|
181
236
|
onPointerMove: handleDragPointerMove,
|
|
182
237
|
onPointerUp: handleDragPointerUp,
|
|
183
238
|
children: [
|
|
184
|
-
/* @__PURE__ */ jsxs(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
239
|
+
/* @__PURE__ */ jsxs(
|
|
240
|
+
"div",
|
|
241
|
+
{
|
|
242
|
+
"data-slot": "signature-field-content",
|
|
243
|
+
style: {
|
|
244
|
+
display: "flex",
|
|
245
|
+
height: "100%",
|
|
246
|
+
width: "100%",
|
|
247
|
+
alignItems: "stretch",
|
|
248
|
+
justifyContent: "space-between"
|
|
249
|
+
},
|
|
250
|
+
children: [
|
|
251
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "signature-field-preview", children: [
|
|
252
|
+
/* @__PURE__ */ jsx("div", { "data-slot": "signature-field-label", children: field.type }),
|
|
253
|
+
field.type === "signature" && preview.signatureDataUrl ? /* @__PURE__ */ jsx(
|
|
254
|
+
"img",
|
|
255
|
+
{
|
|
256
|
+
"data-slot": "signature-field-preview-image",
|
|
257
|
+
src: preview.signatureDataUrl,
|
|
258
|
+
alt: "signature preview",
|
|
259
|
+
draggable: false
|
|
260
|
+
}
|
|
261
|
+
) : /* @__PURE__ */ jsx("div", { "data-slot": "signature-field-preview-text", children: previewText || "\u2014" })
|
|
262
|
+
] }),
|
|
263
|
+
/* @__PURE__ */ jsx(
|
|
264
|
+
"button",
|
|
265
|
+
{
|
|
266
|
+
type: "button",
|
|
267
|
+
"data-slot": "signature-field-remove",
|
|
268
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
269
|
+
onClick: (event) => {
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
onRemoveField(field.id);
|
|
272
|
+
},
|
|
273
|
+
"aria-label": "Remove field",
|
|
274
|
+
children: "\xD7"
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
),
|
|
212
280
|
/* @__PURE__ */ jsx(
|
|
213
281
|
"div",
|
|
214
282
|
{
|
|
215
|
-
|
|
283
|
+
"data-slot": "signature-field-resize",
|
|
284
|
+
style: {
|
|
285
|
+
position: "absolute",
|
|
286
|
+
right: "-0.375rem",
|
|
287
|
+
bottom: "-0.375rem",
|
|
288
|
+
width: "0.75rem",
|
|
289
|
+
height: "0.75rem",
|
|
290
|
+
cursor: "nwse-resize"
|
|
291
|
+
},
|
|
216
292
|
onPointerDown: handleResizePointerDown,
|
|
217
293
|
onPointerMove: handleResizePointerMove,
|
|
218
294
|
onPointerUp: handleResizePointerUp
|
|
@@ -229,7 +305,8 @@ function FieldOverlay({
|
|
|
229
305
|
onAddField,
|
|
230
306
|
onUpdateField,
|
|
231
307
|
onRemoveField,
|
|
232
|
-
preview
|
|
308
|
+
preview,
|
|
309
|
+
className
|
|
233
310
|
}) {
|
|
234
311
|
function handleOverlayPointerDown(event) {
|
|
235
312
|
if (!selectedFieldType) return;
|
|
@@ -249,7 +326,15 @@ function FieldOverlay({
|
|
|
249
326
|
return /* @__PURE__ */ jsx(
|
|
250
327
|
"div",
|
|
251
328
|
{
|
|
252
|
-
|
|
329
|
+
"data-slot": "field-overlay",
|
|
330
|
+
"data-state": selectedFieldType ? "placing" : "idle",
|
|
331
|
+
className: cn(className),
|
|
332
|
+
style: {
|
|
333
|
+
position: "absolute",
|
|
334
|
+
inset: 0,
|
|
335
|
+
zIndex: 20,
|
|
336
|
+
cursor: selectedFieldType ? "crosshair" : "default"
|
|
337
|
+
},
|
|
253
338
|
onPointerDown: handleOverlayPointerDown,
|
|
254
339
|
"aria-label": `Field overlay page ${pageIndex + 1}`,
|
|
255
340
|
children: pageFields.map((field) => /* @__PURE__ */ jsx(
|
|
@@ -272,14 +357,15 @@ var FIELD_LABELS = {
|
|
|
272
357
|
date: "Date"
|
|
273
358
|
};
|
|
274
359
|
var FIELD_TYPES = ["signature", "fullName", "title", "date"];
|
|
275
|
-
function FieldPalette({ selectedFieldType, onSelectFieldType }) {
|
|
276
|
-
return /* @__PURE__ */ jsx("div", {
|
|
360
|
+
function FieldPalette({ selectedFieldType, onSelectFieldType, className }) {
|
|
361
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "field-palette", className: cn(className), children: FIELD_TYPES.map((fieldType) => {
|
|
277
362
|
const isSelected = selectedFieldType === fieldType;
|
|
278
363
|
return /* @__PURE__ */ jsx(
|
|
279
364
|
"button",
|
|
280
365
|
{
|
|
281
366
|
type: "button",
|
|
282
|
-
|
|
367
|
+
"data-slot": "field-palette-button",
|
|
368
|
+
"data-state": isSelected ? "selected" : "idle",
|
|
283
369
|
onClick: () => onSelectFieldType(isSelected ? null : fieldType),
|
|
284
370
|
"aria-pressed": isSelected,
|
|
285
371
|
children: FIELD_LABELS[fieldType]
|
|
@@ -288,43 +374,43 @@ function FieldPalette({ selectedFieldType, onSelectFieldType }) {
|
|
|
288
374
|
);
|
|
289
375
|
}) });
|
|
290
376
|
}
|
|
291
|
-
function SignerDetailsPanel({ signerInfo, onSignerInfoChange }) {
|
|
377
|
+
function SignerDetailsPanel({ signerInfo, onSignerInfoChange, className }) {
|
|
292
378
|
function handleInputChange(fieldName, fieldValue) {
|
|
293
379
|
onSignerInfoChange({
|
|
294
380
|
...signerInfo,
|
|
295
381
|
[fieldName]: fieldValue
|
|
296
382
|
});
|
|
297
383
|
}
|
|
298
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
299
|
-
/* @__PURE__ */ jsx("h2", {
|
|
300
|
-
/* @__PURE__ */ jsxs("label", {
|
|
384
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "signer-panel", className: cn(className), children: [
|
|
385
|
+
/* @__PURE__ */ jsx("h2", { "data-slot": "signer-panel-heading", children: "Signer Details" }),
|
|
386
|
+
/* @__PURE__ */ jsxs("label", { "data-slot": "signer-panel-label", children: [
|
|
301
387
|
"First Name",
|
|
302
388
|
/* @__PURE__ */ jsx(
|
|
303
389
|
"input",
|
|
304
390
|
{
|
|
305
|
-
|
|
391
|
+
"data-slot": "signer-panel-input",
|
|
306
392
|
value: signerInfo.firstName,
|
|
307
393
|
onChange: (event) => handleInputChange("firstName", event.target.value)
|
|
308
394
|
}
|
|
309
395
|
)
|
|
310
396
|
] }),
|
|
311
|
-
/* @__PURE__ */ jsxs("label", {
|
|
397
|
+
/* @__PURE__ */ jsxs("label", { "data-slot": "signer-panel-label", children: [
|
|
312
398
|
"Last Name",
|
|
313
399
|
/* @__PURE__ */ jsx(
|
|
314
400
|
"input",
|
|
315
401
|
{
|
|
316
|
-
|
|
402
|
+
"data-slot": "signer-panel-input",
|
|
317
403
|
value: signerInfo.lastName,
|
|
318
404
|
onChange: (event) => handleInputChange("lastName", event.target.value)
|
|
319
405
|
}
|
|
320
406
|
)
|
|
321
407
|
] }),
|
|
322
|
-
/* @__PURE__ */ jsxs("label", {
|
|
408
|
+
/* @__PURE__ */ jsxs("label", { "data-slot": "signer-panel-label", children: [
|
|
323
409
|
"Title",
|
|
324
410
|
/* @__PURE__ */ jsx(
|
|
325
411
|
"input",
|
|
326
412
|
{
|
|
327
|
-
|
|
413
|
+
"data-slot": "signer-panel-input",
|
|
328
414
|
value: signerInfo.title,
|
|
329
415
|
onChange: (event) => handleInputChange("title", event.target.value)
|
|
330
416
|
}
|
|
@@ -332,39 +418,7 @@ function SignerDetailsPanel({ signerInfo, onSignerInfoChange }) {
|
|
|
332
418
|
] })
|
|
333
419
|
] });
|
|
334
420
|
}
|
|
335
|
-
|
|
336
|
-
// src/lib/signature-fonts.ts
|
|
337
|
-
var loadedFonts = /* @__PURE__ */ new Set();
|
|
338
|
-
var SIGNATURE_FONTS = ["Dancing Script", "Great Vibes", "Sacramento", "Alex Brush"];
|
|
339
|
-
function buildGoogleFontsCssUrl(family) {
|
|
340
|
-
const encoded = family.trim().replace(/\s+/g, "+");
|
|
341
|
-
return `https://fonts.googleapis.com/css2?family=${encoded}&display=swap`;
|
|
342
|
-
}
|
|
343
|
-
async function loadCssFromGoogleFonts(url) {
|
|
344
|
-
const response = await fetch(url);
|
|
345
|
-
if (!response.ok) throw new Error(`Unable to load font css from ${url}`);
|
|
346
|
-
return response.text();
|
|
347
|
-
}
|
|
348
|
-
function extractFontSource(cssText) {
|
|
349
|
-
const sourceMatch = cssText.match(/src:\s*url\(([^)]+)\)\s*format\(['"]?([^'")]+)['"]?\)/i);
|
|
350
|
-
if (!sourceMatch) return null;
|
|
351
|
-
return sourceMatch[1].replace(/['"]/g, "");
|
|
352
|
-
}
|
|
353
|
-
async function loadSignatureFont(fontFamily) {
|
|
354
|
-
if (loadedFonts.has(fontFamily)) return;
|
|
355
|
-
if (typeof document === "undefined") return;
|
|
356
|
-
if (typeof FontFace === "undefined") return;
|
|
357
|
-
const cssUrl = buildGoogleFontsCssUrl(fontFamily);
|
|
358
|
-
const cssText = await loadCssFromGoogleFonts(cssUrl);
|
|
359
|
-
const fontSource = extractFontSource(cssText);
|
|
360
|
-
if (!fontSource) throw new Error(`Unable to extract font source for ${fontFamily}`);
|
|
361
|
-
const fontFace = new FontFace(fontFamily, `url(${fontSource})`);
|
|
362
|
-
await fontFace.load();
|
|
363
|
-
const fontSet = document.fonts;
|
|
364
|
-
fontSet.add(fontFace);
|
|
365
|
-
loadedFonts.add(fontFamily);
|
|
366
|
-
}
|
|
367
|
-
function SignaturePad({ onDrawn }) {
|
|
421
|
+
function SignaturePad({ onDrawn, className }) {
|
|
368
422
|
const canvasRef = useRef(null);
|
|
369
423
|
const signaturePadRef = useRef(null);
|
|
370
424
|
useEffect(() => {
|
|
@@ -391,13 +445,13 @@ function SignaturePad({ onDrawn }) {
|
|
|
391
445
|
signaturePadRef.current?.clear();
|
|
392
446
|
onDrawn("");
|
|
393
447
|
}
|
|
394
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
395
|
-
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, width: 420, height: 140
|
|
396
|
-
/* @__PURE__ */ jsx("div", {
|
|
448
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "signature-pad", className: cn(className), children: [
|
|
449
|
+
/* @__PURE__ */ jsx("canvas", { "data-slot": "signature-pad-canvas", ref: canvasRef, width: 420, height: 140 }),
|
|
450
|
+
/* @__PURE__ */ jsx("div", { "data-slot": "signature-pad-actions", children: /* @__PURE__ */ jsx(
|
|
397
451
|
"button",
|
|
398
452
|
{
|
|
399
453
|
type: "button",
|
|
400
|
-
|
|
454
|
+
"data-slot": "signature-pad-clear",
|
|
401
455
|
onClick: handleClear,
|
|
402
456
|
children: "Clear"
|
|
403
457
|
}
|
|
@@ -409,17 +463,20 @@ function SignaturePreview({
|
|
|
409
463
|
style,
|
|
410
464
|
signatureDataUrl,
|
|
411
465
|
isRendering,
|
|
412
|
-
onStyleChange
|
|
466
|
+
onStyleChange,
|
|
467
|
+
className
|
|
413
468
|
}) {
|
|
414
469
|
const canShowPreview = useMemo(() => signerName.trim().length > 0, [signerName]);
|
|
415
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
416
|
-
/* @__PURE__ */ jsx("h2", {
|
|
417
|
-
/* @__PURE__ */ jsxs("div", {
|
|
470
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "signature-preview", className: cn(className), children: [
|
|
471
|
+
/* @__PURE__ */ jsx("h2", { "data-slot": "signature-preview-heading", children: "Signature" }),
|
|
472
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "signature-preview-mode-toggle", children: [
|
|
418
473
|
/* @__PURE__ */ jsx(
|
|
419
474
|
"button",
|
|
420
475
|
{
|
|
421
476
|
type: "button",
|
|
422
|
-
|
|
477
|
+
"data-slot": "signature-preview-mode-button",
|
|
478
|
+
"data-mode": "typed",
|
|
479
|
+
"data-state": style.mode === "typed" ? "active" : "idle",
|
|
423
480
|
onClick: () => onStyleChange({ mode: "typed", fontFamily: style.mode === "typed" ? style.fontFamily : SIGNATURE_FONTS[0] }),
|
|
424
481
|
children: "Typed"
|
|
425
482
|
}
|
|
@@ -428,25 +485,34 @@ function SignaturePreview({
|
|
|
428
485
|
"button",
|
|
429
486
|
{
|
|
430
487
|
type: "button",
|
|
431
|
-
|
|
488
|
+
"data-slot": "signature-preview-mode-button",
|
|
489
|
+
"data-mode": "drawn",
|
|
490
|
+
"data-state": style.mode === "drawn" ? "active" : "idle",
|
|
432
491
|
onClick: () => onStyleChange({ mode: "drawn", dataUrl: style.mode === "drawn" ? style.dataUrl : "" }),
|
|
433
492
|
children: "Drawn"
|
|
434
493
|
}
|
|
435
494
|
)
|
|
436
495
|
] }),
|
|
437
|
-
style.mode === "typed" ? /* @__PURE__ */ jsxs("label", {
|
|
496
|
+
style.mode === "typed" ? /* @__PURE__ */ jsxs("label", { "data-slot": "signature-preview-font-label", children: [
|
|
438
497
|
"Font",
|
|
439
498
|
/* @__PURE__ */ jsx(
|
|
440
499
|
"select",
|
|
441
500
|
{
|
|
442
|
-
|
|
501
|
+
"data-slot": "signature-preview-font-select",
|
|
443
502
|
value: style.fontFamily,
|
|
444
503
|
onChange: (event) => onStyleChange({ mode: "typed", fontFamily: event.target.value }),
|
|
445
504
|
children: SIGNATURE_FONTS.map((fontFamily) => /* @__PURE__ */ jsx("option", { value: fontFamily, children: fontFamily }, fontFamily))
|
|
446
505
|
}
|
|
447
506
|
)
|
|
448
507
|
] }) : /* @__PURE__ */ jsx(SignaturePad, { onDrawn: (dataUrl) => onStyleChange({ mode: "drawn", dataUrl }) }),
|
|
449
|
-
/* @__PURE__ */ jsx(
|
|
508
|
+
/* @__PURE__ */ jsx(
|
|
509
|
+
"div",
|
|
510
|
+
{
|
|
511
|
+
"data-slot": "signature-preview-display",
|
|
512
|
+
"data-state": !canShowPreview ? "empty" : isRendering ? "rendering" : signatureDataUrl ? "ready" : "missing-signature",
|
|
513
|
+
children: !canShowPreview ? /* @__PURE__ */ jsx("p", { "data-slot": "signature-preview-placeholder", children: "Enter signer first and last name to render a signature." }) : isRendering ? /* @__PURE__ */ jsx("p", { "data-slot": "signature-preview-placeholder", children: "Rendering signature..." }) : signatureDataUrl ? /* @__PURE__ */ jsx("img", { "data-slot": "signature-preview-image", src: signatureDataUrl, alt: "Signature preview" }) : /* @__PURE__ */ jsx("p", { "data-slot": "signature-preview-placeholder", children: "No signature available yet." })
|
|
514
|
+
}
|
|
515
|
+
)
|
|
450
516
|
] });
|
|
451
517
|
}
|
|
452
518
|
function SigningComplete({
|
|
@@ -456,11 +522,12 @@ function SigningComplete({
|
|
|
456
522
|
documentHash,
|
|
457
523
|
downloadUrl,
|
|
458
524
|
fileName = "signed-document.pdf",
|
|
459
|
-
onReset
|
|
525
|
+
onReset,
|
|
526
|
+
className
|
|
460
527
|
}) {
|
|
461
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
462
|
-
/* @__PURE__ */ jsx("h2", {
|
|
463
|
-
/* @__PURE__ */ jsxs("div", {
|
|
528
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "signing-complete", className: cn(className), children: [
|
|
529
|
+
/* @__PURE__ */ jsx("h2", { "data-slot": "signing-complete-heading", children: "Document Signed" }),
|
|
530
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "signing-complete-details", children: [
|
|
464
531
|
/* @__PURE__ */ jsxs("p", { children: [
|
|
465
532
|
"Signer: ",
|
|
466
533
|
signerName || "Unknown"
|
|
@@ -474,17 +541,17 @@ function SigningComplete({
|
|
|
474
541
|
signedAt
|
|
475
542
|
] })
|
|
476
543
|
] }),
|
|
477
|
-
/* @__PURE__ */ jsxs("div", {
|
|
478
|
-
/* @__PURE__ */ jsx("p", {
|
|
479
|
-
/* @__PURE__ */ jsx("p", {
|
|
544
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "signing-complete-hash", children: [
|
|
545
|
+
/* @__PURE__ */ jsx("p", { "data-slot": "signing-complete-hash-label", children: "SHA-256" }),
|
|
546
|
+
/* @__PURE__ */ jsx("p", { "data-slot": "signing-complete-hash-value", children: documentHash })
|
|
480
547
|
] }),
|
|
481
|
-
/* @__PURE__ */ jsxs("div", {
|
|
548
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "signing-complete-actions", children: [
|
|
482
549
|
/* @__PURE__ */ jsx(
|
|
483
550
|
"a",
|
|
484
551
|
{
|
|
485
552
|
href: downloadUrl,
|
|
486
553
|
download: fileName,
|
|
487
|
-
|
|
554
|
+
"data-slot": "signing-complete-download",
|
|
488
555
|
children: "Download Signed PDF"
|
|
489
556
|
}
|
|
490
557
|
),
|
|
@@ -492,7 +559,7 @@ function SigningComplete({
|
|
|
492
559
|
"button",
|
|
493
560
|
{
|
|
494
561
|
type: "button",
|
|
495
|
-
|
|
562
|
+
"data-slot": "signing-complete-reset",
|
|
496
563
|
onClick: onReset,
|
|
497
564
|
children: "Sign Another"
|
|
498
565
|
}
|
|
@@ -647,6 +714,41 @@ function useFieldPlacement(options = {}) {
|
|
|
647
714
|
function buildCanvas() {
|
|
648
715
|
return document.createElement("canvas");
|
|
649
716
|
}
|
|
717
|
+
function hashString(s) {
|
|
718
|
+
let h = 2166136261;
|
|
719
|
+
for (let i = 0; i < s.length; i++) {
|
|
720
|
+
h ^= s.charCodeAt(i);
|
|
721
|
+
h = Math.imul(h, 16777619);
|
|
722
|
+
}
|
|
723
|
+
return h >>> 0;
|
|
724
|
+
}
|
|
725
|
+
function mulberry32(seed) {
|
|
726
|
+
return function() {
|
|
727
|
+
let t = seed += 1831565813;
|
|
728
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
729
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
730
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function layoutTypedGlyphs({
|
|
734
|
+
signerName,
|
|
735
|
+
fontFamily,
|
|
736
|
+
fontSize,
|
|
737
|
+
context
|
|
738
|
+
}) {
|
|
739
|
+
const rng = mulberry32(hashString(`${signerName}\0${fontFamily}`));
|
|
740
|
+
context.font = `${fontSize}px "${fontFamily}"`;
|
|
741
|
+
const chars = Array.from(signerName);
|
|
742
|
+
const layouts = [];
|
|
743
|
+
for (let i = 0; i < chars.length; i++) {
|
|
744
|
+
const char = chars[i];
|
|
745
|
+
const width = context.measureText(char).width;
|
|
746
|
+
const rotation = (rng() * 2 - 1) * 0.07;
|
|
747
|
+
const gapAfter = i < chars.length - 1 ? (rng() * 2 - 1) * 1.25 : 0;
|
|
748
|
+
layouts.push({ char, width, rotation, gapAfter });
|
|
749
|
+
}
|
|
750
|
+
return layouts;
|
|
751
|
+
}
|
|
650
752
|
function drawTypedSignature({
|
|
651
753
|
signerName,
|
|
652
754
|
fontFamily
|
|
@@ -656,15 +758,27 @@ function drawTypedSignature({
|
|
|
656
758
|
if (!context) return "";
|
|
657
759
|
const padding = 16;
|
|
658
760
|
const fontSize = 56;
|
|
659
|
-
|
|
660
|
-
const
|
|
661
|
-
|
|
761
|
+
const baselineY = 50;
|
|
762
|
+
const glyphs = layoutTypedGlyphs({ signerName, fontFamily, fontSize, context });
|
|
763
|
+
const textWidth = glyphs.reduce((sum, g) => sum + g.width + g.gapAfter, 0);
|
|
764
|
+
canvas.width = Math.max(240, Math.ceil(textWidth + padding * 2));
|
|
662
765
|
canvas.height = 100;
|
|
663
766
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
664
767
|
context.font = `${fontSize}px "${fontFamily}"`;
|
|
665
768
|
context.fillStyle = "#111827";
|
|
769
|
+
context.textAlign = "center";
|
|
666
770
|
context.textBaseline = "middle";
|
|
667
|
-
|
|
771
|
+
let x = padding;
|
|
772
|
+
for (const glyph of glyphs) {
|
|
773
|
+
const { char, width, rotation, gapAfter } = glyph;
|
|
774
|
+
const cx = x + width / 2;
|
|
775
|
+
context.save();
|
|
776
|
+
context.translate(cx, baselineY);
|
|
777
|
+
context.rotate(rotation);
|
|
778
|
+
context.fillText(char, 0, 0);
|
|
779
|
+
context.restore();
|
|
780
|
+
x += width + gapAfter;
|
|
781
|
+
}
|
|
668
782
|
return canvas.toDataURL("image/png");
|
|
669
783
|
}
|
|
670
784
|
function useSignatureRenderer({ signerName, style }) {
|
|
@@ -796,13 +910,65 @@ async function sha256(data) {
|
|
|
796
910
|
return Array.from(new Uint8Array(hashBuffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
797
911
|
}
|
|
798
912
|
|
|
913
|
+
// src/lib/slots.ts
|
|
914
|
+
var SLOTS = {
|
|
915
|
+
pdfViewer: "pdf-viewer",
|
|
916
|
+
pdfViewerEmpty: "pdf-viewer-empty",
|
|
917
|
+
pdfViewerToolbar: "pdf-viewer-toolbar",
|
|
918
|
+
pdfViewerPageCount: "pdf-viewer-page-count",
|
|
919
|
+
pdfViewerZoom: "pdf-viewer-zoom",
|
|
920
|
+
pdfViewerZoomButton: "pdf-viewer-zoom-button",
|
|
921
|
+
pdfViewerZoomValue: "pdf-viewer-zoom-value",
|
|
922
|
+
pdfViewerPages: "pdf-viewer-pages",
|
|
923
|
+
pdfViewerPage: "pdf-viewer-page",
|
|
924
|
+
pdfViewerLoading: "pdf-viewer-loading",
|
|
925
|
+
pdfViewerError: "pdf-viewer-error",
|
|
926
|
+
fieldOverlay: "field-overlay",
|
|
927
|
+
signatureField: "signature-field",
|
|
928
|
+
signatureFieldContent: "signature-field-content",
|
|
929
|
+
signatureFieldLabel: "signature-field-label",
|
|
930
|
+
signatureFieldPreview: "signature-field-preview",
|
|
931
|
+
signatureFieldPreviewImage: "signature-field-preview-image",
|
|
932
|
+
signatureFieldPreviewText: "signature-field-preview-text",
|
|
933
|
+
signatureFieldRemove: "signature-field-remove",
|
|
934
|
+
signatureFieldResize: "signature-field-resize",
|
|
935
|
+
fieldPalette: "field-palette",
|
|
936
|
+
fieldPaletteButton: "field-palette-button",
|
|
937
|
+
signerPanel: "signer-panel",
|
|
938
|
+
signerPanelHeading: "signer-panel-heading",
|
|
939
|
+
signerPanelLabel: "signer-panel-label",
|
|
940
|
+
signerPanelInput: "signer-panel-input",
|
|
941
|
+
signaturePreview: "signature-preview",
|
|
942
|
+
signaturePreviewHeading: "signature-preview-heading",
|
|
943
|
+
signaturePreviewModeToggle: "signature-preview-mode-toggle",
|
|
944
|
+
signaturePreviewModeButton: "signature-preview-mode-button",
|
|
945
|
+
signaturePreviewFontLabel: "signature-preview-font-label",
|
|
946
|
+
signaturePreviewFontSelect: "signature-preview-font-select",
|
|
947
|
+
signaturePreviewDisplay: "signature-preview-display",
|
|
948
|
+
signaturePreviewImage: "signature-preview-image",
|
|
949
|
+
signaturePreviewPlaceholder: "signature-preview-placeholder",
|
|
950
|
+
signaturePad: "signature-pad",
|
|
951
|
+
signaturePadCanvas: "signature-pad-canvas",
|
|
952
|
+
signaturePadActions: "signature-pad-actions",
|
|
953
|
+
signaturePadClear: "signature-pad-clear",
|
|
954
|
+
signingComplete: "signing-complete",
|
|
955
|
+
signingCompleteHeading: "signing-complete-heading",
|
|
956
|
+
signingCompleteDetails: "signing-complete-details",
|
|
957
|
+
signingCompleteHash: "signing-complete-hash",
|
|
958
|
+
signingCompleteHashLabel: "signing-complete-hash-label",
|
|
959
|
+
signingCompleteHashValue: "signing-complete-hash-value",
|
|
960
|
+
signingCompleteActions: "signing-complete-actions",
|
|
961
|
+
signingCompleteDownload: "signing-complete-download",
|
|
962
|
+
signingCompleteReset: "signing-complete-reset"
|
|
963
|
+
};
|
|
964
|
+
|
|
799
965
|
// src/index.ts
|
|
800
966
|
var defaults = {
|
|
801
|
-
SIGNATURE_FONTS: [
|
|
967
|
+
SIGNATURE_FONTS: [...SIGNATURE_FONTS],
|
|
802
968
|
DEFAULT_FIELD_WIDTH_PERCENT: 25,
|
|
803
969
|
DEFAULT_FIELD_HEIGHT_PERCENT: 5
|
|
804
970
|
};
|
|
805
971
|
|
|
806
|
-
export { FieldOverlay, FieldPalette, PdfViewer, SIGNATURE_FONTS, SignatureField, SignaturePad, SignaturePreview, SignerDetailsPanel, SigningComplete, defaults, loadSignatureFont, mapFromPoints, mapToPoints, modifyPdf, sha256, useFieldPlacement, usePdfDocument, useSignatureRenderer };
|
|
972
|
+
export { FieldOverlay, FieldPalette, PdfViewer, SIGNATURE_FONTS, SLOTS, SignatureField, SignaturePad, SignaturePreview, SignerDetailsPanel, SigningComplete, defaults, loadSignatureFont, mapFromPoints, mapToPoints, modifyPdf, sha256, useFieldPlacement, usePdfDocument, useSignatureRenderer };
|
|
807
973
|
//# sourceMappingURL=index.js.map
|
|
808
974
|
//# sourceMappingURL=index.js.map
|