@unlev/exeq 0.1.1 → 0.1.3
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 +82 -81
- package/dist/index.css +289 -5
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +651 -351
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +623 -324
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -4
- package/dist/embed.css +0 -1
- package/dist/embed.global.js +0 -419
- package/dist/styles.css +0 -566
package/dist/index.js
CHANGED
|
@@ -45,12 +45,14 @@ __export(lib_exports, {
|
|
|
45
45
|
generateFilledPdf: () => generateFilledPdf,
|
|
46
46
|
getSignerColor: () => getSignerColor,
|
|
47
47
|
postPdfToCallback: () => postPdfToCallback,
|
|
48
|
-
renderPdfPages: () => renderPdfPages
|
|
48
|
+
renderPdfPages: () => renderPdfPages,
|
|
49
|
+
uniqueLabel: () => uniqueLabel
|
|
49
50
|
});
|
|
50
51
|
module.exports = __toCommonJS(lib_exports);
|
|
51
52
|
|
|
52
53
|
// src/components/pdf-builder/DesignerView.tsx
|
|
53
|
-
var
|
|
54
|
+
var import_react3 = require("react");
|
|
55
|
+
var import_react_dom = require("react-dom");
|
|
54
56
|
|
|
55
57
|
// src/types/pdf-builder.ts
|
|
56
58
|
function generateId() {
|
|
@@ -106,14 +108,44 @@ var FIELD_DEFAULTS = {
|
|
|
106
108
|
height: 5,
|
|
107
109
|
fontSize: 12,
|
|
108
110
|
placeholder: "Initials"
|
|
111
|
+
},
|
|
112
|
+
blackout: {
|
|
113
|
+
width: 20,
|
|
114
|
+
height: 3,
|
|
115
|
+
fontSize: 12,
|
|
116
|
+
placeholder: ""
|
|
117
|
+
},
|
|
118
|
+
whiteout: {
|
|
119
|
+
width: 20,
|
|
120
|
+
height: 3,
|
|
121
|
+
fontSize: 12,
|
|
122
|
+
placeholder: ""
|
|
109
123
|
}
|
|
110
124
|
};
|
|
111
|
-
|
|
125
|
+
var TYPE_LABELS = {
|
|
126
|
+
text: "Text Field",
|
|
127
|
+
signature: "Signature",
|
|
128
|
+
"signed-date": "Signed Date",
|
|
129
|
+
checkbox: "Checkbox",
|
|
130
|
+
initials: "Initials",
|
|
131
|
+
blackout: "Blackout",
|
|
132
|
+
whiteout: "Whiteout"
|
|
133
|
+
};
|
|
134
|
+
function uniqueLabel(desired, existingLabels) {
|
|
135
|
+
const lower = desired.toLowerCase();
|
|
136
|
+
if (!existingLabels.some((l) => l.toLowerCase() === lower)) return desired;
|
|
137
|
+
let i = 2;
|
|
138
|
+
while (existingLabels.some((l) => l.toLowerCase() === `${lower} ${i}`)) i++;
|
|
139
|
+
return `${desired} ${i}`;
|
|
140
|
+
}
|
|
141
|
+
function createField(type, assignee, page, x, y, existingFields) {
|
|
112
142
|
const defaults = FIELD_DEFAULTS[type];
|
|
143
|
+
const baseLabel = TYPE_LABELS[type];
|
|
144
|
+
const existingLabels = existingFields?.map((f) => f.label) ?? [];
|
|
113
145
|
return {
|
|
114
146
|
id: generateId(),
|
|
115
147
|
type,
|
|
116
|
-
label:
|
|
148
|
+
label: uniqueLabel(baseLabel, existingLabels),
|
|
117
149
|
placeholder: defaults.placeholder || "",
|
|
118
150
|
required: true,
|
|
119
151
|
assignee,
|
|
@@ -168,6 +200,7 @@ function PdfViewer({
|
|
|
168
200
|
onFieldMove,
|
|
169
201
|
onFieldResize,
|
|
170
202
|
onPageClick,
|
|
203
|
+
onDropField,
|
|
171
204
|
mode,
|
|
172
205
|
currentSigner,
|
|
173
206
|
renderFieldContent
|
|
@@ -185,6 +218,21 @@ function PdfViewer({
|
|
|
185
218
|
onSelectField(null);
|
|
186
219
|
}
|
|
187
220
|
}, [onPageClick, onSelectField]);
|
|
221
|
+
const handleDragOver = (0, import_react.useCallback)((e) => {
|
|
222
|
+
if (e.dataTransfer.types.includes("application/exeq-field-type")) {
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
e.dataTransfer.dropEffect = "copy";
|
|
225
|
+
}
|
|
226
|
+
}, []);
|
|
227
|
+
const handleDrop = (0, import_react.useCallback)((e, pageIndex) => {
|
|
228
|
+
const fieldType = e.dataTransfer.getData("application/exeq-field-type");
|
|
229
|
+
if (!fieldType || !onDropField) return;
|
|
230
|
+
e.preventDefault();
|
|
231
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
232
|
+
const x = (e.clientX - rect.left) / rect.width * 100;
|
|
233
|
+
const y = (e.clientY - rect.top) / rect.height * 100;
|
|
234
|
+
onDropField(pageIndex, x, y, fieldType);
|
|
235
|
+
}, [onDropField]);
|
|
188
236
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pdf-viewer", ref: containerRef, children: pages.map((page, pageIndex) => {
|
|
189
237
|
const pageFields = fields.filter((f) => f.page === pageIndex);
|
|
190
238
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -193,6 +241,8 @@ function PdfViewer({
|
|
|
193
241
|
className: "pdf-page",
|
|
194
242
|
style: { aspectRatio: `${page.width} / ${page.height}` },
|
|
195
243
|
onClick: (e) => handlePageClick(e, pageIndex),
|
|
244
|
+
onDragOver: handleDragOver,
|
|
245
|
+
onDrop: (e) => handleDrop(e, pageIndex),
|
|
196
246
|
"data-page": pageIndex,
|
|
197
247
|
children: [
|
|
198
248
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -238,6 +288,7 @@ function FieldOverlayItem({
|
|
|
238
288
|
const dragStartRef = (0, import_react.useRef)(null);
|
|
239
289
|
const resizeStartRef = (0, import_react.useRef)(null);
|
|
240
290
|
const color = getSignerColor(field.assignee);
|
|
291
|
+
const isRedact = field.type === "blackout" || field.type === "whiteout";
|
|
241
292
|
const isEditable = mode === "designer" || mode === "signer" && field.assignee === currentSigner;
|
|
242
293
|
const isPreFilled = !isEditable && !!field.value;
|
|
243
294
|
const handleMouseDown = (0, import_react.useCallback)((e) => {
|
|
@@ -303,14 +354,15 @@ function FieldOverlayItem({
|
|
|
303
354
|
"div",
|
|
304
355
|
{
|
|
305
356
|
ref: overlayRef,
|
|
306
|
-
className: `field-overlay ${isSelected ? "selected" : ""} ${isEditable ? "editable" : "readonly"} ${isPreFilled ? "prefilled" : ""}`,
|
|
357
|
+
className: `field-overlay ${isSelected ? "selected" : ""} ${isEditable ? "editable" : "readonly"} ${isPreFilled ? "prefilled" : ""} ${isRedact ? "redact" : ""}`,
|
|
307
358
|
style: {
|
|
308
359
|
left: `${field.x}%`,
|
|
309
360
|
top: `${field.y}%`,
|
|
310
361
|
width: `${field.width}%`,
|
|
311
362
|
height: `${field.height}%`,
|
|
312
|
-
borderColor: color,
|
|
313
|
-
|
|
363
|
+
borderColor: isRedact ? field.type === "blackout" ? "#666" : "#bbb" : color,
|
|
364
|
+
borderStyle: isRedact ? "dashed" : "solid",
|
|
365
|
+
backgroundColor: isRedact ? field.type === "blackout" ? "#000000" : "#ffffff" : isSelected ? `${color}22` : `${color}11`,
|
|
314
366
|
cursor: mode === "designer" ? "move" : "default"
|
|
315
367
|
},
|
|
316
368
|
onClick: (e) => {
|
|
@@ -319,7 +371,7 @@ function FieldOverlayItem({
|
|
|
319
371
|
},
|
|
320
372
|
onMouseDown: handleMouseDown,
|
|
321
373
|
children: [
|
|
322
|
-
mode === "designer" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "field-overlay-label", style: { backgroundColor: color }, children: field.label }),
|
|
374
|
+
mode === "designer" && !isRedact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "field-overlay-label", style: { backgroundColor: color }, children: field.label }),
|
|
323
375
|
renderContent ? renderContent(field) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "field-overlay-placeholder", children: field.value || field.placeholder }),
|
|
324
376
|
mode === "designer" && isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
325
377
|
"div",
|
|
@@ -335,8 +387,15 @@ function FieldOverlayItem({
|
|
|
335
387
|
|
|
336
388
|
// src/components/pdf-builder/FieldPropertyPanel.tsx
|
|
337
389
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
390
|
+
var INK_COLORS = [
|
|
391
|
+
{ value: "#000000", label: "Black" },
|
|
392
|
+
{ value: "#1a56db", label: "Blue" }
|
|
393
|
+
];
|
|
338
394
|
function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
339
395
|
const color = getSignerColor(field.assignee);
|
|
396
|
+
const isRedactField = field.type === "blackout" || field.type === "whiteout";
|
|
397
|
+
const showFontSize = field.type === "text" || field.type === "signed-date";
|
|
398
|
+
const showInkColor = field.type === "text" || field.type === "signature" || field.type === "initials" || field.type === "signed-date";
|
|
340
399
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "field-property-panel", children: [
|
|
341
400
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-header", children: [
|
|
342
401
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { color }, children: field.label }),
|
|
@@ -353,7 +412,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
353
412
|
}
|
|
354
413
|
)
|
|
355
414
|
] }),
|
|
356
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
415
|
+
!isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
357
416
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Field Type" }),
|
|
358
417
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
359
418
|
"select",
|
|
@@ -387,7 +446,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
387
446
|
}
|
|
388
447
|
)
|
|
389
448
|
] }),
|
|
390
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
449
|
+
!isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
391
450
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Assigned To" }),
|
|
392
451
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
393
452
|
"select",
|
|
@@ -398,7 +457,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
398
457
|
}
|
|
399
458
|
)
|
|
400
459
|
] }),
|
|
401
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
460
|
+
!isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
402
461
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Placeholder" }),
|
|
403
462
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
404
463
|
"input",
|
|
@@ -409,7 +468,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
409
468
|
}
|
|
410
469
|
)
|
|
411
470
|
] }),
|
|
412
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-field", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "panel-checkbox-label", children: [
|
|
471
|
+
!isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-field", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "panel-checkbox-label", children: [
|
|
413
472
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
414
473
|
"input",
|
|
415
474
|
{
|
|
@@ -420,7 +479,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
420
479
|
),
|
|
421
480
|
"Required"
|
|
422
481
|
] }) }),
|
|
423
|
-
|
|
482
|
+
showFontSize && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
424
483
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font Size (pt)" }),
|
|
425
484
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
426
485
|
"input",
|
|
@@ -433,118 +492,26 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
433
492
|
}
|
|
434
493
|
)
|
|
435
494
|
] }),
|
|
436
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field
|
|
437
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
438
|
-
|
|
439
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
440
|
-
"input",
|
|
441
|
-
{
|
|
442
|
-
type: "number",
|
|
443
|
-
min: "1",
|
|
444
|
-
max: "100",
|
|
445
|
-
step: "0.5",
|
|
446
|
-
value: field.width,
|
|
447
|
-
onChange: (e) => onUpdate(field.id, { width: Number(e.target.value) })
|
|
448
|
-
}
|
|
449
|
-
)
|
|
450
|
-
] }),
|
|
451
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
452
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Height (%)" }),
|
|
453
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
454
|
-
"input",
|
|
455
|
-
{
|
|
456
|
-
type: "number",
|
|
457
|
-
min: "1",
|
|
458
|
-
max: "100",
|
|
459
|
-
step: "0.5",
|
|
460
|
-
value: field.height,
|
|
461
|
-
onChange: (e) => onUpdate(field.id, { height: Number(e.target.value) })
|
|
462
|
-
}
|
|
463
|
-
)
|
|
464
|
-
] })
|
|
465
|
-
] })
|
|
466
|
-
] });
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// src/components/pdf-builder/SignerRoleSelector.tsx
|
|
470
|
-
var import_react2 = require("react");
|
|
471
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
472
|
-
function SignerRoleSelector({
|
|
473
|
-
roles,
|
|
474
|
-
activeRole,
|
|
475
|
-
onSetActiveRole,
|
|
476
|
-
onAddRole,
|
|
477
|
-
onRemoveRole
|
|
478
|
-
}) {
|
|
479
|
-
const [isAdding, setIsAdding] = (0, import_react2.useState)(false);
|
|
480
|
-
const [newRoleName, setNewRoleName] = (0, import_react2.useState)("");
|
|
481
|
-
const handleAdd = () => {
|
|
482
|
-
if (newRoleName.trim()) {
|
|
483
|
-
onAddRole(newRoleName.trim());
|
|
484
|
-
setNewRoleName("");
|
|
485
|
-
setIsAdding(false);
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "signer-role-selector", children: [
|
|
489
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "signer-role-label", children: "Signer Roles" }),
|
|
490
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "signer-role-list", children: [
|
|
491
|
-
roles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
495
|
+
showInkColor && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Ink Color" }),
|
|
497
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ink-color-picker", children: INK_COLORS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
492
498
|
"button",
|
|
493
499
|
{
|
|
494
|
-
className: `
|
|
495
|
-
style: {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
color: role === activeRole ? "#fff" : getSignerColor(role)
|
|
499
|
-
},
|
|
500
|
-
onClick: () => onSetActiveRole(role),
|
|
501
|
-
children: [
|
|
502
|
-
role,
|
|
503
|
-
roles.length > 1 && role !== "Sender" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
504
|
-
"span",
|
|
505
|
-
{
|
|
506
|
-
className: "signer-role-remove",
|
|
507
|
-
onClick: (e) => {
|
|
508
|
-
e.stopPropagation();
|
|
509
|
-
onRemoveRole(role);
|
|
510
|
-
},
|
|
511
|
-
children: "\xD7"
|
|
512
|
-
}
|
|
513
|
-
)
|
|
514
|
-
]
|
|
500
|
+
className: `ink-color-swatch ${(field.inkColor || "#000000") === c.value ? "active" : ""}`,
|
|
501
|
+
style: { backgroundColor: c.value },
|
|
502
|
+
onClick: () => onUpdate(field.id, { inkColor: c.value }),
|
|
503
|
+
title: c.label
|
|
515
504
|
},
|
|
516
|
-
|
|
517
|
-
))
|
|
518
|
-
isAdding ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "signer-role-add-input", children: [
|
|
519
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
520
|
-
"input",
|
|
521
|
-
{
|
|
522
|
-
type: "text",
|
|
523
|
-
value: newRoleName,
|
|
524
|
-
onChange: (e) => setNewRoleName(e.target.value),
|
|
525
|
-
onKeyDown: (e) => e.key === "Enter" && handleAdd(),
|
|
526
|
-
placeholder: "Role name",
|
|
527
|
-
autoFocus: true
|
|
528
|
-
}
|
|
529
|
-
),
|
|
530
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { onClick: handleAdd, children: "Add" }),
|
|
531
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { onClick: () => setIsAdding(false), children: "Cancel" })
|
|
532
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
533
|
-
"button",
|
|
534
|
-
{
|
|
535
|
-
className: "signer-role-add-btn",
|
|
536
|
-
onClick: () => setIsAdding(true),
|
|
537
|
-
children: "+ Add Role"
|
|
538
|
-
}
|
|
539
|
-
)
|
|
505
|
+
c.value
|
|
506
|
+
)) })
|
|
540
507
|
] })
|
|
541
508
|
] });
|
|
542
509
|
}
|
|
543
510
|
|
|
544
511
|
// src/components/pdf-builder/SignatureCanvas.tsx
|
|
545
|
-
var
|
|
512
|
+
var import_react2 = require("react");
|
|
546
513
|
var import_perfect_freehand = require("perfect-freehand");
|
|
547
|
-
var
|
|
514
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
548
515
|
function getSvgPathFromStroke(stroke) {
|
|
549
516
|
if (!stroke.length) return "";
|
|
550
517
|
const d = stroke.reduce(
|
|
@@ -563,13 +530,14 @@ function SignatureCanvas({
|
|
|
563
530
|
height = 150,
|
|
564
531
|
onSign,
|
|
565
532
|
initialValue,
|
|
566
|
-
className
|
|
533
|
+
className,
|
|
534
|
+
inkColor = "#000000"
|
|
567
535
|
}) {
|
|
568
|
-
const canvasRef = (0,
|
|
569
|
-
const [paths, setPaths] = (0,
|
|
570
|
-
const [currentPath, setCurrentPath] = (0,
|
|
571
|
-
const [isEmpty, setIsEmpty] = (0,
|
|
572
|
-
(0,
|
|
536
|
+
const canvasRef = (0, import_react2.useRef)(null);
|
|
537
|
+
const [paths, setPaths] = (0, import_react2.useState)([]);
|
|
538
|
+
const [currentPath, setCurrentPath] = (0, import_react2.useState)(null);
|
|
539
|
+
const [isEmpty, setIsEmpty] = (0, import_react2.useState)(!initialValue);
|
|
540
|
+
(0, import_react2.useEffect)(() => {
|
|
573
541
|
if (initialValue && canvasRef.current) {
|
|
574
542
|
const ctx = canvasRef.current.getContext("2d");
|
|
575
543
|
const img = new Image();
|
|
@@ -580,7 +548,7 @@ function SignatureCanvas({
|
|
|
580
548
|
img.src = initialValue;
|
|
581
549
|
}
|
|
582
550
|
}, [initialValue, width, height]);
|
|
583
|
-
(0,
|
|
551
|
+
(0, import_react2.useEffect)(() => {
|
|
584
552
|
const canvas = canvasRef.current;
|
|
585
553
|
if (!canvas) return;
|
|
586
554
|
const ctx = canvas.getContext("2d");
|
|
@@ -595,11 +563,11 @@ function SignatureCanvas({
|
|
|
595
563
|
});
|
|
596
564
|
const pathStr = getSvgPathFromStroke(stroke);
|
|
597
565
|
const path2d = new Path2D(pathStr);
|
|
598
|
-
ctx.fillStyle =
|
|
566
|
+
ctx.fillStyle = inkColor;
|
|
599
567
|
ctx.fill(path2d);
|
|
600
568
|
}
|
|
601
569
|
}, [paths, currentPath, width, height]);
|
|
602
|
-
const getPoint = (0,
|
|
570
|
+
const getPoint = (0, import_react2.useCallback)((e) => {
|
|
603
571
|
const rect = canvasRef.current.getBoundingClientRect();
|
|
604
572
|
return [
|
|
605
573
|
e.clientX - rect.left,
|
|
@@ -607,17 +575,17 @@ function SignatureCanvas({
|
|
|
607
575
|
e.pressure
|
|
608
576
|
];
|
|
609
577
|
}, []);
|
|
610
|
-
const handlePointerDown = (0,
|
|
578
|
+
const handlePointerDown = (0, import_react2.useCallback)((e) => {
|
|
611
579
|
e.preventDefault();
|
|
612
580
|
e.target.setPointerCapture(e.pointerId);
|
|
613
581
|
setCurrentPath([getPoint(e)]);
|
|
614
582
|
}, [getPoint]);
|
|
615
|
-
const handlePointerMove = (0,
|
|
583
|
+
const handlePointerMove = (0, import_react2.useCallback)((e) => {
|
|
616
584
|
if (!currentPath) return;
|
|
617
585
|
e.preventDefault();
|
|
618
586
|
setCurrentPath([...currentPath, getPoint(e)]);
|
|
619
587
|
}, [currentPath, getPoint]);
|
|
620
|
-
const handlePointerUp = (0,
|
|
588
|
+
const handlePointerUp = (0, import_react2.useCallback)(() => {
|
|
621
589
|
if (!currentPath) return;
|
|
622
590
|
setPaths((prev) => [...prev, currentPath]);
|
|
623
591
|
setCurrentPath(null);
|
|
@@ -628,7 +596,7 @@ function SignatureCanvas({
|
|
|
628
596
|
}
|
|
629
597
|
});
|
|
630
598
|
}, [currentPath, onSign]);
|
|
631
|
-
const handleClear = (0,
|
|
599
|
+
const handleClear = (0, import_react2.useCallback)(() => {
|
|
632
600
|
setPaths([]);
|
|
633
601
|
setCurrentPath(null);
|
|
634
602
|
setIsEmpty(true);
|
|
@@ -639,8 +607,8 @@ function SignatureCanvas({
|
|
|
639
607
|
onSign("");
|
|
640
608
|
}
|
|
641
609
|
}, [width, height, onSign]);
|
|
642
|
-
return /* @__PURE__ */ (0,
|
|
643
|
-
/* @__PURE__ */ (0,
|
|
610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `signature-canvas-wrapper ${className || ""}`, children: [
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
644
612
|
"canvas",
|
|
645
613
|
{
|
|
646
614
|
ref: canvasRef,
|
|
@@ -653,29 +621,76 @@ function SignatureCanvas({
|
|
|
653
621
|
style: { touchAction: "none" }
|
|
654
622
|
}
|
|
655
623
|
),
|
|
656
|
-
/* @__PURE__ */ (0,
|
|
657
|
-
!isEmpty && /* @__PURE__ */ (0,
|
|
658
|
-
isEmpty && /* @__PURE__ */ (0,
|
|
624
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "signature-canvas-actions", children: [
|
|
625
|
+
!isEmpty && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: handleClear, className: "signature-clear-btn", children: "Clear" }),
|
|
626
|
+
isEmpty && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "signature-hint", children: "Draw your signature above" })
|
|
659
627
|
] })
|
|
660
628
|
] });
|
|
661
629
|
}
|
|
662
630
|
|
|
631
|
+
// src/utils/apiKey.ts
|
|
632
|
+
var VALID_KEYS = /* @__PURE__ */ new Set([
|
|
633
|
+
"exeq_live_2024"
|
|
634
|
+
]);
|
|
635
|
+
function isValidApiKey(key) {
|
|
636
|
+
if (!key) return false;
|
|
637
|
+
return VALID_KEYS.has(key);
|
|
638
|
+
}
|
|
639
|
+
|
|
663
640
|
// src/components/pdf-builder/DesignerView.tsx
|
|
664
|
-
var
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
641
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
642
|
+
var FIELD_TYPE_META = [
|
|
643
|
+
{ type: "text", label: "Text", icon: "T" },
|
|
644
|
+
{ type: "signature", label: "Signature", icon: "\u270D" },
|
|
645
|
+
{ type: "signed-date", label: "Date", icon: "\u{1F4C5}" },
|
|
646
|
+
{ type: "checkbox", label: "Checkbox", icon: "\u2611" },
|
|
647
|
+
{ type: "initials", label: "Initials", icon: "IN" },
|
|
648
|
+
{ type: "blackout", label: "Blackout", icon: "\u25A0", group: "redact" },
|
|
649
|
+
{ type: "whiteout", label: "Whiteout", icon: "\u25A1", group: "redact" }
|
|
650
|
+
];
|
|
651
|
+
function DesignerView({
|
|
652
|
+
apiKey,
|
|
653
|
+
initialPdfUrl,
|
|
654
|
+
initialTemplate,
|
|
655
|
+
onSave,
|
|
656
|
+
hideHeader,
|
|
657
|
+
headerPortalRef
|
|
658
|
+
} = {}) {
|
|
659
|
+
if (!isValidApiKey(apiKey)) {
|
|
660
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "designer-layout", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "empty-state", children: [
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { children: "Invalid API Key" }),
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { children: [
|
|
663
|
+
"A valid API key is required to use Exeq. Visit ",
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://exeq.org", children: "exeq.org" }),
|
|
665
|
+
" to get one."
|
|
666
|
+
] })
|
|
667
|
+
] }) });
|
|
668
|
+
}
|
|
669
|
+
const [pages, setPages] = (0, import_react3.useState)([]);
|
|
670
|
+
const [fields, setFields] = (0, import_react3.useState)(initialTemplate?.fields ?? []);
|
|
671
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react3.useState)(null);
|
|
672
|
+
const [signerRoles, setSignerRoles] = (0, import_react3.useState)(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
|
|
673
|
+
const [activeRole, setActiveRole] = (0, import_react3.useState)("Sender");
|
|
674
|
+
const [activeFieldType, setActiveFieldType] = (0, import_react3.useState)("text");
|
|
675
|
+
const [loading, setLoading] = (0, import_react3.useState)(false);
|
|
676
|
+
const [pdfSource, setPdfSource] = (0, import_react3.useState)(null);
|
|
677
|
+
const [rightTab, setRightTab] = (0, import_react3.useState)("properties");
|
|
678
|
+
const [isAddingRole, setIsAddingRole] = (0, import_react3.useState)(false);
|
|
679
|
+
const [newRoleName, setNewRoleName] = (0, import_react3.useState)("");
|
|
680
|
+
const [draggingFieldType, setDraggingFieldType] = (0, import_react3.useState)(null);
|
|
681
|
+
const [panelWidth, setPanelWidth] = (0, import_react3.useState)(380);
|
|
682
|
+
const dragGhostRef = (0, import_react3.useRef)(null);
|
|
683
|
+
const resizingRef = (0, import_react3.useRef)(false);
|
|
684
|
+
(0, import_react3.useEffect)(() => {
|
|
685
|
+
const pdfUrl = initialPdfUrl || initialTemplate?.pdfUrl;
|
|
677
686
|
if (pdfUrl) {
|
|
678
687
|
loadPdf(pdfUrl);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const params = new URLSearchParams(window.location.search);
|
|
691
|
+
const paramPdf = params.get("pdf");
|
|
692
|
+
if (paramPdf) {
|
|
693
|
+
loadPdf(paramPdf);
|
|
679
694
|
}
|
|
680
695
|
const handleMessage = (e) => {
|
|
681
696
|
if (e.data?.type === "load-pdf" && e.data.url) {
|
|
@@ -689,8 +704,8 @@ function DesignerView() {
|
|
|
689
704
|
};
|
|
690
705
|
window.addEventListener("message", handleMessage);
|
|
691
706
|
return () => window.removeEventListener("message", handleMessage);
|
|
692
|
-
}, []);
|
|
693
|
-
const loadPdf = (0,
|
|
707
|
+
}, [initialPdfUrl, initialTemplate]);
|
|
708
|
+
const loadPdf = (0, import_react3.useCallback)(async (source) => {
|
|
694
709
|
setLoading(true);
|
|
695
710
|
try {
|
|
696
711
|
const rendered = await renderPdfPages(source);
|
|
@@ -702,7 +717,7 @@ function DesignerView() {
|
|
|
702
717
|
setLoading(false);
|
|
703
718
|
}
|
|
704
719
|
}, []);
|
|
705
|
-
const handleFileUpload = (0,
|
|
720
|
+
const handleFileUpload = (0, import_react3.useCallback)((e) => {
|
|
706
721
|
const file = e.target.files?.[0];
|
|
707
722
|
if (!file) return;
|
|
708
723
|
const reader = new FileReader();
|
|
@@ -711,204 +726,368 @@ function DesignerView() {
|
|
|
711
726
|
};
|
|
712
727
|
reader.readAsArrayBuffer(file);
|
|
713
728
|
}, [loadPdf]);
|
|
714
|
-
const handlePageClick = (0,
|
|
715
|
-
const field = createField(activeFieldType, activeRole, page, x, y);
|
|
729
|
+
const handlePageClick = (0, import_react3.useCallback)((page, x, y) => {
|
|
730
|
+
const field = createField(activeFieldType, activeRole, page, x, y, fields);
|
|
716
731
|
setFields((prev) => [...prev, field]);
|
|
717
732
|
setSelectedFieldId(field.id);
|
|
718
|
-
|
|
719
|
-
|
|
733
|
+
setRightTab("properties");
|
|
734
|
+
}, [activeFieldType, activeRole, fields]);
|
|
735
|
+
const handleFieldMove = (0, import_react3.useCallback)((id, page, x, y) => {
|
|
720
736
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, page, x, y } : f));
|
|
721
737
|
}, []);
|
|
722
|
-
const handleFieldResize = (0,
|
|
738
|
+
const handleFieldResize = (0, import_react3.useCallback)((id, width, height) => {
|
|
723
739
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, width, height } : f));
|
|
724
740
|
}, []);
|
|
725
|
-
const handleFieldUpdate = (0,
|
|
726
|
-
setFields((prev) =>
|
|
741
|
+
const handleFieldUpdate = (0, import_react3.useCallback)((id, updates) => {
|
|
742
|
+
setFields((prev) => {
|
|
743
|
+
if (updates.label !== void 0) {
|
|
744
|
+
const otherLabels = prev.filter((f) => f.id !== id).map((f) => f.label);
|
|
745
|
+
updates.label = uniqueLabel(updates.label, otherLabels);
|
|
746
|
+
}
|
|
747
|
+
return prev.map((f) => f.id === id ? { ...f, ...updates } : f);
|
|
748
|
+
});
|
|
727
749
|
}, []);
|
|
728
|
-
const handleFieldDelete = (0,
|
|
750
|
+
const handleFieldDelete = (0, import_react3.useCallback)((id) => {
|
|
729
751
|
setFields((prev) => prev.filter((f) => f.id !== id));
|
|
730
752
|
if (selectedFieldId === id) setSelectedFieldId(null);
|
|
731
753
|
}, [selectedFieldId]);
|
|
732
|
-
const handleAddRole = (0,
|
|
733
|
-
|
|
734
|
-
|
|
754
|
+
const handleAddRole = (0, import_react3.useCallback)(() => {
|
|
755
|
+
const name = newRoleName.trim();
|
|
756
|
+
if (name && !signerRoles.includes(name)) {
|
|
757
|
+
setSignerRoles((prev) => [...prev, name]);
|
|
735
758
|
}
|
|
736
|
-
|
|
737
|
-
|
|
759
|
+
setNewRoleName("");
|
|
760
|
+
setIsAddingRole(false);
|
|
761
|
+
}, [newRoleName, signerRoles]);
|
|
762
|
+
const handleRemoveRole = (0, import_react3.useCallback)((role) => {
|
|
738
763
|
setSignerRoles((prev) => prev.filter((r) => r !== role));
|
|
739
764
|
setFields((prev) => prev.map((f) => f.assignee === role ? { ...f, assignee: signerRoles[0] } : f));
|
|
740
765
|
if (activeRole === role) setActiveRole(signerRoles[0]);
|
|
741
766
|
}, [signerRoles, activeRole]);
|
|
742
|
-
const handleExport = (0,
|
|
767
|
+
const handleExport = (0, import_react3.useCallback)(() => {
|
|
743
768
|
const template = {
|
|
744
769
|
fields,
|
|
745
770
|
signerRoles,
|
|
746
771
|
pdfUrl: typeof pdfSource === "string" ? pdfSource : ""
|
|
747
772
|
};
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
773
|
+
if (onSave) {
|
|
774
|
+
onSave(template);
|
|
775
|
+
} else {
|
|
776
|
+
const json = JSON.stringify(template, null, 2);
|
|
777
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
778
|
+
const url = URL.createObjectURL(blob);
|
|
779
|
+
const a = document.createElement("a");
|
|
780
|
+
a.href = url;
|
|
781
|
+
a.download = "template.json";
|
|
782
|
+
a.click();
|
|
783
|
+
URL.revokeObjectURL(url);
|
|
784
|
+
}
|
|
756
785
|
window.parent?.postMessage({ type: "template-saved", template }, "*");
|
|
757
|
-
}, [fields, signerRoles, pdfSource]);
|
|
786
|
+
}, [fields, signerRoles, pdfSource, onSave]);
|
|
787
|
+
const handlePaletteDragStart = (0, import_react3.useCallback)((e, type) => {
|
|
788
|
+
setDraggingFieldType(type);
|
|
789
|
+
e.dataTransfer.setData("application/exeq-field-type", type);
|
|
790
|
+
e.dataTransfer.effectAllowed = "copy";
|
|
791
|
+
const ghost = document.createElement("div");
|
|
792
|
+
ghost.className = "palette-drag-ghost";
|
|
793
|
+
ghost.textContent = FIELD_TYPE_META.find((f) => f.type === type)?.label || type;
|
|
794
|
+
ghost.style.cssText = `
|
|
795
|
+
position: fixed; top: -200px; left: -200px;
|
|
796
|
+
padding: 6px 16px; background: ${getSignerColor(activeRole)};
|
|
797
|
+
color: #fff; border-radius: 4px; font-size: 12px;
|
|
798
|
+
font-family: system-ui; pointer-events: none; white-space: nowrap;
|
|
799
|
+
`;
|
|
800
|
+
document.body.appendChild(ghost);
|
|
801
|
+
e.dataTransfer.setDragImage(ghost, 40, 16);
|
|
802
|
+
dragGhostRef.current = ghost;
|
|
803
|
+
}, [activeRole]);
|
|
804
|
+
const handlePaletteDragEnd = (0, import_react3.useCallback)(() => {
|
|
805
|
+
setDraggingFieldType(null);
|
|
806
|
+
if (dragGhostRef.current) {
|
|
807
|
+
document.body.removeChild(dragGhostRef.current);
|
|
808
|
+
dragGhostRef.current = null;
|
|
809
|
+
}
|
|
810
|
+
}, []);
|
|
811
|
+
const handleDropOnPage = (0, import_react3.useCallback)((page, x, y, fieldType) => {
|
|
812
|
+
const field = createField(fieldType, activeRole, page, x, y, fields);
|
|
813
|
+
setFields((prev) => [...prev, field]);
|
|
814
|
+
setSelectedFieldId(field.id);
|
|
815
|
+
setRightTab("properties");
|
|
816
|
+
}, [activeRole, fields]);
|
|
817
|
+
(0, import_react3.useEffect)(() => {
|
|
818
|
+
const handleKeyDown = (e) => {
|
|
819
|
+
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
820
|
+
if (!selectedFieldId) return;
|
|
821
|
+
const tag = (document.activeElement?.tagName || "").toLowerCase();
|
|
822
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
823
|
+
if (document.activeElement?.isContentEditable) return;
|
|
824
|
+
e.preventDefault();
|
|
825
|
+
if (window.confirm("Delete this field?")) {
|
|
826
|
+
handleFieldDelete(selectedFieldId);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
830
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
831
|
+
}, [selectedFieldId, handleFieldDelete]);
|
|
832
|
+
const handleResizeStart = (0, import_react3.useCallback)((e) => {
|
|
833
|
+
e.preventDefault();
|
|
834
|
+
resizingRef.current = true;
|
|
835
|
+
const startX = e.clientX;
|
|
836
|
+
const startWidth = panelWidth;
|
|
837
|
+
const handleMouseMove = (e2) => {
|
|
838
|
+
if (!resizingRef.current) return;
|
|
839
|
+
const delta = startX - e2.clientX;
|
|
840
|
+
setPanelWidth(Math.max(280, Math.min(600, startWidth + delta)));
|
|
841
|
+
};
|
|
842
|
+
const handleMouseUp = () => {
|
|
843
|
+
resizingRef.current = false;
|
|
844
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
845
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
846
|
+
};
|
|
847
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
848
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
849
|
+
}, [panelWidth]);
|
|
850
|
+
const sortedFields = [...fields].sort((a, b) => {
|
|
851
|
+
if (a.page !== b.page) return a.page - b.page;
|
|
852
|
+
const bandThreshold = 2;
|
|
853
|
+
if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
|
|
854
|
+
return a.x - b.x;
|
|
855
|
+
});
|
|
758
856
|
const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
|
|
759
|
-
const renderFieldContent = (0,
|
|
857
|
+
const renderFieldContent = (0, import_react3.useCallback)((field) => {
|
|
858
|
+
if (field.type === "blackout" || field.type === "whiteout") {
|
|
859
|
+
return null;
|
|
860
|
+
}
|
|
760
861
|
if (field.type === "signature" || field.type === "initials") {
|
|
761
862
|
if (field.value) {
|
|
762
|
-
return /* @__PURE__ */ (0,
|
|
863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" });
|
|
763
864
|
}
|
|
764
865
|
}
|
|
765
|
-
|
|
866
|
+
const inkColor = field.inkColor || "#000000";
|
|
867
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
868
|
+
"div",
|
|
869
|
+
{
|
|
870
|
+
className: "field-overlay-placeholder",
|
|
871
|
+
style: { color: field.value ? inkColor : void 0, fontSize: `${field.fontSize * 0.6}px` },
|
|
872
|
+
children: field.value || field.placeholder
|
|
873
|
+
}
|
|
874
|
+
);
|
|
766
875
|
}, []);
|
|
767
|
-
|
|
768
|
-
/* @__PURE__ */ (0,
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
876
|
+
const headerButtons = pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "header-btn header-btn-outline", children: [
|
|
878
|
+
"Change PDF",
|
|
879
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "file", accept: ".pdf", onChange: handleFileUpload, hidden: true })
|
|
880
|
+
] }),
|
|
881
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: handleExport, className: "header-btn header-btn-primary", children: "Export Template" })
|
|
882
|
+
] }) : null;
|
|
883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "designer-layout", children: [
|
|
884
|
+
headerPortalRef?.current && headerButtons && (0, import_react_dom.createPortal)(headerButtons, headerPortalRef.current),
|
|
885
|
+
!hideHeader && !headerPortalRef && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "designer-header", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "designer-header-right", children: headerButtons }) }),
|
|
886
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "designer-body", children: [
|
|
887
|
+
pages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "designer-palette", children: [
|
|
888
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "palette-heading", children: "New Field Role" }),
|
|
889
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "palette-role-section", children: [
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
891
|
+
"select",
|
|
781
892
|
{
|
|
782
|
-
className:
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
893
|
+
className: "palette-role-select",
|
|
894
|
+
value: activeRole,
|
|
895
|
+
onChange: (e) => setActiveRole(e.target.value),
|
|
896
|
+
style: { borderColor: getSignerColor(activeRole), color: getSignerColor(activeRole) },
|
|
897
|
+
children: signerRoles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: role, children: role }, role))
|
|
898
|
+
}
|
|
899
|
+
),
|
|
900
|
+
isAddingRole ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "palette-role-add-inline", children: [
|
|
901
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
902
|
+
"input",
|
|
903
|
+
{
|
|
904
|
+
type: "text",
|
|
905
|
+
value: newRoleName,
|
|
906
|
+
onChange: (e) => setNewRoleName(e.target.value),
|
|
907
|
+
onKeyDown: (e) => e.key === "Enter" && handleAddRole(),
|
|
908
|
+
placeholder: "Role name",
|
|
909
|
+
autoFocus: true
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: handleAddRole, children: "Add" }),
|
|
913
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: () => {
|
|
914
|
+
setIsAddingRole(false);
|
|
915
|
+
setNewRoleName("");
|
|
916
|
+
}, children: "Cancel" })
|
|
917
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "palette-role-add-link", onClick: () => setIsAddingRole(true), children: "+ Add Role" })
|
|
918
|
+
] }),
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "palette-divider" }),
|
|
920
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "palette-heading", children: "Fields" }),
|
|
921
|
+
FIELD_TYPE_META.filter((f) => !f.group).map(({ type, label, icon }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
922
|
+
"div",
|
|
923
|
+
{
|
|
924
|
+
className: `palette-item ${activeFieldType === type ? "active" : ""}`,
|
|
925
|
+
draggable: true,
|
|
926
|
+
onClick: () => setActiveFieldType(type),
|
|
927
|
+
onDragStart: (e) => handlePaletteDragStart(e, type),
|
|
928
|
+
onDragEnd: handlePaletteDragEnd,
|
|
929
|
+
children: [
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "palette-item-icon", children: icon }),
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "palette-item-label", children: label })
|
|
932
|
+
]
|
|
933
|
+
},
|
|
934
|
+
type
|
|
935
|
+
)),
|
|
936
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "palette-divider" }),
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "palette-heading", children: "Redact" }),
|
|
938
|
+
FIELD_TYPE_META.filter((f) => f.group === "redact").map(({ type, label, icon }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
939
|
+
"div",
|
|
940
|
+
{
|
|
941
|
+
className: `palette-item ${activeFieldType === type ? "active" : ""}`,
|
|
942
|
+
draggable: true,
|
|
943
|
+
onClick: () => setActiveFieldType(type),
|
|
944
|
+
onDragStart: (e) => handlePaletteDragStart(e, type),
|
|
945
|
+
onDragEnd: handlePaletteDragEnd,
|
|
946
|
+
children: [
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "palette-item-icon", children: icon }),
|
|
948
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "palette-item-label", children: label })
|
|
949
|
+
]
|
|
950
|
+
},
|
|
951
|
+
type
|
|
952
|
+
))
|
|
789
953
|
] }),
|
|
790
|
-
/* @__PURE__ */ (0,
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
onAddRole: handleAddRole,
|
|
799
|
-
onRemoveRole: handleRemoveRole
|
|
800
|
-
}
|
|
801
|
-
),
|
|
802
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "designer-content", children: [
|
|
803
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "designer-pdf-area", children: [
|
|
804
|
-
loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "loading-indicator", children: "Loading PDF..." }),
|
|
805
|
-
!pages.length && !loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "empty-state", children: [
|
|
806
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { children: "Upload a PDF to get started" }),
|
|
807
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Upload a template PDF, then click on the page to place form fields." }),
|
|
808
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "upload-btn upload-btn-large", children: [
|
|
809
|
-
"Choose PDF File",
|
|
810
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "file", accept: ".pdf", onChange: handleFileUpload, hidden: true })
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "designer-pdf-area", children: [
|
|
955
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "loading-indicator", children: "Loading PDF..." }),
|
|
956
|
+
!pages.length && !loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "empty-state", children: [
|
|
957
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { children: "Open a PDF to get started" }),
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "Select a PDF from your device to begin. Your file stays on your computer \u2014 nothing is uploaded." }),
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "upload-btn upload-btn-large", children: [
|
|
960
|
+
"Select PDF",
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "file", accept: ".pdf", onChange: handleFileUpload, hidden: true })
|
|
811
962
|
] })
|
|
812
963
|
] }),
|
|
813
|
-
pages.length > 0 && /* @__PURE__ */ (0,
|
|
964
|
+
pages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
814
965
|
PdfViewer,
|
|
815
966
|
{
|
|
816
967
|
pages,
|
|
817
968
|
fields,
|
|
818
969
|
selectedFieldId,
|
|
819
|
-
onSelectField:
|
|
970
|
+
onSelectField: (id) => {
|
|
971
|
+
setSelectedFieldId(id);
|
|
972
|
+
if (id) setRightTab("properties");
|
|
973
|
+
},
|
|
820
974
|
onFieldMove: handleFieldMove,
|
|
821
975
|
onFieldResize: handleFieldResize,
|
|
822
976
|
onPageClick: handlePageClick,
|
|
977
|
+
onDropField: handleDropOnPage,
|
|
823
978
|
mode: "designer",
|
|
824
979
|
renderFieldContent
|
|
825
980
|
}
|
|
826
981
|
)
|
|
827
982
|
] }),
|
|
828
|
-
/* @__PURE__ */ (0,
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
signerRoles,
|
|
835
|
-
onUpdate: handleFieldUpdate,
|
|
836
|
-
onDelete: handleFieldDelete
|
|
837
|
-
}
|
|
838
|
-
),
|
|
839
|
-
selectedField.assignee === activeRole && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "prefill-section", children: [
|
|
840
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Pre-fill Value" }),
|
|
841
|
-
selectedField.type === "signature" || selectedField.type === "initials" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
842
|
-
SignatureCanvas,
|
|
983
|
+
pages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
984
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "panel-resize-handle", onMouseDown: handleResizeStart }),
|
|
985
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "designer-panel", style: { width: panelWidth }, children: [
|
|
986
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "panel-tabs", children: [
|
|
987
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
988
|
+
"button",
|
|
843
989
|
{
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
initialValue: selectedField.value
|
|
990
|
+
className: `panel-tab ${rightTab === "properties" ? "active" : ""}`,
|
|
991
|
+
onClick: () => setRightTab("properties"),
|
|
992
|
+
children: "Properties"
|
|
848
993
|
}
|
|
849
|
-
)
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
{
|
|
853
|
-
type: "checkbox",
|
|
854
|
-
checked: selectedField.value === "true",
|
|
855
|
-
onChange: (e) => handleFieldUpdate(selectedField.id, { value: e.target.checked ? "true" : "" })
|
|
856
|
-
}
|
|
857
|
-
),
|
|
858
|
-
"Checked"
|
|
859
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
860
|
-
"input",
|
|
994
|
+
),
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
996
|
+
"button",
|
|
861
997
|
{
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
998
|
+
className: `panel-tab ${rightTab === "fields" ? "active" : ""}`,
|
|
999
|
+
onClick: () => setRightTab("fields"),
|
|
1000
|
+
children: [
|
|
1001
|
+
"All Fields",
|
|
1002
|
+
fields.length > 0 ? ` (${fields.length})` : ""
|
|
1003
|
+
]
|
|
867
1004
|
}
|
|
868
1005
|
)
|
|
869
|
-
] })
|
|
870
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "panel-empty", children: pages.length > 0 ? "Click on the PDF to place a field, or select an existing field to edit its properties." : "Upload a PDF to begin designing your template." }),
|
|
871
|
-
fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-list", children: [
|
|
872
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h4", { children: [
|
|
873
|
-
"All Fields (",
|
|
874
|
-
fields.length,
|
|
875
|
-
")"
|
|
876
1006
|
] }),
|
|
877
|
-
|
|
878
|
-
"
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1007
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "panel-tab-content", children: [
|
|
1008
|
+
rightTab === "properties" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: selectedField ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1010
|
+
FieldPropertyPanel,
|
|
1011
|
+
{
|
|
1012
|
+
field: selectedField,
|
|
1013
|
+
signerRoles,
|
|
1014
|
+
onUpdate: handleFieldUpdate,
|
|
1015
|
+
onDelete: handleFieldDelete
|
|
1016
|
+
}
|
|
1017
|
+
),
|
|
1018
|
+
selectedField.type !== "blackout" && selectedField.type !== "whiteout" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "prefill-section", children: [
|
|
1019
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { children: "Pre-fill Value" }),
|
|
1020
|
+
selectedField.type === "signature" || selectedField.type === "initials" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1021
|
+
SignatureCanvas,
|
|
885
1022
|
{
|
|
886
|
-
|
|
887
|
-
|
|
1023
|
+
width: panelWidth - 40,
|
|
1024
|
+
height: selectedField.type === "initials" ? 100 : 150,
|
|
1025
|
+
onSign: (dataUrl) => handleFieldUpdate(selectedField.id, { value: dataUrl }),
|
|
1026
|
+
initialValue: selectedField.value,
|
|
1027
|
+
inkColor: selectedField.inkColor
|
|
888
1028
|
}
|
|
889
|
-
),
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1029
|
+
) : selectedField.type === "checkbox" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "panel-checkbox-label", children: [
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1031
|
+
"input",
|
|
1032
|
+
{
|
|
1033
|
+
type: "checkbox",
|
|
1034
|
+
checked: selectedField.value === "true",
|
|
1035
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, { value: e.target.checked ? "true" : "" })
|
|
1036
|
+
}
|
|
1037
|
+
),
|
|
1038
|
+
"Checked"
|
|
1039
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1040
|
+
"input",
|
|
1041
|
+
{
|
|
1042
|
+
type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
|
|
1043
|
+
value: selectedField.value,
|
|
1044
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, { value: e.target.value }),
|
|
1045
|
+
placeholder: `Pre-fill ${selectedField.label}`,
|
|
1046
|
+
className: "prefill-input",
|
|
1047
|
+
style: { color: selectedField.inkColor || "#000000" }
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
1050
|
+
] })
|
|
1051
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "panel-empty", children: "Click on the PDF to place a field, or select an existing field to edit its properties." }) }),
|
|
1052
|
+
rightTab === "fields" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: fields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "panel-empty", children: "No fields yet. Drag a field from the left palette onto the PDF, or click on the PDF to place one." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "field-list", children: sortedFields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1053
|
+
"div",
|
|
1054
|
+
{
|
|
1055
|
+
className: `field-list-item ${f.id === selectedFieldId ? "active" : ""}`,
|
|
1056
|
+
onClick: () => {
|
|
1057
|
+
setSelectedFieldId(f.id);
|
|
1058
|
+
setRightTab("properties");
|
|
1059
|
+
},
|
|
1060
|
+
children: [
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1062
|
+
"span",
|
|
1063
|
+
{
|
|
1064
|
+
className: "field-list-dot",
|
|
1065
|
+
style: { backgroundColor: getSignerColor(f.assignee) }
|
|
1066
|
+
}
|
|
1067
|
+
),
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "field-list-name", children: f.label }),
|
|
1069
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "field-list-page", children: [
|
|
1070
|
+
"p",
|
|
1071
|
+
f.page + 1
|
|
1072
|
+
] }),
|
|
1073
|
+
f.required && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "field-list-required", children: "*" })
|
|
1074
|
+
]
|
|
1075
|
+
},
|
|
1076
|
+
f.id
|
|
1077
|
+
)) }) })
|
|
1078
|
+
] }),
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "powered-by", children: [
|
|
1080
|
+
"Powered by ",
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1082
|
+
] })
|
|
900
1083
|
] })
|
|
901
1084
|
] })
|
|
902
|
-
] }),
|
|
903
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "powered-by", children: [
|
|
904
|
-
"Powered by ",
|
|
905
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
906
1085
|
] })
|
|
907
1086
|
] });
|
|
908
1087
|
}
|
|
909
1088
|
|
|
910
1089
|
// src/components/pdf-builder/SignerView.tsx
|
|
911
|
-
var
|
|
1090
|
+
var import_react4 = require("react");
|
|
912
1091
|
|
|
913
1092
|
// src/utils/pdfFiller.ts
|
|
914
1093
|
var import_pdf_lib = require("pdf-lib");
|
|
@@ -923,8 +1102,13 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
923
1102
|
const pdfDoc = await import_pdf_lib.PDFDocument.load(pdfBytes);
|
|
924
1103
|
const font = await pdfDoc.embedFont(import_pdf_lib.StandardFonts.Helvetica);
|
|
925
1104
|
const pages = pdfDoc.getPages();
|
|
1105
|
+
function hexToRgb(hex) {
|
|
1106
|
+
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
1107
|
+
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
1108
|
+
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
1109
|
+
return (0, import_pdf_lib.rgb)(r, g, b);
|
|
1110
|
+
}
|
|
926
1111
|
for (const field of fields) {
|
|
927
|
-
if (!field.value) continue;
|
|
928
1112
|
const page = pages[field.page];
|
|
929
1113
|
if (!page) continue;
|
|
930
1114
|
const pageWidth = page.getWidth();
|
|
@@ -933,6 +1117,18 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
933
1117
|
const y = pageHeight - field.y / 100 * pageHeight - field.height / 100 * pageHeight;
|
|
934
1118
|
const w = field.width / 100 * pageWidth;
|
|
935
1119
|
const h = field.height / 100 * pageHeight;
|
|
1120
|
+
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1121
|
+
page.drawRectangle({
|
|
1122
|
+
x,
|
|
1123
|
+
y,
|
|
1124
|
+
width: w,
|
|
1125
|
+
height: h,
|
|
1126
|
+
color: field.type === "blackout" ? (0, import_pdf_lib.rgb)(0, 0, 0) : (0, import_pdf_lib.rgb)(1, 1, 1)
|
|
1127
|
+
});
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
if (!field.value) continue;
|
|
1131
|
+
const inkColor = field.inkColor ? hexToRgb(field.inkColor) : (0, import_pdf_lib.rgb)(0, 0, 0);
|
|
936
1132
|
if (field.type === "checkbox") {
|
|
937
1133
|
if (field.value === "true") {
|
|
938
1134
|
const inset = Math.min(w, h) * 0.2;
|
|
@@ -941,13 +1137,13 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
941
1137
|
start: { x: x + inset, y: y + inset },
|
|
942
1138
|
end: { x: x + w - inset, y: y + h - inset },
|
|
943
1139
|
thickness: lineWidth,
|
|
944
|
-
color:
|
|
1140
|
+
color: inkColor
|
|
945
1141
|
});
|
|
946
1142
|
page.drawLine({
|
|
947
1143
|
start: { x: x + w - inset, y: y + inset },
|
|
948
1144
|
end: { x: x + inset, y: y + h - inset },
|
|
949
1145
|
thickness: lineWidth,
|
|
950
|
-
color:
|
|
1146
|
+
color: inkColor
|
|
951
1147
|
});
|
|
952
1148
|
}
|
|
953
1149
|
} else if (field.type === "signature" || field.type === "initials") {
|
|
@@ -971,7 +1167,7 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
971
1167
|
y: y + h * 0.3,
|
|
972
1168
|
size: fontSize,
|
|
973
1169
|
font,
|
|
974
|
-
color:
|
|
1170
|
+
color: inkColor,
|
|
975
1171
|
maxWidth: w - 4
|
|
976
1172
|
});
|
|
977
1173
|
}
|
|
@@ -998,7 +1194,7 @@ async function postPdfToCallback(bytes, callbackUrl, filename) {
|
|
|
998
1194
|
}
|
|
999
1195
|
|
|
1000
1196
|
// src/components/pdf-builder/FieldNavigator.tsx
|
|
1001
|
-
var
|
|
1197
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1002
1198
|
function FieldNavigator({
|
|
1003
1199
|
fields,
|
|
1004
1200
|
currentFieldId,
|
|
@@ -1024,15 +1220,15 @@ function FieldNavigator({
|
|
|
1024
1220
|
if (f.type === "checkbox") return true;
|
|
1025
1221
|
return !!f.value;
|
|
1026
1222
|
}).length;
|
|
1027
|
-
return /* @__PURE__ */ (0,
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator", children: [
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator-progress", children: [
|
|
1029
1225
|
filledCount,
|
|
1030
1226
|
" of ",
|
|
1031
1227
|
fields.length,
|
|
1032
1228
|
" fields completed"
|
|
1033
1229
|
] }),
|
|
1034
|
-
/* @__PURE__ */ (0,
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1230
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator-controls", children: [
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1036
1232
|
"button",
|
|
1037
1233
|
{
|
|
1038
1234
|
onClick: handlePrev,
|
|
@@ -1041,8 +1237,8 @@ function FieldNavigator({
|
|
|
1041
1237
|
children: "Prev"
|
|
1042
1238
|
}
|
|
1043
1239
|
),
|
|
1044
|
-
/* @__PURE__ */ (0,
|
|
1045
|
-
/* @__PURE__ */ (0,
|
|
1240
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "field-navigator-position", children: currentIndex >= 0 ? `${currentIndex + 1} / ${fields.length}` : "-" }),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1046
1242
|
"button",
|
|
1047
1243
|
{
|
|
1048
1244
|
onClick: handleNext,
|
|
@@ -1052,7 +1248,7 @@ function FieldNavigator({
|
|
|
1052
1248
|
}
|
|
1053
1249
|
)
|
|
1054
1250
|
] }),
|
|
1055
|
-
/* @__PURE__ */ (0,
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1056
1252
|
"button",
|
|
1057
1253
|
{
|
|
1058
1254
|
onClick: onSubmit,
|
|
@@ -1065,26 +1261,49 @@ function FieldNavigator({
|
|
|
1065
1261
|
}
|
|
1066
1262
|
|
|
1067
1263
|
// src/components/pdf-builder/SignerView.tsx
|
|
1068
|
-
var
|
|
1264
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1069
1265
|
function SignerView({
|
|
1266
|
+
apiKey,
|
|
1070
1267
|
initialPdfUrl,
|
|
1071
1268
|
initialTemplate,
|
|
1072
1269
|
initialSigner,
|
|
1073
1270
|
callbackUrl: initialCallbackUrl,
|
|
1074
|
-
onComplete
|
|
1271
|
+
onComplete,
|
|
1272
|
+
initialValues
|
|
1075
1273
|
} = {}) {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1274
|
+
if (!isValidApiKey(apiKey)) {
|
|
1275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-layout", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "empty-state", children: [
|
|
1276
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "Invalid API Key" }),
|
|
1277
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
|
|
1278
|
+
"A valid API key is required to use Exeq. Visit ",
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: "https://exeq.org", children: "exeq.org" }),
|
|
1280
|
+
" to get one."
|
|
1281
|
+
] })
|
|
1282
|
+
] }) });
|
|
1283
|
+
}
|
|
1284
|
+
const [pages, setPages] = (0, import_react4.useState)([]);
|
|
1285
|
+
const [fields, setFields] = (0, import_react4.useState)([]);
|
|
1286
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react4.useState)(null);
|
|
1287
|
+
const [signer, setSigner] = (0, import_react4.useState)(initialSigner || "Signer 1");
|
|
1288
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
1289
|
+
const [submitting, setSubmitting] = (0, import_react4.useState)(false);
|
|
1290
|
+
const [pdfSource, setPdfSource] = (0, import_react4.useState)(null);
|
|
1291
|
+
const [callbackUrl, setCallbackUrl] = (0, import_react4.useState)(initialCallbackUrl || "");
|
|
1292
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
1293
|
+
(0, import_react4.useEffect)(() => {
|
|
1086
1294
|
if (initialTemplate) {
|
|
1087
|
-
|
|
1295
|
+
let templateFields = initialTemplate.fields;
|
|
1296
|
+
if (initialValues) {
|
|
1297
|
+
templateFields = templateFields.map((f) => {
|
|
1298
|
+
const byLabel = Object.entries(initialValues).find(
|
|
1299
|
+
([key]) => key.toLowerCase() === f.label.toLowerCase()
|
|
1300
|
+
);
|
|
1301
|
+
const byId = initialValues[f.id];
|
|
1302
|
+
const value = byLabel?.[1] ?? byId;
|
|
1303
|
+
return value !== void 0 ? { ...f, value } : f;
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
setFields(templateFields);
|
|
1088
1307
|
if (initialPdfUrl) loadPdf(initialPdfUrl);
|
|
1089
1308
|
return;
|
|
1090
1309
|
}
|
|
@@ -1110,7 +1329,7 @@ function SignerView({
|
|
|
1110
1329
|
window.addEventListener("message", handleMessage);
|
|
1111
1330
|
return () => window.removeEventListener("message", handleMessage);
|
|
1112
1331
|
}, [initialTemplate, initialPdfUrl]);
|
|
1113
|
-
const loadPdf = (0,
|
|
1332
|
+
const loadPdf = (0, import_react4.useCallback)(async (source) => {
|
|
1114
1333
|
setLoading(true);
|
|
1115
1334
|
try {
|
|
1116
1335
|
const rendered = await renderPdfPages(source);
|
|
@@ -1122,13 +1341,18 @@ function SignerView({
|
|
|
1122
1341
|
setLoading(false);
|
|
1123
1342
|
}
|
|
1124
1343
|
}, []);
|
|
1125
|
-
const editableFields = fields.filter((f) => f.assignee === signer)
|
|
1344
|
+
const editableFields = fields.filter((f) => f.assignee === signer).sort((a, b) => {
|
|
1345
|
+
if (a.page !== b.page) return a.page - b.page;
|
|
1346
|
+
const bandThreshold = 2;
|
|
1347
|
+
if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
|
|
1348
|
+
return a.x - b.x;
|
|
1349
|
+
});
|
|
1126
1350
|
const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
|
|
1127
1351
|
const isFieldEditable = selectedField ? selectedField.assignee === signer : false;
|
|
1128
|
-
const handleFieldUpdate = (0,
|
|
1352
|
+
const handleFieldUpdate = (0, import_react4.useCallback)((id, value) => {
|
|
1129
1353
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
|
|
1130
1354
|
}, []);
|
|
1131
|
-
const handleNavigate = (0,
|
|
1355
|
+
const handleNavigate = (0, import_react4.useCallback)((fieldId) => {
|
|
1132
1356
|
setSelectedFieldId(fieldId);
|
|
1133
1357
|
const field = fields.find((f) => f.id === fieldId);
|
|
1134
1358
|
if (field && containerRef.current) {
|
|
@@ -1143,7 +1367,7 @@ function SignerView({
|
|
|
1143
1367
|
if (f.type === "checkbox") return true;
|
|
1144
1368
|
return !!f.value;
|
|
1145
1369
|
});
|
|
1146
|
-
const handleSubmit = (0,
|
|
1370
|
+
const handleSubmit = (0, import_react4.useCallback)(async () => {
|
|
1147
1371
|
if (!pdfSource || !allRequiredFilled) return;
|
|
1148
1372
|
setSubmitting(true);
|
|
1149
1373
|
try {
|
|
@@ -1163,25 +1387,25 @@ function SignerView({
|
|
|
1163
1387
|
setSubmitting(false);
|
|
1164
1388
|
}
|
|
1165
1389
|
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete]);
|
|
1166
|
-
const renderFieldContent = (0,
|
|
1390
|
+
const renderFieldContent = (0, import_react4.useCallback)((field) => {
|
|
1167
1391
|
const editable = field.assignee === signer;
|
|
1168
1392
|
if (!editable) {
|
|
1169
1393
|
if (field.type === "signature" || field.type === "initials") {
|
|
1170
|
-
return field.value ? /* @__PURE__ */ (0,
|
|
1394
|
+
return field.value ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-placeholder readonly", children: field.placeholder });
|
|
1171
1395
|
}
|
|
1172
1396
|
if (field.type === "checkbox") {
|
|
1173
|
-
return /* @__PURE__ */ (0,
|
|
1397
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-checkbox-display readonly", children: field.value === "true" ? "\u2713" : "" });
|
|
1174
1398
|
}
|
|
1175
|
-
return /* @__PURE__ */ (0,
|
|
1399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-placeholder readonly", children: field.value || field.placeholder });
|
|
1176
1400
|
}
|
|
1177
1401
|
if (field.type === "signature" || field.type === "initials") {
|
|
1178
1402
|
if (field.value) {
|
|
1179
|
-
return /* @__PURE__ */ (0,
|
|
1403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-signature-filled", onClick: () => handleFieldUpdate(field.id, ""), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" }) });
|
|
1180
1404
|
}
|
|
1181
|
-
return /* @__PURE__ */ (0,
|
|
1405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-placeholder editable", children: field.placeholder });
|
|
1182
1406
|
}
|
|
1183
1407
|
if (field.type === "checkbox") {
|
|
1184
|
-
return /* @__PURE__ */ (0,
|
|
1408
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1185
1409
|
"div",
|
|
1186
1410
|
{
|
|
1187
1411
|
className: "field-checkbox-display editable",
|
|
@@ -1194,9 +1418,9 @@ function SignerView({
|
|
|
1194
1418
|
);
|
|
1195
1419
|
}
|
|
1196
1420
|
if (field.type === "signed-date") {
|
|
1197
|
-
return /* @__PURE__ */ (0,
|
|
1421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value", children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
|
|
1198
1422
|
}
|
|
1199
|
-
return /* @__PURE__ */ (0,
|
|
1423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1200
1424
|
"input",
|
|
1201
1425
|
{
|
|
1202
1426
|
type: field.textSubtype === "email" ? "email" : field.textSubtype === "number" ? "number" : field.textSubtype === "phone" ? "tel" : field.textSubtype === "date" ? "date" : "text",
|
|
@@ -1209,7 +1433,7 @@ function SignerView({
|
|
|
1209
1433
|
}
|
|
1210
1434
|
);
|
|
1211
1435
|
}, [signer, handleFieldUpdate]);
|
|
1212
|
-
(0,
|
|
1436
|
+
(0, import_react4.useEffect)(() => {
|
|
1213
1437
|
const sigFields = fields.filter((f) => f.assignee === signer && f.type === "signature" && f.value);
|
|
1214
1438
|
if (sigFields.length > 0) {
|
|
1215
1439
|
const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
@@ -1221,10 +1445,10 @@ function SignerView({
|
|
|
1221
1445
|
}));
|
|
1222
1446
|
}
|
|
1223
1447
|
}, [fields.filter((f) => f.type === "signature" && f.value).length]);
|
|
1224
|
-
return /* @__PURE__ */ (0,
|
|
1225
|
-
loading && /* @__PURE__ */ (0,
|
|
1226
|
-
/* @__PURE__ */ (0,
|
|
1227
|
-
/* @__PURE__ */ (0,
|
|
1448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-layout", ref: containerRef, children: [
|
|
1449
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Loading document..." }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-content", children: [
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-pdf-area", children: pages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1228
1452
|
PdfViewer,
|
|
1229
1453
|
{
|
|
1230
1454
|
pages,
|
|
@@ -1236,11 +1460,11 @@ function SignerView({
|
|
|
1236
1460
|
renderFieldContent
|
|
1237
1461
|
}
|
|
1238
1462
|
) }),
|
|
1239
|
-
/* @__PURE__ */ (0,
|
|
1240
|
-
selectedField && isFieldEditable && /* @__PURE__ */ (0,
|
|
1241
|
-
/* @__PURE__ */ (0,
|
|
1242
|
-
selectedField.required && /* @__PURE__ */ (0,
|
|
1243
|
-
(selectedField.type === "signature" || selectedField.type === "initials") && /* @__PURE__ */ (0,
|
|
1463
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-panel", children: [
|
|
1464
|
+
selectedField && isFieldEditable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-field-input", children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: selectedField.label }),
|
|
1466
|
+
selectedField.required && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "required-badge", children: "Required" }),
|
|
1467
|
+
(selectedField.type === "signature" || selectedField.type === "initials") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1244
1468
|
SignatureCanvas,
|
|
1245
1469
|
{
|
|
1246
1470
|
width: 280,
|
|
@@ -1249,7 +1473,7 @@ function SignerView({
|
|
|
1249
1473
|
initialValue: selectedField.value
|
|
1250
1474
|
}
|
|
1251
1475
|
),
|
|
1252
|
-
selectedField.type === "text" && /* @__PURE__ */ (0,
|
|
1476
|
+
selectedField.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1253
1477
|
"input",
|
|
1254
1478
|
{
|
|
1255
1479
|
type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
|
|
@@ -1259,8 +1483,8 @@ function SignerView({
|
|
|
1259
1483
|
className: "signer-text-input"
|
|
1260
1484
|
}
|
|
1261
1485
|
),
|
|
1262
|
-
selectedField.type === "checkbox" && /* @__PURE__ */ (0,
|
|
1263
|
-
/* @__PURE__ */ (0,
|
|
1486
|
+
selectedField.type === "checkbox" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "signer-checkbox-label", children: [
|
|
1487
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1264
1488
|
"input",
|
|
1265
1489
|
{
|
|
1266
1490
|
type: "checkbox",
|
|
@@ -1270,14 +1494,14 @@ function SignerView({
|
|
|
1270
1494
|
),
|
|
1271
1495
|
selectedField.placeholder || "Check this box"
|
|
1272
1496
|
] }),
|
|
1273
|
-
selectedField.type === "signed-date" && /* @__PURE__ */ (0,
|
|
1497
|
+
selectedField.type === "signed-date" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-date-display", children: selectedField.value || "Will auto-fill when you sign" })
|
|
1274
1498
|
] }),
|
|
1275
|
-
selectedField && !isFieldEditable && /* @__PURE__ */ (0,
|
|
1276
|
-
/* @__PURE__ */ (0,
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1499
|
+
selectedField && !isFieldEditable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-field-readonly", children: [
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: selectedField.label }),
|
|
1501
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "This field belongs to another signer." })
|
|
1278
1502
|
] }),
|
|
1279
|
-
!selectedField && editableFields.length > 0 && /* @__PURE__ */ (0,
|
|
1280
|
-
/* @__PURE__ */ (0,
|
|
1503
|
+
!selectedField && editableFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "panel-empty", children: "Select a field to fill it in, or use the navigation below." }),
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1281
1505
|
FieldNavigator,
|
|
1282
1506
|
{
|
|
1283
1507
|
fields: editableFields,
|
|
@@ -1287,12 +1511,87 @@ function SignerView({
|
|
|
1287
1511
|
onSubmit: handleSubmit
|
|
1288
1512
|
}
|
|
1289
1513
|
),
|
|
1290
|
-
submitting && /* @__PURE__ */ (0,
|
|
1514
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Generating PDF..." })
|
|
1291
1515
|
] })
|
|
1292
1516
|
] }),
|
|
1293
|
-
/* @__PURE__ */ (0,
|
|
1517
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "powered-by", children: [
|
|
1294
1518
|
"Powered by ",
|
|
1295
|
-
/* @__PURE__ */ (0,
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1520
|
+
] })
|
|
1521
|
+
] });
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// src/components/pdf-builder/SignerRoleSelector.tsx
|
|
1525
|
+
var import_react5 = require("react");
|
|
1526
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1527
|
+
function SignerRoleSelector({
|
|
1528
|
+
roles,
|
|
1529
|
+
activeRole,
|
|
1530
|
+
onSetActiveRole,
|
|
1531
|
+
onAddRole,
|
|
1532
|
+
onRemoveRole
|
|
1533
|
+
}) {
|
|
1534
|
+
const [isAdding, setIsAdding] = (0, import_react5.useState)(false);
|
|
1535
|
+
const [newRoleName, setNewRoleName] = (0, import_react5.useState)("");
|
|
1536
|
+
const handleAdd = () => {
|
|
1537
|
+
if (newRoleName.trim()) {
|
|
1538
|
+
onAddRole(newRoleName.trim());
|
|
1539
|
+
setNewRoleName("");
|
|
1540
|
+
setIsAdding(false);
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "signer-role-selector", children: [
|
|
1544
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "signer-role-label", children: "Signer Roles" }),
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "signer-role-list", children: [
|
|
1546
|
+
roles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1547
|
+
"button",
|
|
1548
|
+
{
|
|
1549
|
+
className: `signer-role-chip ${role === activeRole ? "active" : ""}`,
|
|
1550
|
+
style: {
|
|
1551
|
+
borderColor: getSignerColor(role),
|
|
1552
|
+
backgroundColor: role === activeRole ? getSignerColor(role) : "transparent",
|
|
1553
|
+
color: role === activeRole ? "#fff" : getSignerColor(role)
|
|
1554
|
+
},
|
|
1555
|
+
onClick: () => onSetActiveRole(role),
|
|
1556
|
+
children: [
|
|
1557
|
+
role,
|
|
1558
|
+
roles.length > 1 && role !== "Sender" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1559
|
+
"span",
|
|
1560
|
+
{
|
|
1561
|
+
className: "signer-role-remove",
|
|
1562
|
+
onClick: (e) => {
|
|
1563
|
+
e.stopPropagation();
|
|
1564
|
+
onRemoveRole(role);
|
|
1565
|
+
},
|
|
1566
|
+
children: "\xD7"
|
|
1567
|
+
}
|
|
1568
|
+
)
|
|
1569
|
+
]
|
|
1570
|
+
},
|
|
1571
|
+
role
|
|
1572
|
+
)),
|
|
1573
|
+
isAdding ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "signer-role-add-input", children: [
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1575
|
+
"input",
|
|
1576
|
+
{
|
|
1577
|
+
type: "text",
|
|
1578
|
+
value: newRoleName,
|
|
1579
|
+
onChange: (e) => setNewRoleName(e.target.value),
|
|
1580
|
+
onKeyDown: (e) => e.key === "Enter" && handleAdd(),
|
|
1581
|
+
placeholder: "Role name",
|
|
1582
|
+
autoFocus: true
|
|
1583
|
+
}
|
|
1584
|
+
),
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: handleAdd, children: "Add" }),
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: () => setIsAdding(false), children: "Cancel" })
|
|
1587
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1588
|
+
"button",
|
|
1589
|
+
{
|
|
1590
|
+
className: "signer-role-add-btn",
|
|
1591
|
+
onClick: () => setIsAdding(true),
|
|
1592
|
+
children: "+ Add Role"
|
|
1593
|
+
}
|
|
1594
|
+
)
|
|
1296
1595
|
] })
|
|
1297
1596
|
] });
|
|
1298
1597
|
}
|
|
@@ -1313,6 +1612,7 @@ function SignerView({
|
|
|
1313
1612
|
generateFilledPdf,
|
|
1314
1613
|
getSignerColor,
|
|
1315
1614
|
postPdfToCallback,
|
|
1316
|
-
renderPdfPages
|
|
1615
|
+
renderPdfPages,
|
|
1616
|
+
uniqueLabel
|
|
1317
1617
|
});
|
|
1318
1618
|
//# sourceMappingURL=index.js.map
|