@unlev/exeq 0.1.12 → 0.2.1
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 +51 -0
- package/dist/index.css +54 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +421 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +377 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,9 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/lib/index.ts
|
|
31
31
|
var lib_exports = {};
|
|
32
32
|
__export(lib_exports, {
|
|
33
|
+
BUILTIN_TRANSFORMS: () => BUILTIN_TRANSFORMS,
|
|
33
34
|
DEFAULT_SIGNER_ROLES: () => DEFAULT_SIGNER_ROLES,
|
|
34
35
|
DesignerView: () => DesignerView,
|
|
35
36
|
FIELD_DEFAULTS: () => FIELD_DEFAULTS,
|
|
37
|
+
FONT_FAMILIES: () => FONT_FAMILIES,
|
|
36
38
|
FieldNavigator: () => FieldNavigator,
|
|
37
39
|
FieldPropertyPanel: () => FieldPropertyPanel,
|
|
38
40
|
PdfViewer: () => PdfViewer,
|
|
@@ -43,15 +45,18 @@ __export(lib_exports, {
|
|
|
43
45
|
createField: () => createField,
|
|
44
46
|
downloadPdf: () => downloadPdf,
|
|
45
47
|
generateFilledPdf: () => generateFilledPdf,
|
|
48
|
+
generateId: () => generateId,
|
|
46
49
|
getSignerColor: () => getSignerColor,
|
|
47
50
|
postPdfToCallback: () => postPdfToCallback,
|
|
48
51
|
renderPdfPages: () => renderPdfPages,
|
|
52
|
+
resolveAllFormulas: () => resolveAllFormulas,
|
|
53
|
+
resolveFormula: () => resolveFormula,
|
|
49
54
|
uniqueLabel: () => uniqueLabel
|
|
50
55
|
});
|
|
51
56
|
module.exports = __toCommonJS(lib_exports);
|
|
52
57
|
|
|
53
58
|
// src/components/pdf-builder/DesignerView.tsx
|
|
54
|
-
var
|
|
59
|
+
var import_react4 = require("react");
|
|
55
60
|
var import_react_dom = require("react-dom");
|
|
56
61
|
|
|
57
62
|
// src/types/pdf-builder.ts
|
|
@@ -77,6 +82,11 @@ var SIGNER_ROLE_COLORS = {
|
|
|
77
82
|
function getSignerColor(role) {
|
|
78
83
|
return SIGNER_ROLE_COLORS[role] || "#888888";
|
|
79
84
|
}
|
|
85
|
+
var FONT_FAMILIES = [
|
|
86
|
+
{ value: "Helvetica", label: "Helvetica" },
|
|
87
|
+
{ value: "Courier", label: "Courier New" },
|
|
88
|
+
{ value: "TimesRoman", label: "Times New Roman" }
|
|
89
|
+
];
|
|
80
90
|
var FIELD_DEFAULTS = {
|
|
81
91
|
text: {
|
|
82
92
|
width: 20,
|
|
@@ -85,6 +95,12 @@ var FIELD_DEFAULTS = {
|
|
|
85
95
|
placeholder: "Enter text",
|
|
86
96
|
textSubtype: "freeform"
|
|
87
97
|
},
|
|
98
|
+
dropdown: {
|
|
99
|
+
width: 20,
|
|
100
|
+
height: 3,
|
|
101
|
+
fontSize: 12,
|
|
102
|
+
placeholder: "Select..."
|
|
103
|
+
},
|
|
88
104
|
signature: {
|
|
89
105
|
width: 20,
|
|
90
106
|
height: 6,
|
|
@@ -124,6 +140,7 @@ var FIELD_DEFAULTS = {
|
|
|
124
140
|
};
|
|
125
141
|
var TYPE_LABELS = {
|
|
126
142
|
text: "Text Field",
|
|
143
|
+
dropdown: "Dropdown",
|
|
127
144
|
signature: "Signature",
|
|
128
145
|
"signed-date": "Signed Date",
|
|
129
146
|
checkbox: "Checkbox",
|
|
@@ -388,6 +405,7 @@ function FieldOverlayItem({
|
|
|
388
405
|
}
|
|
389
406
|
|
|
390
407
|
// src/components/pdf-builder/FieldPropertyPanel.tsx
|
|
408
|
+
var import_react2 = require("react");
|
|
391
409
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
392
410
|
var INK_COLORS = [
|
|
393
411
|
{ value: "#000000", label: "Black" },
|
|
@@ -396,8 +414,9 @@ var INK_COLORS = [
|
|
|
396
414
|
function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
397
415
|
const color = getSignerColor(field.assignee);
|
|
398
416
|
const isRedactField = field.type === "blackout" || field.type === "whiteout";
|
|
399
|
-
const
|
|
400
|
-
const showInkColor = field.type === "text" || field.type === "signature" || field.type === "initials" || field.type === "signed-date";
|
|
417
|
+
const isTextField = field.type === "text" || field.type === "signed-date" || field.type === "dropdown";
|
|
418
|
+
const showInkColor = field.type === "text" || field.type === "dropdown" || field.type === "signature" || field.type === "initials" || field.type === "signed-date";
|
|
419
|
+
const [newOption, setNewOption] = (0, import_react2.useState)("");
|
|
401
420
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "field-property-panel", children: [
|
|
402
421
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-header", children: [
|
|
403
422
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { color }, children: field.label }),
|
|
@@ -423,6 +442,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
423
442
|
onChange: (e) => onUpdate(field.id, { type: e.target.value }),
|
|
424
443
|
children: [
|
|
425
444
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "text", children: "Text" }),
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "dropdown", children: "Dropdown" }),
|
|
426
446
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "signature", children: "Signature" }),
|
|
427
447
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "signed-date", children: "Signed Date" }),
|
|
428
448
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "checkbox", children: "Checkbox" }),
|
|
@@ -470,6 +490,19 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
470
490
|
}
|
|
471
491
|
)
|
|
472
492
|
] }),
|
|
493
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Formula" }),
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
496
|
+
"input",
|
|
497
|
+
{
|
|
498
|
+
type: "text",
|
|
499
|
+
value: field.formula || "",
|
|
500
|
+
onChange: (e) => onUpdate(field.id, { formula: e.target.value || void 0 }),
|
|
501
|
+
placeholder: "e.g. {{Date Field | month}}"
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
field.formula && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "panel-hint", children: "This field auto-computes from other fields. Signer cannot edit it." })
|
|
505
|
+
] }),
|
|
473
506
|
!isRedactField && field.type !== "checkbox" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-field", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "panel-checkbox-label", children: [
|
|
474
507
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
475
508
|
"input",
|
|
@@ -481,7 +514,18 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
481
514
|
),
|
|
482
515
|
"Required"
|
|
483
516
|
] }) }),
|
|
484
|
-
|
|
517
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
518
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font" }),
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
520
|
+
"select",
|
|
521
|
+
{
|
|
522
|
+
value: field.fontFamily || "Helvetica",
|
|
523
|
+
onChange: (e) => onUpdate(field.id, { fontFamily: e.target.value }),
|
|
524
|
+
children: FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: f.value, children: f.label }, f.value))
|
|
525
|
+
}
|
|
526
|
+
)
|
|
527
|
+
] }),
|
|
528
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
485
529
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font Size (pt)" }),
|
|
486
530
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
487
531
|
"input",
|
|
@@ -494,6 +538,49 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
494
538
|
}
|
|
495
539
|
)
|
|
496
540
|
] }),
|
|
541
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field-row", children: [
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field panel-field-half", children: [
|
|
543
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Letter Spacing" }),
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
545
|
+
"input",
|
|
546
|
+
{
|
|
547
|
+
type: "number",
|
|
548
|
+
min: "0",
|
|
549
|
+
max: "20",
|
|
550
|
+
step: "0.5",
|
|
551
|
+
value: field.letterSpacing || 0,
|
|
552
|
+
onChange: (e) => onUpdate(field.id, { letterSpacing: Number(e.target.value) })
|
|
553
|
+
}
|
|
554
|
+
)
|
|
555
|
+
] }),
|
|
556
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field panel-field-half", children: [
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Line Height" }),
|
|
558
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
559
|
+
"input",
|
|
560
|
+
{
|
|
561
|
+
type: "number",
|
|
562
|
+
min: "0.8",
|
|
563
|
+
max: "3",
|
|
564
|
+
step: "0.1",
|
|
565
|
+
value: field.lineHeight || 1.2,
|
|
566
|
+
onChange: (e) => onUpdate(field.id, { lineHeight: Number(e.target.value) })
|
|
567
|
+
}
|
|
568
|
+
)
|
|
569
|
+
] })
|
|
570
|
+
] }),
|
|
571
|
+
field.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
572
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Max Characters (0 = unlimited)" }),
|
|
573
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
574
|
+
"input",
|
|
575
|
+
{
|
|
576
|
+
type: "number",
|
|
577
|
+
min: "0",
|
|
578
|
+
max: "9999",
|
|
579
|
+
value: field.maxLength || 0,
|
|
580
|
+
onChange: (e) => onUpdate(field.id, { maxLength: Number(e.target.value) })
|
|
581
|
+
}
|
|
582
|
+
)
|
|
583
|
+
] }),
|
|
497
584
|
showInkColor && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
498
585
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Ink Color" }),
|
|
499
586
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ink-color-picker", children: INK_COLORS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -506,12 +593,62 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
506
593
|
},
|
|
507
594
|
c.value
|
|
508
595
|
)) })
|
|
596
|
+
] }),
|
|
597
|
+
(field.type === "text" || field.type === "dropdown") && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: field.type === "dropdown" ? "Options" : "Predefined Options" }),
|
|
599
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-options-list", children: [
|
|
600
|
+
(field.options || []).map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-option-item", children: [
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: opt }),
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
603
|
+
"button",
|
|
604
|
+
{
|
|
605
|
+
className: "panel-option-remove",
|
|
606
|
+
onClick: () => {
|
|
607
|
+
const updated = (field.options || []).filter((_, j) => j !== i);
|
|
608
|
+
onUpdate(field.id, { options: updated.length > 0 ? updated : void 0 });
|
|
609
|
+
},
|
|
610
|
+
children: "\xD7"
|
|
611
|
+
}
|
|
612
|
+
)
|
|
613
|
+
] }, i)),
|
|
614
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-option-add", children: [
|
|
615
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
616
|
+
"input",
|
|
617
|
+
{
|
|
618
|
+
type: "text",
|
|
619
|
+
value: newOption,
|
|
620
|
+
onChange: (e) => setNewOption(e.target.value),
|
|
621
|
+
onKeyDown: (e) => {
|
|
622
|
+
if (e.key === "Enter" && newOption.trim()) {
|
|
623
|
+
onUpdate(field.id, { options: [...field.options || [], newOption.trim()] });
|
|
624
|
+
setNewOption("");
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
placeholder: "Add option..."
|
|
628
|
+
}
|
|
629
|
+
),
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
631
|
+
"button",
|
|
632
|
+
{
|
|
633
|
+
onClick: () => {
|
|
634
|
+
if (newOption.trim()) {
|
|
635
|
+
onUpdate(field.id, { options: [...field.options || [], newOption.trim()] });
|
|
636
|
+
setNewOption("");
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
children: "+"
|
|
640
|
+
}
|
|
641
|
+
)
|
|
642
|
+
] })
|
|
643
|
+
] }),
|
|
644
|
+
field.type === "dropdown" && (field.options?.length ?? 0) === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "panel-hint", style: { color: "#c44" }, children: "Add at least one option" }),
|
|
645
|
+
field.type === "text" && (field.options?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "panel-hint", children: "Signer will choose from these options via dropdown" })
|
|
509
646
|
] })
|
|
510
647
|
] });
|
|
511
648
|
}
|
|
512
649
|
|
|
513
650
|
// src/components/pdf-builder/SignatureCanvas.tsx
|
|
514
|
-
var
|
|
651
|
+
var import_react3 = require("react");
|
|
515
652
|
var import_perfect_freehand = require("perfect-freehand");
|
|
516
653
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
517
654
|
function getSvgPathFromStroke(stroke) {
|
|
@@ -535,11 +672,11 @@ function SignatureCanvas({
|
|
|
535
672
|
className,
|
|
536
673
|
inkColor = "#000000"
|
|
537
674
|
}) {
|
|
538
|
-
const canvasRef = (0,
|
|
539
|
-
const [paths, setPaths] = (0,
|
|
540
|
-
const [currentPath, setCurrentPath] = (0,
|
|
541
|
-
const [isEmpty, setIsEmpty] = (0,
|
|
542
|
-
(0,
|
|
675
|
+
const canvasRef = (0, import_react3.useRef)(null);
|
|
676
|
+
const [paths, setPaths] = (0, import_react3.useState)([]);
|
|
677
|
+
const [currentPath, setCurrentPath] = (0, import_react3.useState)(null);
|
|
678
|
+
const [isEmpty, setIsEmpty] = (0, import_react3.useState)(!initialValue);
|
|
679
|
+
(0, import_react3.useEffect)(() => {
|
|
543
680
|
if (initialValue && canvasRef.current) {
|
|
544
681
|
const ctx = canvasRef.current.getContext("2d");
|
|
545
682
|
const img = new Image();
|
|
@@ -550,7 +687,7 @@ function SignatureCanvas({
|
|
|
550
687
|
img.src = initialValue;
|
|
551
688
|
}
|
|
552
689
|
}, [initialValue, width, height]);
|
|
553
|
-
(0,
|
|
690
|
+
(0, import_react3.useEffect)(() => {
|
|
554
691
|
const canvas = canvasRef.current;
|
|
555
692
|
if (!canvas) return;
|
|
556
693
|
const ctx = canvas.getContext("2d");
|
|
@@ -569,7 +706,7 @@ function SignatureCanvas({
|
|
|
569
706
|
ctx.fill(path2d);
|
|
570
707
|
}
|
|
571
708
|
}, [paths, currentPath, width, height]);
|
|
572
|
-
const getPoint = (0,
|
|
709
|
+
const getPoint = (0, import_react3.useCallback)((e) => {
|
|
573
710
|
const canvas = canvasRef.current;
|
|
574
711
|
const rect = canvas.getBoundingClientRect();
|
|
575
712
|
const style = getComputedStyle(canvas);
|
|
@@ -587,17 +724,17 @@ function SignatureCanvas({
|
|
|
587
724
|
e.pressure
|
|
588
725
|
];
|
|
589
726
|
}, []);
|
|
590
|
-
const handlePointerDown = (0,
|
|
727
|
+
const handlePointerDown = (0, import_react3.useCallback)((e) => {
|
|
591
728
|
e.preventDefault();
|
|
592
729
|
e.target.setPointerCapture(e.pointerId);
|
|
593
730
|
setCurrentPath([getPoint(e)]);
|
|
594
731
|
}, [getPoint]);
|
|
595
|
-
const handlePointerMove = (0,
|
|
732
|
+
const handlePointerMove = (0, import_react3.useCallback)((e) => {
|
|
596
733
|
if (!currentPath) return;
|
|
597
734
|
e.preventDefault();
|
|
598
735
|
setCurrentPath([...currentPath, getPoint(e)]);
|
|
599
736
|
}, [currentPath, getPoint]);
|
|
600
|
-
const handlePointerUp = (0,
|
|
737
|
+
const handlePointerUp = (0, import_react3.useCallback)(() => {
|
|
601
738
|
if (!currentPath) return;
|
|
602
739
|
setPaths((prev) => [...prev, currentPath]);
|
|
603
740
|
setCurrentPath(null);
|
|
@@ -608,7 +745,7 @@ function SignatureCanvas({
|
|
|
608
745
|
}
|
|
609
746
|
});
|
|
610
747
|
}, [currentPath, onSign]);
|
|
611
|
-
const handleClear = (0,
|
|
748
|
+
const handleClear = (0, import_react3.useCallback)(() => {
|
|
612
749
|
setPaths([]);
|
|
613
750
|
setCurrentPath(null);
|
|
614
751
|
setIsEmpty(true);
|
|
@@ -654,6 +791,7 @@ function isValidApiKey(key) {
|
|
|
654
791
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
655
792
|
var FIELD_TYPE_META = [
|
|
656
793
|
{ type: "text", label: "Text", icon: "T" },
|
|
794
|
+
{ type: "dropdown", label: "Dropdown", icon: "\u25BE" },
|
|
657
795
|
{ type: "signature", label: "Signature", icon: "\u270D" },
|
|
658
796
|
{ type: "signed-date", label: "Date", icon: "\u{1F4C5}" },
|
|
659
797
|
{ type: "checkbox", label: "Checkbox", icon: "\u2611" },
|
|
@@ -679,24 +817,24 @@ function DesignerView({
|
|
|
679
817
|
] })
|
|
680
818
|
] }) });
|
|
681
819
|
}
|
|
682
|
-
const [pages, setPages] = (0,
|
|
683
|
-
const [fields, setFields] = (0,
|
|
684
|
-
const [selectedFieldId, setSelectedFieldId] = (0,
|
|
685
|
-
const [signerRoles, setSignerRoles] = (0,
|
|
686
|
-
const [activeRole, setActiveRole] = (0,
|
|
687
|
-
const [activeFieldType, setActiveFieldType] = (0,
|
|
688
|
-
const [loading, setLoading] = (0,
|
|
689
|
-
const [pdfSource, setPdfSource] = (0,
|
|
690
|
-
const [rightTab, setRightTab] = (0,
|
|
691
|
-
const [isAddingRole, setIsAddingRole] = (0,
|
|
692
|
-
const [newRoleName, setNewRoleName] = (0,
|
|
693
|
-
const [draggingFieldType, setDraggingFieldType] = (0,
|
|
694
|
-
const [panelWidth, setPanelWidth] = (0,
|
|
695
|
-
const [clipboardField, setClipboardField] = (0,
|
|
696
|
-
const dragGhostRef = (0,
|
|
697
|
-
const resizingRef = (0,
|
|
698
|
-
const lastStylesRef = (0,
|
|
699
|
-
(0,
|
|
820
|
+
const [pages, setPages] = (0, import_react4.useState)([]);
|
|
821
|
+
const [fields, setFields] = (0, import_react4.useState)(initialTemplate?.fields ?? []);
|
|
822
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react4.useState)(null);
|
|
823
|
+
const [signerRoles, setSignerRoles] = (0, import_react4.useState)(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
|
|
824
|
+
const [activeRole, setActiveRole] = (0, import_react4.useState)("Sender");
|
|
825
|
+
const [activeFieldType, setActiveFieldType] = (0, import_react4.useState)("text");
|
|
826
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
827
|
+
const [pdfSource, setPdfSource] = (0, import_react4.useState)(null);
|
|
828
|
+
const [rightTab, setRightTab] = (0, import_react4.useState)("properties");
|
|
829
|
+
const [isAddingRole, setIsAddingRole] = (0, import_react4.useState)(false);
|
|
830
|
+
const [newRoleName, setNewRoleName] = (0, import_react4.useState)("");
|
|
831
|
+
const [draggingFieldType, setDraggingFieldType] = (0, import_react4.useState)(null);
|
|
832
|
+
const [panelWidth, setPanelWidth] = (0, import_react4.useState)(380);
|
|
833
|
+
const [clipboardField, setClipboardField] = (0, import_react4.useState)(null);
|
|
834
|
+
const dragGhostRef = (0, import_react4.useRef)(null);
|
|
835
|
+
const resizingRef = (0, import_react4.useRef)(false);
|
|
836
|
+
const lastStylesRef = (0, import_react4.useRef)({});
|
|
837
|
+
(0, import_react4.useEffect)(() => {
|
|
700
838
|
const pdfUrl = initialPdfUrl || initialTemplate?.pdfUrl;
|
|
701
839
|
if (pdfUrl) {
|
|
702
840
|
loadPdf(pdfUrl);
|
|
@@ -720,7 +858,7 @@ function DesignerView({
|
|
|
720
858
|
window.addEventListener("message", handleMessage);
|
|
721
859
|
return () => window.removeEventListener("message", handleMessage);
|
|
722
860
|
}, [initialPdfUrl, initialTemplate]);
|
|
723
|
-
const loadPdf = (0,
|
|
861
|
+
const loadPdf = (0, import_react4.useCallback)(async (source) => {
|
|
724
862
|
setLoading(true);
|
|
725
863
|
try {
|
|
726
864
|
const rendered = await renderPdfPages(source);
|
|
@@ -732,7 +870,7 @@ function DesignerView({
|
|
|
732
870
|
setLoading(false);
|
|
733
871
|
}
|
|
734
872
|
}, []);
|
|
735
|
-
const handleFileUpload = (0,
|
|
873
|
+
const handleFileUpload = (0, import_react4.useCallback)((e) => {
|
|
736
874
|
const file = e.target.files?.[0];
|
|
737
875
|
if (!file) return;
|
|
738
876
|
const reader = new FileReader();
|
|
@@ -741,7 +879,7 @@ function DesignerView({
|
|
|
741
879
|
};
|
|
742
880
|
reader.readAsArrayBuffer(file);
|
|
743
881
|
}, [loadPdf]);
|
|
744
|
-
const handlePageClick = (0,
|
|
882
|
+
const handlePageClick = (0, import_react4.useCallback)((page, x, y) => {
|
|
745
883
|
const field = createField(activeFieldType, activeRole, page, x, y, fields);
|
|
746
884
|
const sticky = lastStylesRef.current[activeFieldType];
|
|
747
885
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
@@ -749,10 +887,10 @@ function DesignerView({
|
|
|
749
887
|
setSelectedFieldId(styledField.id);
|
|
750
888
|
setRightTab("properties");
|
|
751
889
|
}, [activeFieldType, activeRole, fields]);
|
|
752
|
-
const handleFieldMove = (0,
|
|
890
|
+
const handleFieldMove = (0, import_react4.useCallback)((id, page, x, y) => {
|
|
753
891
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, page, x, y } : f));
|
|
754
892
|
}, []);
|
|
755
|
-
const handleFieldResize = (0,
|
|
893
|
+
const handleFieldResize = (0, import_react4.useCallback)((id, width, height) => {
|
|
756
894
|
setFields((prev) => {
|
|
757
895
|
const field = prev.find((f) => f.id === id);
|
|
758
896
|
if (field) {
|
|
@@ -762,7 +900,7 @@ function DesignerView({
|
|
|
762
900
|
return prev.map((f) => f.id === id ? { ...f, width, height } : f);
|
|
763
901
|
});
|
|
764
902
|
}, []);
|
|
765
|
-
const handleFieldUpdate = (0,
|
|
903
|
+
const handleFieldUpdate = (0, import_react4.useCallback)((id, updates) => {
|
|
766
904
|
setFields((prev) => {
|
|
767
905
|
if (updates.label !== void 0) {
|
|
768
906
|
const otherLabels = prev.filter((f) => f.id !== id).map((f) => f.label);
|
|
@@ -782,11 +920,11 @@ function DesignerView({
|
|
|
782
920
|
return updated;
|
|
783
921
|
});
|
|
784
922
|
}, []);
|
|
785
|
-
const handleFieldDelete = (0,
|
|
923
|
+
const handleFieldDelete = (0, import_react4.useCallback)((id) => {
|
|
786
924
|
setFields((prev) => prev.filter((f) => f.id !== id));
|
|
787
925
|
if (selectedFieldId === id) setSelectedFieldId(null);
|
|
788
926
|
}, [selectedFieldId]);
|
|
789
|
-
const handleAddRole = (0,
|
|
927
|
+
const handleAddRole = (0, import_react4.useCallback)(() => {
|
|
790
928
|
const name = newRoleName.trim();
|
|
791
929
|
if (name && !signerRoles.includes(name)) {
|
|
792
930
|
setSignerRoles((prev) => [...prev, name]);
|
|
@@ -794,12 +932,12 @@ function DesignerView({
|
|
|
794
932
|
setNewRoleName("");
|
|
795
933
|
setIsAddingRole(false);
|
|
796
934
|
}, [newRoleName, signerRoles]);
|
|
797
|
-
const handleRemoveRole = (0,
|
|
935
|
+
const handleRemoveRole = (0, import_react4.useCallback)((role) => {
|
|
798
936
|
setSignerRoles((prev) => prev.filter((r) => r !== role));
|
|
799
937
|
setFields((prev) => prev.map((f) => f.assignee === role ? { ...f, assignee: signerRoles[0] } : f));
|
|
800
938
|
if (activeRole === role) setActiveRole(signerRoles[0]);
|
|
801
939
|
}, [signerRoles, activeRole]);
|
|
802
|
-
const handleExport = (0,
|
|
940
|
+
const handleExport = (0, import_react4.useCallback)(() => {
|
|
803
941
|
const template = {
|
|
804
942
|
fields,
|
|
805
943
|
signerRoles,
|
|
@@ -819,7 +957,7 @@ function DesignerView({
|
|
|
819
957
|
}
|
|
820
958
|
window.parent?.postMessage({ type: "template-saved", template }, "*");
|
|
821
959
|
}, [fields, signerRoles, pdfSource, onSave]);
|
|
822
|
-
const handlePaletteDragStart = (0,
|
|
960
|
+
const handlePaletteDragStart = (0, import_react4.useCallback)((e, type) => {
|
|
823
961
|
setDraggingFieldType(type);
|
|
824
962
|
e.dataTransfer.setData("application/exeq-field-type", type);
|
|
825
963
|
e.dataTransfer.effectAllowed = "copy";
|
|
@@ -836,14 +974,14 @@ function DesignerView({
|
|
|
836
974
|
e.dataTransfer.setDragImage(ghost, 40, 16);
|
|
837
975
|
dragGhostRef.current = ghost;
|
|
838
976
|
}, [activeRole]);
|
|
839
|
-
const handlePaletteDragEnd = (0,
|
|
977
|
+
const handlePaletteDragEnd = (0, import_react4.useCallback)(() => {
|
|
840
978
|
setDraggingFieldType(null);
|
|
841
979
|
if (dragGhostRef.current) {
|
|
842
980
|
document.body.removeChild(dragGhostRef.current);
|
|
843
981
|
dragGhostRef.current = null;
|
|
844
982
|
}
|
|
845
983
|
}, []);
|
|
846
|
-
const handleDropOnPage = (0,
|
|
984
|
+
const handleDropOnPage = (0, import_react4.useCallback)((page, x, y, fieldType) => {
|
|
847
985
|
const field = createField(fieldType, activeRole, page, x, y, fields);
|
|
848
986
|
const sticky = lastStylesRef.current[fieldType];
|
|
849
987
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
@@ -851,7 +989,7 @@ function DesignerView({
|
|
|
851
989
|
setSelectedFieldId(styledField.id);
|
|
852
990
|
setRightTab("properties");
|
|
853
991
|
}, [activeRole, fields]);
|
|
854
|
-
(0,
|
|
992
|
+
(0, import_react4.useEffect)(() => {
|
|
855
993
|
const handleKeyDown = (e) => {
|
|
856
994
|
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
857
995
|
if (!selectedFieldId) return;
|
|
@@ -866,7 +1004,7 @@ function DesignerView({
|
|
|
866
1004
|
window.addEventListener("keydown", handleKeyDown);
|
|
867
1005
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
868
1006
|
}, [selectedFieldId, handleFieldDelete]);
|
|
869
|
-
(0,
|
|
1007
|
+
(0, import_react4.useEffect)(() => {
|
|
870
1008
|
const handleKeyDown = (e) => {
|
|
871
1009
|
const tag = (document.activeElement?.tagName || "").toLowerCase();
|
|
872
1010
|
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
@@ -898,7 +1036,7 @@ function DesignerView({
|
|
|
898
1036
|
window.addEventListener("keydown", handleKeyDown);
|
|
899
1037
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
900
1038
|
}, [selectedFieldId, fields, clipboardField]);
|
|
901
|
-
const handleResizeStart = (0,
|
|
1039
|
+
const handleResizeStart = (0, import_react4.useCallback)((e) => {
|
|
902
1040
|
e.preventDefault();
|
|
903
1041
|
resizingRef.current = true;
|
|
904
1042
|
const startX = e.clientX;
|
|
@@ -923,7 +1061,7 @@ function DesignerView({
|
|
|
923
1061
|
return a.x - b.x;
|
|
924
1062
|
});
|
|
925
1063
|
const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
|
|
926
|
-
const renderFieldContent = (0,
|
|
1064
|
+
const renderFieldContent = (0, import_react4.useCallback)((field) => {
|
|
927
1065
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
928
1066
|
return null;
|
|
929
1067
|
}
|
|
@@ -933,15 +1071,22 @@ function DesignerView({
|
|
|
933
1071
|
}
|
|
934
1072
|
}
|
|
935
1073
|
const inkColor = field.inkColor || "#000000";
|
|
1074
|
+
const cssFontFamily = field.fontFamily === "Courier" ? '"Courier New", Courier, monospace' : field.fontFamily === "TimesRoman" ? '"Times New Roman", Times, serif' : field.fontFamily === "Helvetica" ? "Helvetica, Arial, sans-serif" : void 0;
|
|
936
1075
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
937
1076
|
"div",
|
|
938
1077
|
{
|
|
939
1078
|
className: "field-overlay-placeholder",
|
|
940
|
-
style: {
|
|
1079
|
+
style: {
|
|
1080
|
+
color: field.value ? inkColor : void 0,
|
|
1081
|
+
fontSize: `${field.fontSize * 0.6}px`,
|
|
1082
|
+
fontFamily: cssFontFamily,
|
|
1083
|
+
letterSpacing: field.letterSpacing ? `${field.letterSpacing * 0.6}px` : void 0,
|
|
1084
|
+
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0
|
|
1085
|
+
},
|
|
941
1086
|
children: field.value || field.placeholder
|
|
942
1087
|
}
|
|
943
1088
|
);
|
|
944
|
-
}, []);
|
|
1089
|
+
}, [fields]);
|
|
945
1090
|
const headerButtons = pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
946
1091
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "header-btn header-btn-outline", children: [
|
|
947
1092
|
"Change PDF",
|
|
@@ -1160,10 +1305,15 @@ function DesignerView({
|
|
|
1160
1305
|
}
|
|
1161
1306
|
|
|
1162
1307
|
// src/components/pdf-builder/SignerView.tsx
|
|
1163
|
-
var
|
|
1308
|
+
var import_react6 = require("react");
|
|
1164
1309
|
|
|
1165
1310
|
// src/utils/pdfFiller.ts
|
|
1166
1311
|
var import_pdf_lib = require("pdf-lib");
|
|
1312
|
+
var FONT_MAP = {
|
|
1313
|
+
"Helvetica": import_pdf_lib.StandardFonts.Helvetica,
|
|
1314
|
+
"Courier": import_pdf_lib.StandardFonts.Courier,
|
|
1315
|
+
"TimesRoman": import_pdf_lib.StandardFonts.TimesRoman
|
|
1316
|
+
};
|
|
1167
1317
|
async function generateFilledPdf(pdfSource, fields) {
|
|
1168
1318
|
let pdfBytes;
|
|
1169
1319
|
if (typeof pdfSource === "string") {
|
|
@@ -1173,7 +1323,12 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
1173
1323
|
pdfBytes = pdfSource;
|
|
1174
1324
|
}
|
|
1175
1325
|
const pdfDoc = await import_pdf_lib.PDFDocument.load(pdfBytes);
|
|
1176
|
-
const
|
|
1326
|
+
const fontCache = /* @__PURE__ */ new Map();
|
|
1327
|
+
const usedFontKeys = new Set(fields.map((f) => f.fontFamily || "Helvetica"));
|
|
1328
|
+
for (const key of usedFontKeys) {
|
|
1329
|
+
const stdFont = FONT_MAP[key] || import_pdf_lib.StandardFonts.Helvetica;
|
|
1330
|
+
fontCache.set(key, await pdfDoc.embedFont(stdFont));
|
|
1331
|
+
}
|
|
1177
1332
|
const pages = pdfDoc.getPages();
|
|
1178
1333
|
function hexToRgb(hex) {
|
|
1179
1334
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
@@ -1234,21 +1389,35 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
1234
1389
|
});
|
|
1235
1390
|
}
|
|
1236
1391
|
} else {
|
|
1392
|
+
const font = fontCache.get(field.fontFamily || "Helvetica");
|
|
1393
|
+
const spacing = field.letterSpacing || 0;
|
|
1394
|
+
const textWidthAtSize = (text, size) => {
|
|
1395
|
+
const baseWidth = font.widthOfTextAtSize(text, size);
|
|
1396
|
+
return baseWidth + spacing * (text.length - 1);
|
|
1397
|
+
};
|
|
1237
1398
|
const maxFontSize = Math.min(field.fontSize, h * 0.7);
|
|
1238
1399
|
let fontSize = maxFontSize;
|
|
1239
1400
|
const padding = 4;
|
|
1240
1401
|
while (fontSize > 4) {
|
|
1241
|
-
|
|
1242
|
-
if (textWidth <= w - padding) break;
|
|
1402
|
+
if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
|
|
1243
1403
|
fontSize -= 0.5;
|
|
1244
1404
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1405
|
+
if (spacing > 0) {
|
|
1406
|
+
let cx = x + 2;
|
|
1407
|
+
const cy = y + h * 0.3;
|
|
1408
|
+
for (const char of field.value) {
|
|
1409
|
+
page.drawText(char, { x: cx, y: cy, size: fontSize, font, color: inkColor });
|
|
1410
|
+
cx += font.widthOfTextAtSize(char, fontSize) + spacing;
|
|
1411
|
+
}
|
|
1412
|
+
} else {
|
|
1413
|
+
page.drawText(field.value, {
|
|
1414
|
+
x: x + 2,
|
|
1415
|
+
y: y + h * 0.3,
|
|
1416
|
+
size: fontSize,
|
|
1417
|
+
font,
|
|
1418
|
+
color: inkColor
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1252
1421
|
}
|
|
1253
1422
|
}
|
|
1254
1423
|
return pdfDoc.save();
|
|
@@ -1273,7 +1442,7 @@ async function postPdfToCallback(bytes, callbackUrl, filename) {
|
|
|
1273
1442
|
}
|
|
1274
1443
|
|
|
1275
1444
|
// src/components/pdf-builder/FieldNavigator.tsx
|
|
1276
|
-
var
|
|
1445
|
+
var import_react5 = require("react");
|
|
1277
1446
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1278
1447
|
function isFieldFilled(f) {
|
|
1279
1448
|
if (!f.required) return true;
|
|
@@ -1288,7 +1457,7 @@ function FieldNavigator({
|
|
|
1288
1457
|
onComplete,
|
|
1289
1458
|
completeLabel = "Complete"
|
|
1290
1459
|
}) {
|
|
1291
|
-
const [showIncomplete, setShowIncomplete] = (0,
|
|
1460
|
+
const [showIncomplete, setShowIncomplete] = (0, import_react5.useState)(false);
|
|
1292
1461
|
const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
|
|
1293
1462
|
const hasPrev = currentIndex > 0;
|
|
1294
1463
|
const hasNext = currentIndex < fields.length - 1;
|
|
@@ -1363,6 +1532,95 @@ function FieldNavigator({
|
|
|
1363
1532
|
] });
|
|
1364
1533
|
}
|
|
1365
1534
|
|
|
1535
|
+
// src/utils/formulaResolver.ts
|
|
1536
|
+
var BUILTIN_TRANSFORMS = {
|
|
1537
|
+
// Date transforms (expects a parseable date string)
|
|
1538
|
+
month: (v) => {
|
|
1539
|
+
const d = new Date(v);
|
|
1540
|
+
return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1);
|
|
1541
|
+
},
|
|
1542
|
+
month2: (v) => {
|
|
1543
|
+
const d = new Date(v);
|
|
1544
|
+
return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1).padStart(2, "0");
|
|
1545
|
+
},
|
|
1546
|
+
monthname: (v) => {
|
|
1547
|
+
const d = new Date(v);
|
|
1548
|
+
return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "long" });
|
|
1549
|
+
},
|
|
1550
|
+
monthshort: (v) => {
|
|
1551
|
+
const d = new Date(v);
|
|
1552
|
+
return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "short" });
|
|
1553
|
+
},
|
|
1554
|
+
day: (v) => {
|
|
1555
|
+
const d = new Date(v);
|
|
1556
|
+
return isNaN(d.getTime()) ? "" : String(d.getDate());
|
|
1557
|
+
},
|
|
1558
|
+
day2: (v) => {
|
|
1559
|
+
const d = new Date(v);
|
|
1560
|
+
return isNaN(d.getTime()) ? "" : String(d.getDate()).padStart(2, "0");
|
|
1561
|
+
},
|
|
1562
|
+
year: (v) => {
|
|
1563
|
+
const d = new Date(v);
|
|
1564
|
+
return isNaN(d.getTime()) ? "" : String(d.getFullYear());
|
|
1565
|
+
},
|
|
1566
|
+
year2: (v) => {
|
|
1567
|
+
const d = new Date(v);
|
|
1568
|
+
return isNaN(d.getTime()) ? "" : String(d.getFullYear()).slice(-2);
|
|
1569
|
+
},
|
|
1570
|
+
// String transforms
|
|
1571
|
+
upper: (v) => v.toUpperCase(),
|
|
1572
|
+
lower: (v) => v.toLowerCase(),
|
|
1573
|
+
trim: (v) => v.trim(),
|
|
1574
|
+
first: (v) => v.split(/\s+/)[0] || "",
|
|
1575
|
+
last: (v) => {
|
|
1576
|
+
const parts = v.split(/\s+/);
|
|
1577
|
+
return parts[parts.length - 1] || "";
|
|
1578
|
+
},
|
|
1579
|
+
initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
|
|
1580
|
+
// Numeric / substring
|
|
1581
|
+
last4: (v) => v.slice(-4),
|
|
1582
|
+
last2: (v) => v.slice(-2),
|
|
1583
|
+
first4: (v) => v.slice(0, 4),
|
|
1584
|
+
first2: (v) => v.slice(0, 2),
|
|
1585
|
+
digits: (v) => v.replace(/\D/g, ""),
|
|
1586
|
+
number: (v) => {
|
|
1587
|
+
const n = parseFloat(v);
|
|
1588
|
+
return isNaN(n) ? "" : String(n);
|
|
1589
|
+
},
|
|
1590
|
+
currency: (v) => {
|
|
1591
|
+
const n = parseFloat(v.replace(/[^0-9.-]/g, ""));
|
|
1592
|
+
return isNaN(n) ? "" : `$${n.toFixed(2)}`;
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
var FORMULA_RE = /\{\{(.+?)\}\}/g;
|
|
1596
|
+
var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
|
|
1597
|
+
function resolveFormula(formula, fields, customTransforms) {
|
|
1598
|
+
const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
|
|
1599
|
+
return formula.replace(FORMULA_RE, (_match, expr) => {
|
|
1600
|
+
const pipeMatch = expr.match(PIPE_RE);
|
|
1601
|
+
const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
|
|
1602
|
+
const transformName = pipeMatch ? pipeMatch[2].trim() : null;
|
|
1603
|
+
const sourceField = fields.find((f) => f.label.toLowerCase() === sourceLabel.toLowerCase()) || fields.find((f) => f.id === sourceLabel);
|
|
1604
|
+
if (!sourceField) return "";
|
|
1605
|
+
const rawValue = sourceField.value || "";
|
|
1606
|
+
if (!transformName) return rawValue;
|
|
1607
|
+
const fn = transforms[transformName];
|
|
1608
|
+
if (!fn) return rawValue;
|
|
1609
|
+
try {
|
|
1610
|
+
return fn(rawValue);
|
|
1611
|
+
} catch {
|
|
1612
|
+
return rawValue;
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
function resolveAllFormulas(fields, customTransforms) {
|
|
1617
|
+
return fields.map((f) => {
|
|
1618
|
+
if (!f.formula) return f;
|
|
1619
|
+
const computed = resolveFormula(f.formula, fields, customTransforms);
|
|
1620
|
+
return computed !== f.value ? { ...f, value: computed } : f;
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1366
1624
|
// src/components/pdf-builder/SignerView.tsx
|
|
1367
1625
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1368
1626
|
function SignerView({
|
|
@@ -1374,7 +1632,8 @@ function SignerView({
|
|
|
1374
1632
|
onComplete,
|
|
1375
1633
|
initialValues,
|
|
1376
1634
|
submitLabel,
|
|
1377
|
-
signerOrder: signerOrderProp
|
|
1635
|
+
signerOrder: signerOrderProp,
|
|
1636
|
+
transforms
|
|
1378
1637
|
} = {}) {
|
|
1379
1638
|
if (!isValidApiKey(apiKey)) {
|
|
1380
1639
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-layout", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "empty-state", children: [
|
|
@@ -1386,28 +1645,43 @@ function SignerView({
|
|
|
1386
1645
|
] })
|
|
1387
1646
|
] }) });
|
|
1388
1647
|
}
|
|
1389
|
-
const [pages, setPages] = (0,
|
|
1390
|
-
const [fields, setFields] = (0,
|
|
1391
|
-
const [selectedFieldId, setSelectedFieldId] = (0,
|
|
1392
|
-
const [signerRoles, setSignerRoles] = (0,
|
|
1393
|
-
const [currentSignerIndex, setCurrentSignerIndex] = (0,
|
|
1648
|
+
const [pages, setPages] = (0, import_react6.useState)([]);
|
|
1649
|
+
const [fields, setFields] = (0, import_react6.useState)([]);
|
|
1650
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react6.useState)(null);
|
|
1651
|
+
const [signerRoles, setSignerRoles] = (0, import_react6.useState)([]);
|
|
1652
|
+
const [currentSignerIndex, setCurrentSignerIndex] = (0, import_react6.useState)(() => {
|
|
1394
1653
|
if (initialSigner && signerOrderProp) {
|
|
1395
1654
|
const idx = signerOrderProp.indexOf(initialSigner);
|
|
1396
1655
|
return idx >= 0 ? idx : 0;
|
|
1397
1656
|
}
|
|
1398
1657
|
return 0;
|
|
1399
1658
|
});
|
|
1400
|
-
const initializedRef = (0,
|
|
1401
|
-
const [loading, setLoading] = (0,
|
|
1402
|
-
const [submitting, setSubmitting] = (0,
|
|
1403
|
-
const [pdfSource, setPdfSource] = (0,
|
|
1404
|
-
const [callbackUrl, setCallbackUrl] = (0,
|
|
1405
|
-
const containerRef = (0,
|
|
1659
|
+
const initializedRef = (0, import_react6.useRef)(false);
|
|
1660
|
+
const [loading, setLoading] = (0, import_react6.useState)(false);
|
|
1661
|
+
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
1662
|
+
const [pdfSource, setPdfSource] = (0, import_react6.useState)(null);
|
|
1663
|
+
const [callbackUrl, setCallbackUrl] = (0, import_react6.useState)(initialCallbackUrl || "");
|
|
1664
|
+
const containerRef = (0, import_react6.useRef)(null);
|
|
1406
1665
|
const signerOrder = signerOrderProp || (signerRoles.length > 0 ? [...signerRoles.filter((r) => r !== "Sender"), ...signerRoles.filter((r) => r === "Sender")] : [initialSigner || "Signer 1"]);
|
|
1407
1666
|
const signer = signerOrder[currentSignerIndex] || signerOrder[0] || "Signer 1";
|
|
1408
1667
|
const isLastSigner = currentSignerIndex >= signerOrder.length - 1;
|
|
1409
1668
|
const isMultiSigner = signerOrder.length > 1;
|
|
1410
|
-
(0,
|
|
1669
|
+
(0, import_react6.useEffect)(() => {
|
|
1670
|
+
if (fields.length === 0 || !isMultiSigner) return;
|
|
1671
|
+
const signerFields = fields.filter(
|
|
1672
|
+
(f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout"
|
|
1673
|
+
);
|
|
1674
|
+
const allFilled = signerFields.length > 0 && signerFields.every((f) => {
|
|
1675
|
+
if (!f.required) return true;
|
|
1676
|
+
if (f.type === "checkbox") return true;
|
|
1677
|
+
return !!f.value;
|
|
1678
|
+
});
|
|
1679
|
+
if (allFilled && !isLastSigner) {
|
|
1680
|
+
setCurrentSignerIndex((prev) => prev + 1);
|
|
1681
|
+
setSelectedFieldId(null);
|
|
1682
|
+
}
|
|
1683
|
+
}, [currentSignerIndex, fields, signer, isLastSigner, isMultiSigner]);
|
|
1684
|
+
(0, import_react6.useEffect)(() => {
|
|
1411
1685
|
if (initialTemplate) {
|
|
1412
1686
|
let templateFields = initialTemplate.fields;
|
|
1413
1687
|
if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
|
|
@@ -1477,7 +1751,7 @@ function SignerView({
|
|
|
1477
1751
|
window.addEventListener("message", handleMessage);
|
|
1478
1752
|
return () => window.removeEventListener("message", handleMessage);
|
|
1479
1753
|
}, [initialTemplate, initialPdfUrl]);
|
|
1480
|
-
const loadPdf = (0,
|
|
1754
|
+
const loadPdf = (0, import_react6.useCallback)(async (source) => {
|
|
1481
1755
|
setLoading(true);
|
|
1482
1756
|
try {
|
|
1483
1757
|
const rendered = await renderPdfPages(source);
|
|
@@ -1489,21 +1763,21 @@ function SignerView({
|
|
|
1489
1763
|
setLoading(false);
|
|
1490
1764
|
}
|
|
1491
1765
|
}, []);
|
|
1492
|
-
const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout").sort((a, b) => {
|
|
1766
|
+
const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout" && !f.formula).sort((a, b) => {
|
|
1493
1767
|
if (a.page !== b.page) return a.page - b.page;
|
|
1494
1768
|
const bandThreshold = 2;
|
|
1495
1769
|
if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
|
|
1496
1770
|
return a.x - b.x;
|
|
1497
1771
|
});
|
|
1498
1772
|
const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
|
|
1499
|
-
const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" : false;
|
|
1500
|
-
const handleFieldUpdate = (0,
|
|
1773
|
+
const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" && !selectedField.formula : false;
|
|
1774
|
+
const handleFieldUpdate = (0, import_react6.useCallback)((id, value) => {
|
|
1501
1775
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
|
|
1502
1776
|
}, []);
|
|
1503
|
-
const handleFieldPropertyUpdate = (0,
|
|
1777
|
+
const handleFieldPropertyUpdate = (0, import_react6.useCallback)((id, updates) => {
|
|
1504
1778
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, ...updates } : f));
|
|
1505
1779
|
}, []);
|
|
1506
|
-
const handleNavigate = (0,
|
|
1780
|
+
const handleNavigate = (0, import_react6.useCallback)((fieldId) => {
|
|
1507
1781
|
setSelectedFieldId(fieldId);
|
|
1508
1782
|
const field = fields.find((f) => f.id === fieldId);
|
|
1509
1783
|
if (field && containerRef.current) {
|
|
@@ -1518,7 +1792,7 @@ function SignerView({
|
|
|
1518
1792
|
if (f.type === "checkbox") return true;
|
|
1519
1793
|
return !!f.value;
|
|
1520
1794
|
});
|
|
1521
|
-
const handleAdvanceOrSubmit = (0,
|
|
1795
|
+
const handleAdvanceOrSubmit = (0, import_react6.useCallback)(async () => {
|
|
1522
1796
|
if (!allRequiredFilled) return;
|
|
1523
1797
|
if (!isLastSigner) {
|
|
1524
1798
|
setCurrentSignerIndex((prev) => prev + 1);
|
|
@@ -1532,7 +1806,8 @@ function SignerView({
|
|
|
1532
1806
|
if (!pdfSource) return;
|
|
1533
1807
|
setSubmitting(true);
|
|
1534
1808
|
try {
|
|
1535
|
-
const
|
|
1809
|
+
const finalFields = resolveAllFormulas(fields, transforms);
|
|
1810
|
+
const pdfBytes = await generateFilledPdf(pdfSource, finalFields);
|
|
1536
1811
|
const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
|
|
1537
1812
|
if (callbackUrl) {
|
|
1538
1813
|
await postPdfToCallback(pdfBytes, callbackUrl, "signed-document.pdf");
|
|
@@ -1550,10 +1825,13 @@ function SignerView({
|
|
|
1550
1825
|
setSubmitting(false);
|
|
1551
1826
|
}
|
|
1552
1827
|
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
|
|
1553
|
-
const renderFieldContent = (0,
|
|
1828
|
+
const renderFieldContent = (0, import_react6.useCallback)((field) => {
|
|
1554
1829
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1555
1830
|
return null;
|
|
1556
1831
|
}
|
|
1832
|
+
if (field.formula) {
|
|
1833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value formula", children: field.value || "..." });
|
|
1834
|
+
}
|
|
1557
1835
|
const editable = field.assignee === signer;
|
|
1558
1836
|
if (!editable) {
|
|
1559
1837
|
if (field.type === "signature" || field.type === "initials") {
|
|
@@ -1586,6 +1864,29 @@ function SignerView({
|
|
|
1586
1864
|
if (field.type === "signed-date") {
|
|
1587
1865
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value", children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
|
|
1588
1866
|
}
|
|
1867
|
+
const fontStyle = {
|
|
1868
|
+
fontSize: `${field.fontSize * 0.6}px`,
|
|
1869
|
+
letterSpacing: field.letterSpacing ? `${field.letterSpacing * 0.6}px` : void 0,
|
|
1870
|
+
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
|
|
1871
|
+
fontFamily: field.fontFamily === "Courier" ? '"Courier New", Courier, monospace' : field.fontFamily === "TimesRoman" ? '"Times New Roman", Times, serif' : field.fontFamily === "Helvetica" ? "Helvetica, Arial, sans-serif" : void 0
|
|
1872
|
+
};
|
|
1873
|
+
if (field.type === "dropdown" || field.options && field.options.length > 0) {
|
|
1874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1875
|
+
"select",
|
|
1876
|
+
{
|
|
1877
|
+
className: "field-inline-input",
|
|
1878
|
+
value: field.value,
|
|
1879
|
+
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
1880
|
+
onFocus: () => setSelectedFieldId(field.id),
|
|
1881
|
+
onClick: (e) => e.stopPropagation(),
|
|
1882
|
+
style: fontStyle,
|
|
1883
|
+
children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: field.placeholder || "Select..." }),
|
|
1885
|
+
(field.options || []).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: opt, children: opt }, opt))
|
|
1886
|
+
]
|
|
1887
|
+
}
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1589
1890
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1590
1891
|
"input",
|
|
1591
1892
|
{
|
|
@@ -1593,14 +1894,15 @@ function SignerView({
|
|
|
1593
1894
|
className: "field-inline-input",
|
|
1594
1895
|
value: field.value,
|
|
1595
1896
|
placeholder: field.placeholder,
|
|
1897
|
+
maxLength: field.maxLength || void 0,
|
|
1596
1898
|
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
1597
1899
|
onFocus: () => setSelectedFieldId(field.id),
|
|
1598
1900
|
onClick: (e) => e.stopPropagation(),
|
|
1599
|
-
style:
|
|
1901
|
+
style: fontStyle
|
|
1600
1902
|
}
|
|
1601
1903
|
);
|
|
1602
1904
|
}, [signer, handleFieldUpdate, setSelectedFieldId]);
|
|
1603
|
-
(0,
|
|
1905
|
+
(0, import_react6.useEffect)(() => {
|
|
1604
1906
|
const sigFields = fields.filter((f) => f.assignee === signer && f.type === "signature" && f.value);
|
|
1605
1907
|
if (sigFields.length > 0) {
|
|
1606
1908
|
const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
@@ -1612,6 +1914,13 @@ function SignerView({
|
|
|
1612
1914
|
}));
|
|
1613
1915
|
}
|
|
1614
1916
|
}, [fields.filter((f) => f.type === "signature" && f.value).length]);
|
|
1917
|
+
(0, import_react6.useEffect)(() => {
|
|
1918
|
+
const hasFormulas = fields.some((f) => f.formula);
|
|
1919
|
+
if (!hasFormulas) return;
|
|
1920
|
+
const resolved = resolveAllFormulas(fields, transforms);
|
|
1921
|
+
const changed = resolved.some((f, i) => f.value !== fields[i].value);
|
|
1922
|
+
if (changed) setFields(resolved);
|
|
1923
|
+
}, [fields, transforms]);
|
|
1615
1924
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-layout", ref: containerRef, children: [
|
|
1616
1925
|
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Loading document..." }),
|
|
1617
1926
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-content", children: [
|
|
@@ -1653,14 +1962,26 @@ function SignerView({
|
|
|
1653
1962
|
initialValue: selectedField.value
|
|
1654
1963
|
}
|
|
1655
1964
|
),
|
|
1656
|
-
selectedField.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1657
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.
|
|
1965
|
+
(selectedField.type === "text" || selectedField.type === "dropdown") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1966
|
+
selectedField.type === "dropdown" || selectedField.options && selectedField.options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1967
|
+
"select",
|
|
1968
|
+
{
|
|
1969
|
+
value: selectedField.value,
|
|
1970
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
|
|
1971
|
+
className: "signer-text-input",
|
|
1972
|
+
children: [
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: selectedField.placeholder || "Select..." }),
|
|
1974
|
+
(selectedField.options || []).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: opt, children: opt }, opt))
|
|
1975
|
+
]
|
|
1976
|
+
}
|
|
1977
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1658
1978
|
"input",
|
|
1659
1979
|
{
|
|
1660
1980
|
type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
|
|
1661
1981
|
value: selectedField.value,
|
|
1662
1982
|
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
|
|
1663
1983
|
placeholder: selectedField.placeholder,
|
|
1984
|
+
maxLength: selectedField.maxLength || void 0,
|
|
1664
1985
|
className: "signer-text-input"
|
|
1665
1986
|
}
|
|
1666
1987
|
),
|
|
@@ -1722,7 +2043,7 @@ function SignerView({
|
|
|
1722
2043
|
}
|
|
1723
2044
|
|
|
1724
2045
|
// src/components/pdf-builder/SignerRoleSelector.tsx
|
|
1725
|
-
var
|
|
2046
|
+
var import_react7 = require("react");
|
|
1726
2047
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1727
2048
|
function SignerRoleSelector({
|
|
1728
2049
|
roles,
|
|
@@ -1731,8 +2052,8 @@ function SignerRoleSelector({
|
|
|
1731
2052
|
onAddRole,
|
|
1732
2053
|
onRemoveRole
|
|
1733
2054
|
}) {
|
|
1734
|
-
const [isAdding, setIsAdding] = (0,
|
|
1735
|
-
const [newRoleName, setNewRoleName] = (0,
|
|
2055
|
+
const [isAdding, setIsAdding] = (0, import_react7.useState)(false);
|
|
2056
|
+
const [newRoleName, setNewRoleName] = (0, import_react7.useState)("");
|
|
1736
2057
|
const handleAdd = () => {
|
|
1737
2058
|
if (newRoleName.trim()) {
|
|
1738
2059
|
onAddRole(newRoleName.trim());
|
|
@@ -1797,9 +2118,11 @@ function SignerRoleSelector({
|
|
|
1797
2118
|
}
|
|
1798
2119
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1799
2120
|
0 && (module.exports = {
|
|
2121
|
+
BUILTIN_TRANSFORMS,
|
|
1800
2122
|
DEFAULT_SIGNER_ROLES,
|
|
1801
2123
|
DesignerView,
|
|
1802
2124
|
FIELD_DEFAULTS,
|
|
2125
|
+
FONT_FAMILIES,
|
|
1803
2126
|
FieldNavigator,
|
|
1804
2127
|
FieldPropertyPanel,
|
|
1805
2128
|
PdfViewer,
|
|
@@ -1810,9 +2133,12 @@ function SignerRoleSelector({
|
|
|
1810
2133
|
createField,
|
|
1811
2134
|
downloadPdf,
|
|
1812
2135
|
generateFilledPdf,
|
|
2136
|
+
generateId,
|
|
1813
2137
|
getSignerColor,
|
|
1814
2138
|
postPdfToCallback,
|
|
1815
2139
|
renderPdfPages,
|
|
2140
|
+
resolveAllFormulas,
|
|
2141
|
+
resolveFormula,
|
|
1816
2142
|
uniqueLabel
|
|
1817
2143
|
});
|
|
1818
2144
|
//# sourceMappingURL=index.js.map
|