@unlev/exeq 0.1.11 → 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/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,
@@ -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 showFontSize = field.type === "text" || field.type === "signed-date";
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
- showFontSize && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
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 import_react2 = require("react");
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, 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)(() => {
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, import_react2.useEffect)(() => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)((e) => {
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, import_react2.useCallback)(() => {
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, import_react2.useCallback)(() => {
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, 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)(() => {
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, import_react3.useCallback)(async (source) => {
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, import_react3.useCallback)((e) => {
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, import_react3.useCallback)((page, x, y) => {
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, import_react3.useCallback)((id, page, x, y) => {
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, import_react3.useCallback)((id, width, height) => {
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, import_react3.useCallback)((id, updates) => {
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, import_react3.useCallback)((id) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((role) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((e, type) => {
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, import_react3.useCallback)(() => {
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, import_react3.useCallback)((page, x, y, fieldType) => {
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, import_react3.useEffect)(() => {
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, import_react3.useEffect)(() => {
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, import_react3.useCallback)((e) => {
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, import_react3.useCallback)((field) => {
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 import_react4 = require("react");
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 font = await pdfDoc.embedFont(import_pdf_lib.StandardFonts.Helvetica);
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,15 +1372,35 @@ async function generateFilledPdf(pdfSource, fields) {
1234
1372
  });
1235
1373
  }
1236
1374
  } else {
1237
- const fontSize = Math.min(field.fontSize, h * 0.7);
1238
- page.drawText(field.value, {
1239
- x: x + 2,
1240
- y: y + h * 0.3,
1241
- size: fontSize,
1242
- font,
1243
- color: inkColor,
1244
- maxWidth: w - 4
1245
- });
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
+ };
1381
+ const maxFontSize = Math.min(field.fontSize, h * 0.7);
1382
+ let fontSize = maxFontSize;
1383
+ const padding = 4;
1384
+ while (fontSize > 4) {
1385
+ if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
1386
+ fontSize -= 0.5;
1387
+ }
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
+ }
1246
1404
  }
1247
1405
  }
1248
1406
  return pdfDoc.save();
@@ -1267,7 +1425,13 @@ async function postPdfToCallback(bytes, callbackUrl, filename) {
1267
1425
  }
1268
1426
 
1269
1427
  // src/components/pdf-builder/FieldNavigator.tsx
1428
+ var import_react5 = require("react");
1270
1429
  var import_jsx_runtime5 = require("react/jsx-runtime");
1430
+ function isFieldFilled(f) {
1431
+ if (!f.required) return true;
1432
+ if (f.type === "checkbox") return true;
1433
+ return !!f.value;
1434
+ }
1271
1435
  function FieldNavigator({
1272
1436
  fields,
1273
1437
  currentFieldId,
@@ -1276,6 +1440,7 @@ function FieldNavigator({
1276
1440
  onComplete,
1277
1441
  completeLabel = "Complete"
1278
1442
  }) {
1443
+ const [showIncomplete, setShowIncomplete] = (0, import_react5.useState)(false);
1279
1444
  const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
1280
1445
  const hasPrev = currentIndex > 0;
1281
1446
  const hasNext = currentIndex < fields.length - 1;
@@ -1289,19 +1454,36 @@ function FieldNavigator({
1289
1454
  onNavigate(fields[currentIndex + 1].id);
1290
1455
  }
1291
1456
  };
1292
- const filledCount = fields.filter((f) => {
1293
- if (!f.required) return true;
1294
- if (f.type === "checkbox") return true;
1295
- return !!f.value;
1296
- }).length;
1457
+ const filledCount = fields.filter(isFieldFilled).length;
1458
+ const incompleteFields = fields.filter((f) => !isFieldFilled(f));
1297
1459
  const showCompleteAsNext = !hasNext && allRequiredFilled;
1298
1460
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator", children: [
1299
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator-progress", children: [
1300
- filledCount,
1301
- " of ",
1302
- fields.length,
1303
- " fields completed"
1304
- ] }),
1461
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1462
+ "div",
1463
+ {
1464
+ className: `field-navigator-progress ${incompleteFields.length > 0 ? "clickable" : ""}`,
1465
+ onClick: () => incompleteFields.length > 0 && setShowIncomplete(!showIncomplete),
1466
+ children: [
1467
+ filledCount,
1468
+ " of ",
1469
+ fields.length,
1470
+ " fields completed",
1471
+ incompleteFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "field-navigator-toggle", children: showIncomplete ? "\u25B2" : "\u25BC" })
1472
+ ]
1473
+ }
1474
+ ),
1475
+ showIncomplete && incompleteFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "incomplete-fields-list", children: incompleteFields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1476
+ "button",
1477
+ {
1478
+ className: "incomplete-field-item",
1479
+ onClick: () => {
1480
+ onNavigate(f.id);
1481
+ setShowIncomplete(false);
1482
+ },
1483
+ children: f.label
1484
+ },
1485
+ f.id
1486
+ )) }),
1305
1487
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "field-navigator-controls", children: [
1306
1488
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1307
1489
  "button",
@@ -1333,6 +1515,95 @@ function FieldNavigator({
1333
1515
  ] });
1334
1516
  }
1335
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
+
1336
1607
  // src/components/pdf-builder/SignerView.tsx
1337
1608
  var import_jsx_runtime6 = require("react/jsx-runtime");
1338
1609
  function SignerView({
@@ -1344,7 +1615,8 @@ function SignerView({
1344
1615
  onComplete,
1345
1616
  initialValues,
1346
1617
  submitLabel,
1347
- signerOrder: signerOrderProp
1618
+ signerOrder: signerOrderProp,
1619
+ transforms
1348
1620
  } = {}) {
1349
1621
  if (!isValidApiKey(apiKey)) {
1350
1622
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-layout", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "empty-state", children: [
@@ -1356,28 +1628,43 @@ function SignerView({
1356
1628
  ] })
1357
1629
  ] }) });
1358
1630
  }
1359
- const [pages, setPages] = (0, import_react4.useState)([]);
1360
- const [fields, setFields] = (0, import_react4.useState)([]);
1361
- const [selectedFieldId, setSelectedFieldId] = (0, import_react4.useState)(null);
1362
- const [signerRoles, setSignerRoles] = (0, import_react4.useState)([]);
1363
- const [currentSignerIndex, setCurrentSignerIndex] = (0, import_react4.useState)(() => {
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)(() => {
1364
1636
  if (initialSigner && signerOrderProp) {
1365
1637
  const idx = signerOrderProp.indexOf(initialSigner);
1366
1638
  return idx >= 0 ? idx : 0;
1367
1639
  }
1368
1640
  return 0;
1369
1641
  });
1370
- const initializedRef = (0, import_react4.useRef)(false);
1371
- const [loading, setLoading] = (0, import_react4.useState)(false);
1372
- const [submitting, setSubmitting] = (0, import_react4.useState)(false);
1373
- const [pdfSource, setPdfSource] = (0, import_react4.useState)(null);
1374
- const [callbackUrl, setCallbackUrl] = (0, import_react4.useState)(initialCallbackUrl || "");
1375
- const containerRef = (0, import_react4.useRef)(null);
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);
1376
1648
  const signerOrder = signerOrderProp || (signerRoles.length > 0 ? [...signerRoles.filter((r) => r !== "Sender"), ...signerRoles.filter((r) => r === "Sender")] : [initialSigner || "Signer 1"]);
1377
1649
  const signer = signerOrder[currentSignerIndex] || signerOrder[0] || "Signer 1";
1378
1650
  const isLastSigner = currentSignerIndex >= signerOrder.length - 1;
1379
1651
  const isMultiSigner = signerOrder.length > 1;
1380
- (0, import_react4.useEffect)(() => {
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)(() => {
1381
1668
  if (initialTemplate) {
1382
1669
  let templateFields = initialTemplate.fields;
1383
1670
  if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
@@ -1447,7 +1734,7 @@ function SignerView({
1447
1734
  window.addEventListener("message", handleMessage);
1448
1735
  return () => window.removeEventListener("message", handleMessage);
1449
1736
  }, [initialTemplate, initialPdfUrl]);
1450
- const loadPdf = (0, import_react4.useCallback)(async (source) => {
1737
+ const loadPdf = (0, import_react6.useCallback)(async (source) => {
1451
1738
  setLoading(true);
1452
1739
  try {
1453
1740
  const rendered = await renderPdfPages(source);
@@ -1459,21 +1746,21 @@ function SignerView({
1459
1746
  setLoading(false);
1460
1747
  }
1461
1748
  }, []);
1462
- 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) => {
1463
1750
  if (a.page !== b.page) return a.page - b.page;
1464
1751
  const bandThreshold = 2;
1465
1752
  if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
1466
1753
  return a.x - b.x;
1467
1754
  });
1468
1755
  const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
1469
- const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" : false;
1470
- const handleFieldUpdate = (0, import_react4.useCallback)((id, value) => {
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) => {
1471
1758
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
1472
1759
  }, []);
1473
- const handleFieldPropertyUpdate = (0, import_react4.useCallback)((id, updates) => {
1760
+ const handleFieldPropertyUpdate = (0, import_react6.useCallback)((id, updates) => {
1474
1761
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, ...updates } : f));
1475
1762
  }, []);
1476
- const handleNavigate = (0, import_react4.useCallback)((fieldId) => {
1763
+ const handleNavigate = (0, import_react6.useCallback)((fieldId) => {
1477
1764
  setSelectedFieldId(fieldId);
1478
1765
  const field = fields.find((f) => f.id === fieldId);
1479
1766
  if (field && containerRef.current) {
@@ -1488,7 +1775,7 @@ function SignerView({
1488
1775
  if (f.type === "checkbox") return true;
1489
1776
  return !!f.value;
1490
1777
  });
1491
- const handleAdvanceOrSubmit = (0, import_react4.useCallback)(async () => {
1778
+ const handleAdvanceOrSubmit = (0, import_react6.useCallback)(async () => {
1492
1779
  if (!allRequiredFilled) return;
1493
1780
  if (!isLastSigner) {
1494
1781
  setCurrentSignerIndex((prev) => prev + 1);
@@ -1502,7 +1789,8 @@ function SignerView({
1502
1789
  if (!pdfSource) return;
1503
1790
  setSubmitting(true);
1504
1791
  try {
1505
- const pdfBytes = await generateFilledPdf(pdfSource, fields);
1792
+ const finalFields = resolveAllFormulas(fields, transforms);
1793
+ const pdfBytes = await generateFilledPdf(pdfSource, finalFields);
1506
1794
  const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
1507
1795
  if (callbackUrl) {
1508
1796
  await postPdfToCallback(pdfBytes, callbackUrl, "signed-document.pdf");
@@ -1520,10 +1808,13 @@ function SignerView({
1520
1808
  setSubmitting(false);
1521
1809
  }
1522
1810
  }, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
1523
- const renderFieldContent = (0, import_react4.useCallback)((field) => {
1811
+ const renderFieldContent = (0, import_react6.useCallback)((field) => {
1524
1812
  if (field.type === "blackout" || field.type === "whiteout") {
1525
1813
  return null;
1526
1814
  }
1815
+ if (field.formula) {
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value formula", children: field.value || "..." });
1817
+ }
1527
1818
  const editable = field.assignee === signer;
1528
1819
  if (!editable) {
1529
1820
  if (field.type === "signature" || field.type === "initials") {
@@ -1556,6 +1847,28 @@ function SignerView({
1556
1847
  if (field.type === "signed-date") {
1557
1848
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value", children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
1558
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
+ }
1559
1872
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1560
1873
  "input",
1561
1874
  {
@@ -1563,14 +1876,15 @@ function SignerView({
1563
1876
  className: "field-inline-input",
1564
1877
  value: field.value,
1565
1878
  placeholder: field.placeholder,
1879
+ maxLength: field.maxLength || void 0,
1566
1880
  onChange: (e) => handleFieldUpdate(field.id, e.target.value),
1567
1881
  onFocus: () => setSelectedFieldId(field.id),
1568
1882
  onClick: (e) => e.stopPropagation(),
1569
- style: { fontSize: `${field.fontSize * 0.6}px` }
1883
+ style: fontStyle
1570
1884
  }
1571
1885
  );
1572
1886
  }, [signer, handleFieldUpdate, setSelectedFieldId]);
1573
- (0, import_react4.useEffect)(() => {
1887
+ (0, import_react6.useEffect)(() => {
1574
1888
  const sigFields = fields.filter((f) => f.assignee === signer && f.type === "signature" && f.value);
1575
1889
  if (sigFields.length > 0) {
1576
1890
  const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString();
@@ -1582,6 +1896,13 @@ function SignerView({
1582
1896
  }));
1583
1897
  }
1584
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]);
1585
1906
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-layout", ref: containerRef, children: [
1586
1907
  loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Loading document..." }),
1587
1908
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-content", children: [
@@ -1624,13 +1945,25 @@ function SignerView({
1624
1945
  }
1625
1946
  ),
1626
1947
  selectedField.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1627
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
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)(
1628
1960
  "input",
1629
1961
  {
1630
1962
  type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
1631
1963
  value: selectedField.value,
1632
1964
  onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
1633
1965
  placeholder: selectedField.placeholder,
1966
+ maxLength: selectedField.maxLength || void 0,
1634
1967
  className: "signer-text-input"
1635
1968
  }
1636
1969
  ),
@@ -1692,7 +2025,7 @@ function SignerView({
1692
2025
  }
1693
2026
 
1694
2027
  // src/components/pdf-builder/SignerRoleSelector.tsx
1695
- var import_react5 = require("react");
2028
+ var import_react7 = require("react");
1696
2029
  var import_jsx_runtime7 = require("react/jsx-runtime");
1697
2030
  function SignerRoleSelector({
1698
2031
  roles,
@@ -1701,8 +2034,8 @@ function SignerRoleSelector({
1701
2034
  onAddRole,
1702
2035
  onRemoveRole
1703
2036
  }) {
1704
- const [isAdding, setIsAdding] = (0, import_react5.useState)(false);
1705
- const [newRoleName, setNewRoleName] = (0, import_react5.useState)("");
2037
+ const [isAdding, setIsAdding] = (0, import_react7.useState)(false);
2038
+ const [newRoleName, setNewRoleName] = (0, import_react7.useState)("");
1706
2039
  const handleAdd = () => {
1707
2040
  if (newRoleName.trim()) {
1708
2041
  onAddRole(newRoleName.trim());
@@ -1767,9 +2100,11 @@ function SignerRoleSelector({
1767
2100
  }
1768
2101
  // Annotate the CommonJS export names for ESM import in node:
1769
2102
  0 && (module.exports = {
2103
+ BUILTIN_TRANSFORMS,
1770
2104
  DEFAULT_SIGNER_ROLES,
1771
2105
  DesignerView,
1772
2106
  FIELD_DEFAULTS,
2107
+ FONT_FAMILIES,
1773
2108
  FieldNavigator,
1774
2109
  FieldPropertyPanel,
1775
2110
  PdfViewer,
@@ -1780,9 +2115,12 @@ function SignerRoleSelector({
1780
2115
  createField,
1781
2116
  downloadPdf,
1782
2117
  generateFilledPdf,
2118
+ generateId,
1783
2119
  getSignerColor,
1784
2120
  postPdfToCallback,
1785
2121
  renderPdfPages,
2122
+ resolveAllFormulas,
2123
+ resolveFormula,
1786
2124
  uniqueLabel
1787
2125
  });
1788
2126
  //# sourceMappingURL=index.js.map