@unlev/exeq 0.1.12 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/dist/index.css +54 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +399 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +355 -52
- 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,
|
|
@@ -388,6 +398,7 @@ function FieldOverlayItem({
|
|
|
388
398
|
}
|
|
389
399
|
|
|
390
400
|
// src/components/pdf-builder/FieldPropertyPanel.tsx
|
|
401
|
+
var import_react2 = require("react");
|
|
391
402
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
392
403
|
var INK_COLORS = [
|
|
393
404
|
{ value: "#000000", label: "Black" },
|
|
@@ -396,8 +407,9 @@ var INK_COLORS = [
|
|
|
396
407
|
function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
397
408
|
const color = getSignerColor(field.assignee);
|
|
398
409
|
const isRedactField = field.type === "blackout" || field.type === "whiteout";
|
|
399
|
-
const
|
|
410
|
+
const isTextField = field.type === "text" || field.type === "signed-date";
|
|
400
411
|
const showInkColor = field.type === "text" || field.type === "signature" || field.type === "initials" || field.type === "signed-date";
|
|
412
|
+
const [newOption, setNewOption] = (0, import_react2.useState)("");
|
|
401
413
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "field-property-panel", children: [
|
|
402
414
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-header", children: [
|
|
403
415
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { color }, children: field.label }),
|
|
@@ -470,6 +482,19 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
470
482
|
}
|
|
471
483
|
)
|
|
472
484
|
] }),
|
|
485
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
486
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Formula" }),
|
|
487
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
488
|
+
"input",
|
|
489
|
+
{
|
|
490
|
+
type: "text",
|
|
491
|
+
value: field.formula || "",
|
|
492
|
+
onChange: (e) => onUpdate(field.id, { formula: e.target.value || void 0 }),
|
|
493
|
+
placeholder: "e.g. {{Date Field | month}}"
|
|
494
|
+
}
|
|
495
|
+
),
|
|
496
|
+
field.formula && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "panel-hint", children: "This field auto-computes from other fields. Signer cannot edit it." })
|
|
497
|
+
] }),
|
|
473
498
|
!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
499
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
475
500
|
"input",
|
|
@@ -481,7 +506,18 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
481
506
|
),
|
|
482
507
|
"Required"
|
|
483
508
|
] }) }),
|
|
484
|
-
|
|
509
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font" }),
|
|
511
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
512
|
+
"select",
|
|
513
|
+
{
|
|
514
|
+
value: field.fontFamily || "Helvetica",
|
|
515
|
+
onChange: (e) => onUpdate(field.id, { fontFamily: e.target.value }),
|
|
516
|
+
children: FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: f.value, children: f.label }, f.value))
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] }),
|
|
520
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
485
521
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font Size (pt)" }),
|
|
486
522
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
487
523
|
"input",
|
|
@@ -494,6 +530,49 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
494
530
|
}
|
|
495
531
|
)
|
|
496
532
|
] }),
|
|
533
|
+
isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field-row", children: [
|
|
534
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field panel-field-half", children: [
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Letter Spacing" }),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
537
|
+
"input",
|
|
538
|
+
{
|
|
539
|
+
type: "number",
|
|
540
|
+
min: "0",
|
|
541
|
+
max: "20",
|
|
542
|
+
step: "0.5",
|
|
543
|
+
value: field.letterSpacing || 0,
|
|
544
|
+
onChange: (e) => onUpdate(field.id, { letterSpacing: Number(e.target.value) })
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
] }),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field panel-field-half", children: [
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Line Height" }),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
551
|
+
"input",
|
|
552
|
+
{
|
|
553
|
+
type: "number",
|
|
554
|
+
min: "0.8",
|
|
555
|
+
max: "3",
|
|
556
|
+
step: "0.1",
|
|
557
|
+
value: field.lineHeight || 1.2,
|
|
558
|
+
onChange: (e) => onUpdate(field.id, { lineHeight: Number(e.target.value) })
|
|
559
|
+
}
|
|
560
|
+
)
|
|
561
|
+
] })
|
|
562
|
+
] }),
|
|
563
|
+
field.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Max Characters (0 = unlimited)" }),
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
566
|
+
"input",
|
|
567
|
+
{
|
|
568
|
+
type: "number",
|
|
569
|
+
min: "0",
|
|
570
|
+
max: "9999",
|
|
571
|
+
value: field.maxLength || 0,
|
|
572
|
+
onChange: (e) => onUpdate(field.id, { maxLength: Number(e.target.value) })
|
|
573
|
+
}
|
|
574
|
+
)
|
|
575
|
+
] }),
|
|
497
576
|
showInkColor && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
498
577
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Ink Color" }),
|
|
499
578
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ink-color-picker", children: INK_COLORS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -506,12 +585,61 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
|
|
|
506
585
|
},
|
|
507
586
|
c.value
|
|
508
587
|
)) })
|
|
588
|
+
] }),
|
|
589
|
+
field.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Predefined Options" }),
|
|
591
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-options-list", children: [
|
|
592
|
+
(field.options || []).map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-option-item", children: [
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: opt }),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
595
|
+
"button",
|
|
596
|
+
{
|
|
597
|
+
className: "panel-option-remove",
|
|
598
|
+
onClick: () => {
|
|
599
|
+
const updated = (field.options || []).filter((_, j) => j !== i);
|
|
600
|
+
onUpdate(field.id, { options: updated.length > 0 ? updated : void 0 });
|
|
601
|
+
},
|
|
602
|
+
children: "\xD7"
|
|
603
|
+
}
|
|
604
|
+
)
|
|
605
|
+
] }, i)),
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-option-add", children: [
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
608
|
+
"input",
|
|
609
|
+
{
|
|
610
|
+
type: "text",
|
|
611
|
+
value: newOption,
|
|
612
|
+
onChange: (e) => setNewOption(e.target.value),
|
|
613
|
+
onKeyDown: (e) => {
|
|
614
|
+
if (e.key === "Enter" && newOption.trim()) {
|
|
615
|
+
onUpdate(field.id, { options: [...field.options || [], newOption.trim()] });
|
|
616
|
+
setNewOption("");
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
placeholder: "Add option..."
|
|
620
|
+
}
|
|
621
|
+
),
|
|
622
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
623
|
+
"button",
|
|
624
|
+
{
|
|
625
|
+
onClick: () => {
|
|
626
|
+
if (newOption.trim()) {
|
|
627
|
+
onUpdate(field.id, { options: [...field.options || [], newOption.trim()] });
|
|
628
|
+
setNewOption("");
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
children: "+"
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
] })
|
|
635
|
+
] }),
|
|
636
|
+
(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
637
|
] })
|
|
510
638
|
] });
|
|
511
639
|
}
|
|
512
640
|
|
|
513
641
|
// src/components/pdf-builder/SignatureCanvas.tsx
|
|
514
|
-
var
|
|
642
|
+
var import_react3 = require("react");
|
|
515
643
|
var import_perfect_freehand = require("perfect-freehand");
|
|
516
644
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
517
645
|
function getSvgPathFromStroke(stroke) {
|
|
@@ -535,11 +663,11 @@ function SignatureCanvas({
|
|
|
535
663
|
className,
|
|
536
664
|
inkColor = "#000000"
|
|
537
665
|
}) {
|
|
538
|
-
const canvasRef = (0,
|
|
539
|
-
const [paths, setPaths] = (0,
|
|
540
|
-
const [currentPath, setCurrentPath] = (0,
|
|
541
|
-
const [isEmpty, setIsEmpty] = (0,
|
|
542
|
-
(0,
|
|
666
|
+
const canvasRef = (0, import_react3.useRef)(null);
|
|
667
|
+
const [paths, setPaths] = (0, import_react3.useState)([]);
|
|
668
|
+
const [currentPath, setCurrentPath] = (0, import_react3.useState)(null);
|
|
669
|
+
const [isEmpty, setIsEmpty] = (0, import_react3.useState)(!initialValue);
|
|
670
|
+
(0, import_react3.useEffect)(() => {
|
|
543
671
|
if (initialValue && canvasRef.current) {
|
|
544
672
|
const ctx = canvasRef.current.getContext("2d");
|
|
545
673
|
const img = new Image();
|
|
@@ -550,7 +678,7 @@ function SignatureCanvas({
|
|
|
550
678
|
img.src = initialValue;
|
|
551
679
|
}
|
|
552
680
|
}, [initialValue, width, height]);
|
|
553
|
-
(0,
|
|
681
|
+
(0, import_react3.useEffect)(() => {
|
|
554
682
|
const canvas = canvasRef.current;
|
|
555
683
|
if (!canvas) return;
|
|
556
684
|
const ctx = canvas.getContext("2d");
|
|
@@ -569,7 +697,7 @@ function SignatureCanvas({
|
|
|
569
697
|
ctx.fill(path2d);
|
|
570
698
|
}
|
|
571
699
|
}, [paths, currentPath, width, height]);
|
|
572
|
-
const getPoint = (0,
|
|
700
|
+
const getPoint = (0, import_react3.useCallback)((e) => {
|
|
573
701
|
const canvas = canvasRef.current;
|
|
574
702
|
const rect = canvas.getBoundingClientRect();
|
|
575
703
|
const style = getComputedStyle(canvas);
|
|
@@ -587,17 +715,17 @@ function SignatureCanvas({
|
|
|
587
715
|
e.pressure
|
|
588
716
|
];
|
|
589
717
|
}, []);
|
|
590
|
-
const handlePointerDown = (0,
|
|
718
|
+
const handlePointerDown = (0, import_react3.useCallback)((e) => {
|
|
591
719
|
e.preventDefault();
|
|
592
720
|
e.target.setPointerCapture(e.pointerId);
|
|
593
721
|
setCurrentPath([getPoint(e)]);
|
|
594
722
|
}, [getPoint]);
|
|
595
|
-
const handlePointerMove = (0,
|
|
723
|
+
const handlePointerMove = (0, import_react3.useCallback)((e) => {
|
|
596
724
|
if (!currentPath) return;
|
|
597
725
|
e.preventDefault();
|
|
598
726
|
setCurrentPath([...currentPath, getPoint(e)]);
|
|
599
727
|
}, [currentPath, getPoint]);
|
|
600
|
-
const handlePointerUp = (0,
|
|
728
|
+
const handlePointerUp = (0, import_react3.useCallback)(() => {
|
|
601
729
|
if (!currentPath) return;
|
|
602
730
|
setPaths((prev) => [...prev, currentPath]);
|
|
603
731
|
setCurrentPath(null);
|
|
@@ -608,7 +736,7 @@ function SignatureCanvas({
|
|
|
608
736
|
}
|
|
609
737
|
});
|
|
610
738
|
}, [currentPath, onSign]);
|
|
611
|
-
const handleClear = (0,
|
|
739
|
+
const handleClear = (0, import_react3.useCallback)(() => {
|
|
612
740
|
setPaths([]);
|
|
613
741
|
setCurrentPath(null);
|
|
614
742
|
setIsEmpty(true);
|
|
@@ -679,24 +807,24 @@ function DesignerView({
|
|
|
679
807
|
] })
|
|
680
808
|
] }) });
|
|
681
809
|
}
|
|
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,
|
|
810
|
+
const [pages, setPages] = (0, import_react4.useState)([]);
|
|
811
|
+
const [fields, setFields] = (0, import_react4.useState)(initialTemplate?.fields ?? []);
|
|
812
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react4.useState)(null);
|
|
813
|
+
const [signerRoles, setSignerRoles] = (0, import_react4.useState)(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
|
|
814
|
+
const [activeRole, setActiveRole] = (0, import_react4.useState)("Sender");
|
|
815
|
+
const [activeFieldType, setActiveFieldType] = (0, import_react4.useState)("text");
|
|
816
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
817
|
+
const [pdfSource, setPdfSource] = (0, import_react4.useState)(null);
|
|
818
|
+
const [rightTab, setRightTab] = (0, import_react4.useState)("properties");
|
|
819
|
+
const [isAddingRole, setIsAddingRole] = (0, import_react4.useState)(false);
|
|
820
|
+
const [newRoleName, setNewRoleName] = (0, import_react4.useState)("");
|
|
821
|
+
const [draggingFieldType, setDraggingFieldType] = (0, import_react4.useState)(null);
|
|
822
|
+
const [panelWidth, setPanelWidth] = (0, import_react4.useState)(380);
|
|
823
|
+
const [clipboardField, setClipboardField] = (0, import_react4.useState)(null);
|
|
824
|
+
const dragGhostRef = (0, import_react4.useRef)(null);
|
|
825
|
+
const resizingRef = (0, import_react4.useRef)(false);
|
|
826
|
+
const lastStylesRef = (0, import_react4.useRef)({});
|
|
827
|
+
(0, import_react4.useEffect)(() => {
|
|
700
828
|
const pdfUrl = initialPdfUrl || initialTemplate?.pdfUrl;
|
|
701
829
|
if (pdfUrl) {
|
|
702
830
|
loadPdf(pdfUrl);
|
|
@@ -720,7 +848,7 @@ function DesignerView({
|
|
|
720
848
|
window.addEventListener("message", handleMessage);
|
|
721
849
|
return () => window.removeEventListener("message", handleMessage);
|
|
722
850
|
}, [initialPdfUrl, initialTemplate]);
|
|
723
|
-
const loadPdf = (0,
|
|
851
|
+
const loadPdf = (0, import_react4.useCallback)(async (source) => {
|
|
724
852
|
setLoading(true);
|
|
725
853
|
try {
|
|
726
854
|
const rendered = await renderPdfPages(source);
|
|
@@ -732,7 +860,7 @@ function DesignerView({
|
|
|
732
860
|
setLoading(false);
|
|
733
861
|
}
|
|
734
862
|
}, []);
|
|
735
|
-
const handleFileUpload = (0,
|
|
863
|
+
const handleFileUpload = (0, import_react4.useCallback)((e) => {
|
|
736
864
|
const file = e.target.files?.[0];
|
|
737
865
|
if (!file) return;
|
|
738
866
|
const reader = new FileReader();
|
|
@@ -741,7 +869,7 @@ function DesignerView({
|
|
|
741
869
|
};
|
|
742
870
|
reader.readAsArrayBuffer(file);
|
|
743
871
|
}, [loadPdf]);
|
|
744
|
-
const handlePageClick = (0,
|
|
872
|
+
const handlePageClick = (0, import_react4.useCallback)((page, x, y) => {
|
|
745
873
|
const field = createField(activeFieldType, activeRole, page, x, y, fields);
|
|
746
874
|
const sticky = lastStylesRef.current[activeFieldType];
|
|
747
875
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
@@ -749,10 +877,10 @@ function DesignerView({
|
|
|
749
877
|
setSelectedFieldId(styledField.id);
|
|
750
878
|
setRightTab("properties");
|
|
751
879
|
}, [activeFieldType, activeRole, fields]);
|
|
752
|
-
const handleFieldMove = (0,
|
|
880
|
+
const handleFieldMove = (0, import_react4.useCallback)((id, page, x, y) => {
|
|
753
881
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, page, x, y } : f));
|
|
754
882
|
}, []);
|
|
755
|
-
const handleFieldResize = (0,
|
|
883
|
+
const handleFieldResize = (0, import_react4.useCallback)((id, width, height) => {
|
|
756
884
|
setFields((prev) => {
|
|
757
885
|
const field = prev.find((f) => f.id === id);
|
|
758
886
|
if (field) {
|
|
@@ -762,7 +890,7 @@ function DesignerView({
|
|
|
762
890
|
return prev.map((f) => f.id === id ? { ...f, width, height } : f);
|
|
763
891
|
});
|
|
764
892
|
}, []);
|
|
765
|
-
const handleFieldUpdate = (0,
|
|
893
|
+
const handleFieldUpdate = (0, import_react4.useCallback)((id, updates) => {
|
|
766
894
|
setFields((prev) => {
|
|
767
895
|
if (updates.label !== void 0) {
|
|
768
896
|
const otherLabels = prev.filter((f) => f.id !== id).map((f) => f.label);
|
|
@@ -782,11 +910,11 @@ function DesignerView({
|
|
|
782
910
|
return updated;
|
|
783
911
|
});
|
|
784
912
|
}, []);
|
|
785
|
-
const handleFieldDelete = (0,
|
|
913
|
+
const handleFieldDelete = (0, import_react4.useCallback)((id) => {
|
|
786
914
|
setFields((prev) => prev.filter((f) => f.id !== id));
|
|
787
915
|
if (selectedFieldId === id) setSelectedFieldId(null);
|
|
788
916
|
}, [selectedFieldId]);
|
|
789
|
-
const handleAddRole = (0,
|
|
917
|
+
const handleAddRole = (0, import_react4.useCallback)(() => {
|
|
790
918
|
const name = newRoleName.trim();
|
|
791
919
|
if (name && !signerRoles.includes(name)) {
|
|
792
920
|
setSignerRoles((prev) => [...prev, name]);
|
|
@@ -794,12 +922,12 @@ function DesignerView({
|
|
|
794
922
|
setNewRoleName("");
|
|
795
923
|
setIsAddingRole(false);
|
|
796
924
|
}, [newRoleName, signerRoles]);
|
|
797
|
-
const handleRemoveRole = (0,
|
|
925
|
+
const handleRemoveRole = (0, import_react4.useCallback)((role) => {
|
|
798
926
|
setSignerRoles((prev) => prev.filter((r) => r !== role));
|
|
799
927
|
setFields((prev) => prev.map((f) => f.assignee === role ? { ...f, assignee: signerRoles[0] } : f));
|
|
800
928
|
if (activeRole === role) setActiveRole(signerRoles[0]);
|
|
801
929
|
}, [signerRoles, activeRole]);
|
|
802
|
-
const handleExport = (0,
|
|
930
|
+
const handleExport = (0, import_react4.useCallback)(() => {
|
|
803
931
|
const template = {
|
|
804
932
|
fields,
|
|
805
933
|
signerRoles,
|
|
@@ -819,7 +947,7 @@ function DesignerView({
|
|
|
819
947
|
}
|
|
820
948
|
window.parent?.postMessage({ type: "template-saved", template }, "*");
|
|
821
949
|
}, [fields, signerRoles, pdfSource, onSave]);
|
|
822
|
-
const handlePaletteDragStart = (0,
|
|
950
|
+
const handlePaletteDragStart = (0, import_react4.useCallback)((e, type) => {
|
|
823
951
|
setDraggingFieldType(type);
|
|
824
952
|
e.dataTransfer.setData("application/exeq-field-type", type);
|
|
825
953
|
e.dataTransfer.effectAllowed = "copy";
|
|
@@ -836,14 +964,14 @@ function DesignerView({
|
|
|
836
964
|
e.dataTransfer.setDragImage(ghost, 40, 16);
|
|
837
965
|
dragGhostRef.current = ghost;
|
|
838
966
|
}, [activeRole]);
|
|
839
|
-
const handlePaletteDragEnd = (0,
|
|
967
|
+
const handlePaletteDragEnd = (0, import_react4.useCallback)(() => {
|
|
840
968
|
setDraggingFieldType(null);
|
|
841
969
|
if (dragGhostRef.current) {
|
|
842
970
|
document.body.removeChild(dragGhostRef.current);
|
|
843
971
|
dragGhostRef.current = null;
|
|
844
972
|
}
|
|
845
973
|
}, []);
|
|
846
|
-
const handleDropOnPage = (0,
|
|
974
|
+
const handleDropOnPage = (0, import_react4.useCallback)((page, x, y, fieldType) => {
|
|
847
975
|
const field = createField(fieldType, activeRole, page, x, y, fields);
|
|
848
976
|
const sticky = lastStylesRef.current[fieldType];
|
|
849
977
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
@@ -851,7 +979,7 @@ function DesignerView({
|
|
|
851
979
|
setSelectedFieldId(styledField.id);
|
|
852
980
|
setRightTab("properties");
|
|
853
981
|
}, [activeRole, fields]);
|
|
854
|
-
(0,
|
|
982
|
+
(0, import_react4.useEffect)(() => {
|
|
855
983
|
const handleKeyDown = (e) => {
|
|
856
984
|
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
857
985
|
if (!selectedFieldId) return;
|
|
@@ -866,7 +994,7 @@ function DesignerView({
|
|
|
866
994
|
window.addEventListener("keydown", handleKeyDown);
|
|
867
995
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
868
996
|
}, [selectedFieldId, handleFieldDelete]);
|
|
869
|
-
(0,
|
|
997
|
+
(0, import_react4.useEffect)(() => {
|
|
870
998
|
const handleKeyDown = (e) => {
|
|
871
999
|
const tag = (document.activeElement?.tagName || "").toLowerCase();
|
|
872
1000
|
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
@@ -898,7 +1026,7 @@ function DesignerView({
|
|
|
898
1026
|
window.addEventListener("keydown", handleKeyDown);
|
|
899
1027
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
900
1028
|
}, [selectedFieldId, fields, clipboardField]);
|
|
901
|
-
const handleResizeStart = (0,
|
|
1029
|
+
const handleResizeStart = (0, import_react4.useCallback)((e) => {
|
|
902
1030
|
e.preventDefault();
|
|
903
1031
|
resizingRef.current = true;
|
|
904
1032
|
const startX = e.clientX;
|
|
@@ -923,7 +1051,7 @@ function DesignerView({
|
|
|
923
1051
|
return a.x - b.x;
|
|
924
1052
|
});
|
|
925
1053
|
const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
|
|
926
|
-
const renderFieldContent = (0,
|
|
1054
|
+
const renderFieldContent = (0, import_react4.useCallback)((field) => {
|
|
927
1055
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
928
1056
|
return null;
|
|
929
1057
|
}
|
|
@@ -1160,10 +1288,15 @@ function DesignerView({
|
|
|
1160
1288
|
}
|
|
1161
1289
|
|
|
1162
1290
|
// src/components/pdf-builder/SignerView.tsx
|
|
1163
|
-
var
|
|
1291
|
+
var import_react6 = require("react");
|
|
1164
1292
|
|
|
1165
1293
|
// src/utils/pdfFiller.ts
|
|
1166
1294
|
var import_pdf_lib = require("pdf-lib");
|
|
1295
|
+
var FONT_MAP = {
|
|
1296
|
+
"Helvetica": import_pdf_lib.StandardFonts.Helvetica,
|
|
1297
|
+
"Courier": import_pdf_lib.StandardFonts.Courier,
|
|
1298
|
+
"TimesRoman": import_pdf_lib.StandardFonts.TimesRoman
|
|
1299
|
+
};
|
|
1167
1300
|
async function generateFilledPdf(pdfSource, fields) {
|
|
1168
1301
|
let pdfBytes;
|
|
1169
1302
|
if (typeof pdfSource === "string") {
|
|
@@ -1173,7 +1306,12 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
1173
1306
|
pdfBytes = pdfSource;
|
|
1174
1307
|
}
|
|
1175
1308
|
const pdfDoc = await import_pdf_lib.PDFDocument.load(pdfBytes);
|
|
1176
|
-
const
|
|
1309
|
+
const fontCache = /* @__PURE__ */ new Map();
|
|
1310
|
+
const usedFontKeys = new Set(fields.map((f) => f.fontFamily || "Helvetica"));
|
|
1311
|
+
for (const key of usedFontKeys) {
|
|
1312
|
+
const stdFont = FONT_MAP[key] || import_pdf_lib.StandardFonts.Helvetica;
|
|
1313
|
+
fontCache.set(key, await pdfDoc.embedFont(stdFont));
|
|
1314
|
+
}
|
|
1177
1315
|
const pages = pdfDoc.getPages();
|
|
1178
1316
|
function hexToRgb(hex) {
|
|
1179
1317
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
@@ -1234,21 +1372,35 @@ async function generateFilledPdf(pdfSource, fields) {
|
|
|
1234
1372
|
});
|
|
1235
1373
|
}
|
|
1236
1374
|
} else {
|
|
1375
|
+
const font = fontCache.get(field.fontFamily || "Helvetica");
|
|
1376
|
+
const spacing = field.letterSpacing || 0;
|
|
1377
|
+
const textWidthAtSize = (text, size) => {
|
|
1378
|
+
const baseWidth = font.widthOfTextAtSize(text, size);
|
|
1379
|
+
return baseWidth + spacing * (text.length - 1);
|
|
1380
|
+
};
|
|
1237
1381
|
const maxFontSize = Math.min(field.fontSize, h * 0.7);
|
|
1238
1382
|
let fontSize = maxFontSize;
|
|
1239
1383
|
const padding = 4;
|
|
1240
1384
|
while (fontSize > 4) {
|
|
1241
|
-
|
|
1242
|
-
if (textWidth <= w - padding) break;
|
|
1385
|
+
if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
|
|
1243
1386
|
fontSize -= 0.5;
|
|
1244
1387
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1388
|
+
if (spacing > 0) {
|
|
1389
|
+
let cx = x + 2;
|
|
1390
|
+
const cy = y + h * 0.3;
|
|
1391
|
+
for (const char of field.value) {
|
|
1392
|
+
page.drawText(char, { x: cx, y: cy, size: fontSize, font, color: inkColor });
|
|
1393
|
+
cx += font.widthOfTextAtSize(char, fontSize) + spacing;
|
|
1394
|
+
}
|
|
1395
|
+
} else {
|
|
1396
|
+
page.drawText(field.value, {
|
|
1397
|
+
x: x + 2,
|
|
1398
|
+
y: y + h * 0.3,
|
|
1399
|
+
size: fontSize,
|
|
1400
|
+
font,
|
|
1401
|
+
color: inkColor
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1252
1404
|
}
|
|
1253
1405
|
}
|
|
1254
1406
|
return pdfDoc.save();
|
|
@@ -1273,7 +1425,7 @@ async function postPdfToCallback(bytes, callbackUrl, filename) {
|
|
|
1273
1425
|
}
|
|
1274
1426
|
|
|
1275
1427
|
// src/components/pdf-builder/FieldNavigator.tsx
|
|
1276
|
-
var
|
|
1428
|
+
var import_react5 = require("react");
|
|
1277
1429
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1278
1430
|
function isFieldFilled(f) {
|
|
1279
1431
|
if (!f.required) return true;
|
|
@@ -1288,7 +1440,7 @@ function FieldNavigator({
|
|
|
1288
1440
|
onComplete,
|
|
1289
1441
|
completeLabel = "Complete"
|
|
1290
1442
|
}) {
|
|
1291
|
-
const [showIncomplete, setShowIncomplete] = (0,
|
|
1443
|
+
const [showIncomplete, setShowIncomplete] = (0, import_react5.useState)(false);
|
|
1292
1444
|
const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
|
|
1293
1445
|
const hasPrev = currentIndex > 0;
|
|
1294
1446
|
const hasNext = currentIndex < fields.length - 1;
|
|
@@ -1363,6 +1515,95 @@ function FieldNavigator({
|
|
|
1363
1515
|
] });
|
|
1364
1516
|
}
|
|
1365
1517
|
|
|
1518
|
+
// src/utils/formulaResolver.ts
|
|
1519
|
+
var BUILTIN_TRANSFORMS = {
|
|
1520
|
+
// Date transforms (expects a parseable date string)
|
|
1521
|
+
month: (v) => {
|
|
1522
|
+
const d = new Date(v);
|
|
1523
|
+
return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1);
|
|
1524
|
+
},
|
|
1525
|
+
month2: (v) => {
|
|
1526
|
+
const d = new Date(v);
|
|
1527
|
+
return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1).padStart(2, "0");
|
|
1528
|
+
},
|
|
1529
|
+
monthname: (v) => {
|
|
1530
|
+
const d = new Date(v);
|
|
1531
|
+
return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "long" });
|
|
1532
|
+
},
|
|
1533
|
+
monthshort: (v) => {
|
|
1534
|
+
const d = new Date(v);
|
|
1535
|
+
return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "short" });
|
|
1536
|
+
},
|
|
1537
|
+
day: (v) => {
|
|
1538
|
+
const d = new Date(v);
|
|
1539
|
+
return isNaN(d.getTime()) ? "" : String(d.getDate());
|
|
1540
|
+
},
|
|
1541
|
+
day2: (v) => {
|
|
1542
|
+
const d = new Date(v);
|
|
1543
|
+
return isNaN(d.getTime()) ? "" : String(d.getDate()).padStart(2, "0");
|
|
1544
|
+
},
|
|
1545
|
+
year: (v) => {
|
|
1546
|
+
const d = new Date(v);
|
|
1547
|
+
return isNaN(d.getTime()) ? "" : String(d.getFullYear());
|
|
1548
|
+
},
|
|
1549
|
+
year2: (v) => {
|
|
1550
|
+
const d = new Date(v);
|
|
1551
|
+
return isNaN(d.getTime()) ? "" : String(d.getFullYear()).slice(-2);
|
|
1552
|
+
},
|
|
1553
|
+
// String transforms
|
|
1554
|
+
upper: (v) => v.toUpperCase(),
|
|
1555
|
+
lower: (v) => v.toLowerCase(),
|
|
1556
|
+
trim: (v) => v.trim(),
|
|
1557
|
+
first: (v) => v.split(/\s+/)[0] || "",
|
|
1558
|
+
last: (v) => {
|
|
1559
|
+
const parts = v.split(/\s+/);
|
|
1560
|
+
return parts[parts.length - 1] || "";
|
|
1561
|
+
},
|
|
1562
|
+
initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
|
|
1563
|
+
// Numeric / substring
|
|
1564
|
+
last4: (v) => v.slice(-4),
|
|
1565
|
+
last2: (v) => v.slice(-2),
|
|
1566
|
+
first4: (v) => v.slice(0, 4),
|
|
1567
|
+
first2: (v) => v.slice(0, 2),
|
|
1568
|
+
digits: (v) => v.replace(/\D/g, ""),
|
|
1569
|
+
number: (v) => {
|
|
1570
|
+
const n = parseFloat(v);
|
|
1571
|
+
return isNaN(n) ? "" : String(n);
|
|
1572
|
+
},
|
|
1573
|
+
currency: (v) => {
|
|
1574
|
+
const n = parseFloat(v.replace(/[^0-9.-]/g, ""));
|
|
1575
|
+
return isNaN(n) ? "" : `$${n.toFixed(2)}`;
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
var FORMULA_RE = /\{\{(.+?)\}\}/g;
|
|
1579
|
+
var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
|
|
1580
|
+
function resolveFormula(formula, fields, customTransforms) {
|
|
1581
|
+
const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
|
|
1582
|
+
return formula.replace(FORMULA_RE, (_match, expr) => {
|
|
1583
|
+
const pipeMatch = expr.match(PIPE_RE);
|
|
1584
|
+
const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
|
|
1585
|
+
const transformName = pipeMatch ? pipeMatch[2].trim() : null;
|
|
1586
|
+
const sourceField = fields.find((f) => f.label.toLowerCase() === sourceLabel.toLowerCase()) || fields.find((f) => f.id === sourceLabel);
|
|
1587
|
+
if (!sourceField) return "";
|
|
1588
|
+
const rawValue = sourceField.value || "";
|
|
1589
|
+
if (!transformName) return rawValue;
|
|
1590
|
+
const fn = transforms[transformName];
|
|
1591
|
+
if (!fn) return rawValue;
|
|
1592
|
+
try {
|
|
1593
|
+
return fn(rawValue);
|
|
1594
|
+
} catch {
|
|
1595
|
+
return rawValue;
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
function resolveAllFormulas(fields, customTransforms) {
|
|
1600
|
+
return fields.map((f) => {
|
|
1601
|
+
if (!f.formula) return f;
|
|
1602
|
+
const computed = resolveFormula(f.formula, fields, customTransforms);
|
|
1603
|
+
return computed !== f.value ? { ...f, value: computed } : f;
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1366
1607
|
// src/components/pdf-builder/SignerView.tsx
|
|
1367
1608
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1368
1609
|
function SignerView({
|
|
@@ -1374,7 +1615,8 @@ function SignerView({
|
|
|
1374
1615
|
onComplete,
|
|
1375
1616
|
initialValues,
|
|
1376
1617
|
submitLabel,
|
|
1377
|
-
signerOrder: signerOrderProp
|
|
1618
|
+
signerOrder: signerOrderProp,
|
|
1619
|
+
transforms
|
|
1378
1620
|
} = {}) {
|
|
1379
1621
|
if (!isValidApiKey(apiKey)) {
|
|
1380
1622
|
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 +1628,43 @@ function SignerView({
|
|
|
1386
1628
|
] })
|
|
1387
1629
|
] }) });
|
|
1388
1630
|
}
|
|
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,
|
|
1631
|
+
const [pages, setPages] = (0, import_react6.useState)([]);
|
|
1632
|
+
const [fields, setFields] = (0, import_react6.useState)([]);
|
|
1633
|
+
const [selectedFieldId, setSelectedFieldId] = (0, import_react6.useState)(null);
|
|
1634
|
+
const [signerRoles, setSignerRoles] = (0, import_react6.useState)([]);
|
|
1635
|
+
const [currentSignerIndex, setCurrentSignerIndex] = (0, import_react6.useState)(() => {
|
|
1394
1636
|
if (initialSigner && signerOrderProp) {
|
|
1395
1637
|
const idx = signerOrderProp.indexOf(initialSigner);
|
|
1396
1638
|
return idx >= 0 ? idx : 0;
|
|
1397
1639
|
}
|
|
1398
1640
|
return 0;
|
|
1399
1641
|
});
|
|
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,
|
|
1642
|
+
const initializedRef = (0, import_react6.useRef)(false);
|
|
1643
|
+
const [loading, setLoading] = (0, import_react6.useState)(false);
|
|
1644
|
+
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
1645
|
+
const [pdfSource, setPdfSource] = (0, import_react6.useState)(null);
|
|
1646
|
+
const [callbackUrl, setCallbackUrl] = (0, import_react6.useState)(initialCallbackUrl || "");
|
|
1647
|
+
const containerRef = (0, import_react6.useRef)(null);
|
|
1406
1648
|
const signerOrder = signerOrderProp || (signerRoles.length > 0 ? [...signerRoles.filter((r) => r !== "Sender"), ...signerRoles.filter((r) => r === "Sender")] : [initialSigner || "Signer 1"]);
|
|
1407
1649
|
const signer = signerOrder[currentSignerIndex] || signerOrder[0] || "Signer 1";
|
|
1408
1650
|
const isLastSigner = currentSignerIndex >= signerOrder.length - 1;
|
|
1409
1651
|
const isMultiSigner = signerOrder.length > 1;
|
|
1410
|
-
(0,
|
|
1652
|
+
(0, import_react6.useEffect)(() => {
|
|
1653
|
+
if (fields.length === 0 || !isMultiSigner) return;
|
|
1654
|
+
const signerFields = fields.filter(
|
|
1655
|
+
(f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout"
|
|
1656
|
+
);
|
|
1657
|
+
const allFilled = signerFields.length > 0 && signerFields.every((f) => {
|
|
1658
|
+
if (!f.required) return true;
|
|
1659
|
+
if (f.type === "checkbox") return true;
|
|
1660
|
+
return !!f.value;
|
|
1661
|
+
});
|
|
1662
|
+
if (allFilled && !isLastSigner) {
|
|
1663
|
+
setCurrentSignerIndex((prev) => prev + 1);
|
|
1664
|
+
setSelectedFieldId(null);
|
|
1665
|
+
}
|
|
1666
|
+
}, [currentSignerIndex, fields, signer, isLastSigner, isMultiSigner]);
|
|
1667
|
+
(0, import_react6.useEffect)(() => {
|
|
1411
1668
|
if (initialTemplate) {
|
|
1412
1669
|
let templateFields = initialTemplate.fields;
|
|
1413
1670
|
if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
|
|
@@ -1477,7 +1734,7 @@ function SignerView({
|
|
|
1477
1734
|
window.addEventListener("message", handleMessage);
|
|
1478
1735
|
return () => window.removeEventListener("message", handleMessage);
|
|
1479
1736
|
}, [initialTemplate, initialPdfUrl]);
|
|
1480
|
-
const loadPdf = (0,
|
|
1737
|
+
const loadPdf = (0, import_react6.useCallback)(async (source) => {
|
|
1481
1738
|
setLoading(true);
|
|
1482
1739
|
try {
|
|
1483
1740
|
const rendered = await renderPdfPages(source);
|
|
@@ -1489,21 +1746,21 @@ function SignerView({
|
|
|
1489
1746
|
setLoading(false);
|
|
1490
1747
|
}
|
|
1491
1748
|
}, []);
|
|
1492
|
-
const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout").sort((a, b) => {
|
|
1749
|
+
const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout" && !f.formula).sort((a, b) => {
|
|
1493
1750
|
if (a.page !== b.page) return a.page - b.page;
|
|
1494
1751
|
const bandThreshold = 2;
|
|
1495
1752
|
if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
|
|
1496
1753
|
return a.x - b.x;
|
|
1497
1754
|
});
|
|
1498
1755
|
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,
|
|
1756
|
+
const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" && !selectedField.formula : false;
|
|
1757
|
+
const handleFieldUpdate = (0, import_react6.useCallback)((id, value) => {
|
|
1501
1758
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
|
|
1502
1759
|
}, []);
|
|
1503
|
-
const handleFieldPropertyUpdate = (0,
|
|
1760
|
+
const handleFieldPropertyUpdate = (0, import_react6.useCallback)((id, updates) => {
|
|
1504
1761
|
setFields((prev) => prev.map((f) => f.id === id ? { ...f, ...updates } : f));
|
|
1505
1762
|
}, []);
|
|
1506
|
-
const handleNavigate = (0,
|
|
1763
|
+
const handleNavigate = (0, import_react6.useCallback)((fieldId) => {
|
|
1507
1764
|
setSelectedFieldId(fieldId);
|
|
1508
1765
|
const field = fields.find((f) => f.id === fieldId);
|
|
1509
1766
|
if (field && containerRef.current) {
|
|
@@ -1518,7 +1775,7 @@ function SignerView({
|
|
|
1518
1775
|
if (f.type === "checkbox") return true;
|
|
1519
1776
|
return !!f.value;
|
|
1520
1777
|
});
|
|
1521
|
-
const handleAdvanceOrSubmit = (0,
|
|
1778
|
+
const handleAdvanceOrSubmit = (0, import_react6.useCallback)(async () => {
|
|
1522
1779
|
if (!allRequiredFilled) return;
|
|
1523
1780
|
if (!isLastSigner) {
|
|
1524
1781
|
setCurrentSignerIndex((prev) => prev + 1);
|
|
@@ -1532,7 +1789,8 @@ function SignerView({
|
|
|
1532
1789
|
if (!pdfSource) return;
|
|
1533
1790
|
setSubmitting(true);
|
|
1534
1791
|
try {
|
|
1535
|
-
const
|
|
1792
|
+
const finalFields = resolveAllFormulas(fields, transforms);
|
|
1793
|
+
const pdfBytes = await generateFilledPdf(pdfSource, finalFields);
|
|
1536
1794
|
const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
|
|
1537
1795
|
if (callbackUrl) {
|
|
1538
1796
|
await postPdfToCallback(pdfBytes, callbackUrl, "signed-document.pdf");
|
|
@@ -1550,10 +1808,13 @@ function SignerView({
|
|
|
1550
1808
|
setSubmitting(false);
|
|
1551
1809
|
}
|
|
1552
1810
|
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
|
|
1553
|
-
const renderFieldContent = (0,
|
|
1811
|
+
const renderFieldContent = (0, import_react6.useCallback)((field) => {
|
|
1554
1812
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1555
1813
|
return null;
|
|
1556
1814
|
}
|
|
1815
|
+
if (field.formula) {
|
|
1816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value formula", children: field.value || "..." });
|
|
1817
|
+
}
|
|
1557
1818
|
const editable = field.assignee === signer;
|
|
1558
1819
|
if (!editable) {
|
|
1559
1820
|
if (field.type === "signature" || field.type === "initials") {
|
|
@@ -1586,6 +1847,28 @@ function SignerView({
|
|
|
1586
1847
|
if (field.type === "signed-date") {
|
|
1587
1848
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value", children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
|
|
1588
1849
|
}
|
|
1850
|
+
const fontStyle = {
|
|
1851
|
+
fontSize: `${field.fontSize * 0.6}px`,
|
|
1852
|
+
letterSpacing: field.letterSpacing ? `${field.letterSpacing * 0.6}px` : void 0,
|
|
1853
|
+
fontFamily: field.fontFamily === "Courier" ? "monospace" : field.fontFamily === "TimesRoman" ? "serif" : void 0
|
|
1854
|
+
};
|
|
1855
|
+
if (field.options && field.options.length > 0) {
|
|
1856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1857
|
+
"select",
|
|
1858
|
+
{
|
|
1859
|
+
className: "field-inline-input",
|
|
1860
|
+
value: field.value,
|
|
1861
|
+
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
1862
|
+
onFocus: () => setSelectedFieldId(field.id),
|
|
1863
|
+
onClick: (e) => e.stopPropagation(),
|
|
1864
|
+
style: fontStyle,
|
|
1865
|
+
children: [
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: field.placeholder || "Select..." }),
|
|
1867
|
+
field.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: opt, children: opt }, opt))
|
|
1868
|
+
]
|
|
1869
|
+
}
|
|
1870
|
+
);
|
|
1871
|
+
}
|
|
1589
1872
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1590
1873
|
"input",
|
|
1591
1874
|
{
|
|
@@ -1593,14 +1876,15 @@ function SignerView({
|
|
|
1593
1876
|
className: "field-inline-input",
|
|
1594
1877
|
value: field.value,
|
|
1595
1878
|
placeholder: field.placeholder,
|
|
1879
|
+
maxLength: field.maxLength || void 0,
|
|
1596
1880
|
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
1597
1881
|
onFocus: () => setSelectedFieldId(field.id),
|
|
1598
1882
|
onClick: (e) => e.stopPropagation(),
|
|
1599
|
-
style:
|
|
1883
|
+
style: fontStyle
|
|
1600
1884
|
}
|
|
1601
1885
|
);
|
|
1602
1886
|
}, [signer, handleFieldUpdate, setSelectedFieldId]);
|
|
1603
|
-
(0,
|
|
1887
|
+
(0, import_react6.useEffect)(() => {
|
|
1604
1888
|
const sigFields = fields.filter((f) => f.assignee === signer && f.type === "signature" && f.value);
|
|
1605
1889
|
if (sigFields.length > 0) {
|
|
1606
1890
|
const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
@@ -1612,6 +1896,13 @@ function SignerView({
|
|
|
1612
1896
|
}));
|
|
1613
1897
|
}
|
|
1614
1898
|
}, [fields.filter((f) => f.type === "signature" && f.value).length]);
|
|
1899
|
+
(0, import_react6.useEffect)(() => {
|
|
1900
|
+
const hasFormulas = fields.some((f) => f.formula);
|
|
1901
|
+
if (!hasFormulas) return;
|
|
1902
|
+
const resolved = resolveAllFormulas(fields, transforms);
|
|
1903
|
+
const changed = resolved.some((f, i) => f.value !== fields[i].value);
|
|
1904
|
+
if (changed) setFields(resolved);
|
|
1905
|
+
}, [fields, transforms]);
|
|
1615
1906
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-layout", ref: containerRef, children: [
|
|
1616
1907
|
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Loading document..." }),
|
|
1617
1908
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-content", children: [
|
|
@@ -1654,13 +1945,25 @@ function SignerView({
|
|
|
1654
1945
|
}
|
|
1655
1946
|
),
|
|
1656
1947
|
selectedField.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1657
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.
|
|
1948
|
+
selectedField.options && selectedField.options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1949
|
+
"select",
|
|
1950
|
+
{
|
|
1951
|
+
value: selectedField.value,
|
|
1952
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
|
|
1953
|
+
className: "signer-text-input",
|
|
1954
|
+
children: [
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: selectedField.placeholder || "Select..." }),
|
|
1956
|
+
selectedField.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: opt, children: opt }, opt))
|
|
1957
|
+
]
|
|
1958
|
+
}
|
|
1959
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1658
1960
|
"input",
|
|
1659
1961
|
{
|
|
1660
1962
|
type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
|
|
1661
1963
|
value: selectedField.value,
|
|
1662
1964
|
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
|
|
1663
1965
|
placeholder: selectedField.placeholder,
|
|
1966
|
+
maxLength: selectedField.maxLength || void 0,
|
|
1664
1967
|
className: "signer-text-input"
|
|
1665
1968
|
}
|
|
1666
1969
|
),
|
|
@@ -1722,7 +2025,7 @@ function SignerView({
|
|
|
1722
2025
|
}
|
|
1723
2026
|
|
|
1724
2027
|
// src/components/pdf-builder/SignerRoleSelector.tsx
|
|
1725
|
-
var
|
|
2028
|
+
var import_react7 = require("react");
|
|
1726
2029
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1727
2030
|
function SignerRoleSelector({
|
|
1728
2031
|
roles,
|
|
@@ -1731,8 +2034,8 @@ function SignerRoleSelector({
|
|
|
1731
2034
|
onAddRole,
|
|
1732
2035
|
onRemoveRole
|
|
1733
2036
|
}) {
|
|
1734
|
-
const [isAdding, setIsAdding] = (0,
|
|
1735
|
-
const [newRoleName, setNewRoleName] = (0,
|
|
2037
|
+
const [isAdding, setIsAdding] = (0, import_react7.useState)(false);
|
|
2038
|
+
const [newRoleName, setNewRoleName] = (0, import_react7.useState)("");
|
|
1736
2039
|
const handleAdd = () => {
|
|
1737
2040
|
if (newRoleName.trim()) {
|
|
1738
2041
|
onAddRole(newRoleName.trim());
|
|
@@ -1797,9 +2100,11 @@ function SignerRoleSelector({
|
|
|
1797
2100
|
}
|
|
1798
2101
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1799
2102
|
0 && (module.exports = {
|
|
2103
|
+
BUILTIN_TRANSFORMS,
|
|
1800
2104
|
DEFAULT_SIGNER_ROLES,
|
|
1801
2105
|
DesignerView,
|
|
1802
2106
|
FIELD_DEFAULTS,
|
|
2107
|
+
FONT_FAMILIES,
|
|
1803
2108
|
FieldNavigator,
|
|
1804
2109
|
FieldPropertyPanel,
|
|
1805
2110
|
PdfViewer,
|
|
@@ -1810,9 +2115,12 @@ function SignerRoleSelector({
|
|
|
1810
2115
|
createField,
|
|
1811
2116
|
downloadPdf,
|
|
1812
2117
|
generateFilledPdf,
|
|
2118
|
+
generateId,
|
|
1813
2119
|
getSignerColor,
|
|
1814
2120
|
postPdfToCallback,
|
|
1815
2121
|
renderPdfPages,
|
|
2122
|
+
resolveAllFormulas,
|
|
2123
|
+
resolveFormula,
|
|
1816
2124
|
uniqueLabel
|
|
1817
2125
|
});
|
|
1818
2126
|
//# sourceMappingURL=index.js.map
|