@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/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 import_react3 = require("react");
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 showFontSize = field.type === "text" || field.type === "signed-date";
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
- showFontSize && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
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 import_react2 = require("react");
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, import_react2.useRef)(null);
539
- const [paths, setPaths] = (0, import_react2.useState)([]);
540
- const [currentPath, setCurrentPath] = (0, import_react2.useState)(null);
541
- const [isEmpty, setIsEmpty] = (0, import_react2.useState)(!initialValue);
542
- (0, import_react2.useEffect)(() => {
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, import_react2.useEffect)(() => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)(() => {
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, import_react2.useCallback)(() => {
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, import_react3.useState)([]);
683
- const [fields, setFields] = (0, import_react3.useState)(initialTemplate?.fields ?? []);
684
- const [selectedFieldId, setSelectedFieldId] = (0, import_react3.useState)(null);
685
- const [signerRoles, setSignerRoles] = (0, import_react3.useState)(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
686
- const [activeRole, setActiveRole] = (0, import_react3.useState)("Sender");
687
- const [activeFieldType, setActiveFieldType] = (0, import_react3.useState)("text");
688
- const [loading, setLoading] = (0, import_react3.useState)(false);
689
- const [pdfSource, setPdfSource] = (0, import_react3.useState)(null);
690
- const [rightTab, setRightTab] = (0, import_react3.useState)("properties");
691
- const [isAddingRole, setIsAddingRole] = (0, import_react3.useState)(false);
692
- const [newRoleName, setNewRoleName] = (0, import_react3.useState)("");
693
- const [draggingFieldType, setDraggingFieldType] = (0, import_react3.useState)(null);
694
- const [panelWidth, setPanelWidth] = (0, import_react3.useState)(380);
695
- const [clipboardField, setClipboardField] = (0, import_react3.useState)(null);
696
- const dragGhostRef = (0, import_react3.useRef)(null);
697
- const resizingRef = (0, import_react3.useRef)(false);
698
- const lastStylesRef = (0, import_react3.useRef)({});
699
- (0, import_react3.useEffect)(() => {
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, import_react3.useCallback)(async (source) => {
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, import_react3.useCallback)((e) => {
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, import_react3.useCallback)((page, x, y) => {
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, import_react3.useCallback)((id, page, x, y) => {
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, import_react3.useCallback)((id, width, height) => {
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, import_react3.useCallback)((id, updates) => {
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, import_react3.useCallback)((id) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((role) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((e, type) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((page, x, y, fieldType) => {
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, import_react3.useEffect)(() => {
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, import_react3.useEffect)(() => {
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, import_react3.useCallback)((e) => {
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, import_react3.useCallback)((field) => {
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: { color: field.value ? inkColor : void 0, fontSize: `${field.fontSize * 0.6}px` },
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 import_react5 = require("react");
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 font = await pdfDoc.embedFont(import_pdf_lib.StandardFonts.Helvetica);
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
- const textWidth = font.widthOfTextAtSize(field.value, fontSize);
1242
- if (textWidth <= w - padding) break;
1402
+ if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
1243
1403
  fontSize -= 0.5;
1244
1404
  }
1245
- page.drawText(field.value, {
1246
- x: x + 2,
1247
- y: y + h * 0.3,
1248
- size: fontSize,
1249
- font,
1250
- color: inkColor
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 import_react4 = require("react");
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, import_react4.useState)(false);
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, import_react5.useState)([]);
1390
- const [fields, setFields] = (0, import_react5.useState)([]);
1391
- const [selectedFieldId, setSelectedFieldId] = (0, import_react5.useState)(null);
1392
- const [signerRoles, setSignerRoles] = (0, import_react5.useState)([]);
1393
- const [currentSignerIndex, setCurrentSignerIndex] = (0, import_react5.useState)(() => {
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, import_react5.useRef)(false);
1401
- const [loading, setLoading] = (0, import_react5.useState)(false);
1402
- const [submitting, setSubmitting] = (0, import_react5.useState)(false);
1403
- const [pdfSource, setPdfSource] = (0, import_react5.useState)(null);
1404
- const [callbackUrl, setCallbackUrl] = (0, import_react5.useState)(initialCallbackUrl || "");
1405
- const containerRef = (0, import_react5.useRef)(null);
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, import_react5.useEffect)(() => {
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, import_react5.useCallback)(async (source) => {
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, import_react5.useCallback)((id, value) => {
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, import_react5.useCallback)((id, updates) => {
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, import_react5.useCallback)((fieldId) => {
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, import_react5.useCallback)(async () => {
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 pdfBytes = await generateFilledPdf(pdfSource, fields);
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, import_react5.useCallback)((field) => {
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: { fontSize: `${field.fontSize * 0.6}px` }
1901
+ style: fontStyle
1600
1902
  }
1601
1903
  );
1602
1904
  }, [signer, handleFieldUpdate, setSelectedFieldId]);
1603
- (0, import_react5.useEffect)(() => {
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.jsx)(
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 import_react6 = require("react");
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, import_react6.useState)(false);
1735
- const [newRoleName, setNewRoleName] = (0, import_react6.useState)("");
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