@unlev/exeq 0.1.12 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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_react5 = 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,21 +1372,35 @@ async function generateFilledPdf(pdfSource, fields) {
1234
1372
  });
1235
1373
  }
1236
1374
  } else {
1375
+ const font = fontCache.get(field.fontFamily || "Helvetica");
1376
+ const spacing = field.letterSpacing || 0;
1377
+ const textWidthAtSize = (text, size) => {
1378
+ const baseWidth = font.widthOfTextAtSize(text, size);
1379
+ return baseWidth + spacing * (text.length - 1);
1380
+ };
1237
1381
  const maxFontSize = Math.min(field.fontSize, h * 0.7);
1238
1382
  let fontSize = maxFontSize;
1239
1383
  const padding = 4;
1240
1384
  while (fontSize > 4) {
1241
- const textWidth = font.widthOfTextAtSize(field.value, fontSize);
1242
- if (textWidth <= w - padding) break;
1385
+ if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
1243
1386
  fontSize -= 0.5;
1244
1387
  }
1245
- page.drawText(field.value, {
1246
- x: x + 2,
1247
- y: y + h * 0.3,
1248
- size: fontSize,
1249
- font,
1250
- color: inkColor
1251
- });
1388
+ if (spacing > 0) {
1389
+ let cx = x + 2;
1390
+ const cy = y + h * 0.3;
1391
+ for (const char of field.value) {
1392
+ page.drawText(char, { x: cx, y: cy, size: fontSize, font, color: inkColor });
1393
+ cx += font.widthOfTextAtSize(char, fontSize) + spacing;
1394
+ }
1395
+ } else {
1396
+ page.drawText(field.value, {
1397
+ x: x + 2,
1398
+ y: y + h * 0.3,
1399
+ size: fontSize,
1400
+ font,
1401
+ color: inkColor
1402
+ });
1403
+ }
1252
1404
  }
1253
1405
  }
1254
1406
  return pdfDoc.save();
@@ -1273,7 +1425,7 @@ async function postPdfToCallback(bytes, callbackUrl, filename) {
1273
1425
  }
1274
1426
 
1275
1427
  // src/components/pdf-builder/FieldNavigator.tsx
1276
- var import_react4 = require("react");
1428
+ var import_react5 = require("react");
1277
1429
  var import_jsx_runtime5 = require("react/jsx-runtime");
1278
1430
  function isFieldFilled(f) {
1279
1431
  if (!f.required) return true;
@@ -1288,7 +1440,7 @@ function FieldNavigator({
1288
1440
  onComplete,
1289
1441
  completeLabel = "Complete"
1290
1442
  }) {
1291
- const [showIncomplete, setShowIncomplete] = (0, import_react4.useState)(false);
1443
+ const [showIncomplete, setShowIncomplete] = (0, import_react5.useState)(false);
1292
1444
  const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
1293
1445
  const hasPrev = currentIndex > 0;
1294
1446
  const hasNext = currentIndex < fields.length - 1;
@@ -1363,6 +1515,95 @@ function FieldNavigator({
1363
1515
  ] });
1364
1516
  }
1365
1517
 
1518
+ // src/utils/formulaResolver.ts
1519
+ var BUILTIN_TRANSFORMS = {
1520
+ // Date transforms (expects a parseable date string)
1521
+ month: (v) => {
1522
+ const d = new Date(v);
1523
+ return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1);
1524
+ },
1525
+ month2: (v) => {
1526
+ const d = new Date(v);
1527
+ return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1).padStart(2, "0");
1528
+ },
1529
+ monthname: (v) => {
1530
+ const d = new Date(v);
1531
+ return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "long" });
1532
+ },
1533
+ monthshort: (v) => {
1534
+ const d = new Date(v);
1535
+ return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "short" });
1536
+ },
1537
+ day: (v) => {
1538
+ const d = new Date(v);
1539
+ return isNaN(d.getTime()) ? "" : String(d.getDate());
1540
+ },
1541
+ day2: (v) => {
1542
+ const d = new Date(v);
1543
+ return isNaN(d.getTime()) ? "" : String(d.getDate()).padStart(2, "0");
1544
+ },
1545
+ year: (v) => {
1546
+ const d = new Date(v);
1547
+ return isNaN(d.getTime()) ? "" : String(d.getFullYear());
1548
+ },
1549
+ year2: (v) => {
1550
+ const d = new Date(v);
1551
+ return isNaN(d.getTime()) ? "" : String(d.getFullYear()).slice(-2);
1552
+ },
1553
+ // String transforms
1554
+ upper: (v) => v.toUpperCase(),
1555
+ lower: (v) => v.toLowerCase(),
1556
+ trim: (v) => v.trim(),
1557
+ first: (v) => v.split(/\s+/)[0] || "",
1558
+ last: (v) => {
1559
+ const parts = v.split(/\s+/);
1560
+ return parts[parts.length - 1] || "";
1561
+ },
1562
+ initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
1563
+ // Numeric / substring
1564
+ last4: (v) => v.slice(-4),
1565
+ last2: (v) => v.slice(-2),
1566
+ first4: (v) => v.slice(0, 4),
1567
+ first2: (v) => v.slice(0, 2),
1568
+ digits: (v) => v.replace(/\D/g, ""),
1569
+ number: (v) => {
1570
+ const n = parseFloat(v);
1571
+ return isNaN(n) ? "" : String(n);
1572
+ },
1573
+ currency: (v) => {
1574
+ const n = parseFloat(v.replace(/[^0-9.-]/g, ""));
1575
+ return isNaN(n) ? "" : `$${n.toFixed(2)}`;
1576
+ }
1577
+ };
1578
+ var FORMULA_RE = /\{\{(.+?)\}\}/g;
1579
+ var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
1580
+ function resolveFormula(formula, fields, customTransforms) {
1581
+ const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
1582
+ return formula.replace(FORMULA_RE, (_match, expr) => {
1583
+ const pipeMatch = expr.match(PIPE_RE);
1584
+ const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
1585
+ const transformName = pipeMatch ? pipeMatch[2].trim() : null;
1586
+ const sourceField = fields.find((f) => f.label.toLowerCase() === sourceLabel.toLowerCase()) || fields.find((f) => f.id === sourceLabel);
1587
+ if (!sourceField) return "";
1588
+ const rawValue = sourceField.value || "";
1589
+ if (!transformName) return rawValue;
1590
+ const fn = transforms[transformName];
1591
+ if (!fn) return rawValue;
1592
+ try {
1593
+ return fn(rawValue);
1594
+ } catch {
1595
+ return rawValue;
1596
+ }
1597
+ });
1598
+ }
1599
+ function resolveAllFormulas(fields, customTransforms) {
1600
+ return fields.map((f) => {
1601
+ if (!f.formula) return f;
1602
+ const computed = resolveFormula(f.formula, fields, customTransforms);
1603
+ return computed !== f.value ? { ...f, value: computed } : f;
1604
+ });
1605
+ }
1606
+
1366
1607
  // src/components/pdf-builder/SignerView.tsx
1367
1608
  var import_jsx_runtime6 = require("react/jsx-runtime");
1368
1609
  function SignerView({
@@ -1374,7 +1615,8 @@ function SignerView({
1374
1615
  onComplete,
1375
1616
  initialValues,
1376
1617
  submitLabel,
1377
- signerOrder: signerOrderProp
1618
+ signerOrder: signerOrderProp,
1619
+ transforms
1378
1620
  } = {}) {
1379
1621
  if (!isValidApiKey(apiKey)) {
1380
1622
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "signer-layout", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "empty-state", children: [
@@ -1386,28 +1628,43 @@ function SignerView({
1386
1628
  ] })
1387
1629
  ] }) });
1388
1630
  }
1389
- const [pages, setPages] = (0, 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)(() => {
1631
+ const [pages, setPages] = (0, import_react6.useState)([]);
1632
+ const [fields, setFields] = (0, import_react6.useState)([]);
1633
+ const [selectedFieldId, setSelectedFieldId] = (0, import_react6.useState)(null);
1634
+ const [signerRoles, setSignerRoles] = (0, import_react6.useState)([]);
1635
+ const [currentSignerIndex, setCurrentSignerIndex] = (0, import_react6.useState)(() => {
1394
1636
  if (initialSigner && signerOrderProp) {
1395
1637
  const idx = signerOrderProp.indexOf(initialSigner);
1396
1638
  return idx >= 0 ? idx : 0;
1397
1639
  }
1398
1640
  return 0;
1399
1641
  });
1400
- const initializedRef = (0, 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);
1642
+ const initializedRef = (0, import_react6.useRef)(false);
1643
+ const [loading, setLoading] = (0, import_react6.useState)(false);
1644
+ const [submitting, setSubmitting] = (0, import_react6.useState)(false);
1645
+ const [pdfSource, setPdfSource] = (0, import_react6.useState)(null);
1646
+ const [callbackUrl, setCallbackUrl] = (0, import_react6.useState)(initialCallbackUrl || "");
1647
+ const containerRef = (0, import_react6.useRef)(null);
1406
1648
  const signerOrder = signerOrderProp || (signerRoles.length > 0 ? [...signerRoles.filter((r) => r !== "Sender"), ...signerRoles.filter((r) => r === "Sender")] : [initialSigner || "Signer 1"]);
1407
1649
  const signer = signerOrder[currentSignerIndex] || signerOrder[0] || "Signer 1";
1408
1650
  const isLastSigner = currentSignerIndex >= signerOrder.length - 1;
1409
1651
  const isMultiSigner = signerOrder.length > 1;
1410
- (0, import_react5.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)(() => {
1411
1668
  if (initialTemplate) {
1412
1669
  let templateFields = initialTemplate.fields;
1413
1670
  if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
@@ -1477,7 +1734,7 @@ function SignerView({
1477
1734
  window.addEventListener("message", handleMessage);
1478
1735
  return () => window.removeEventListener("message", handleMessage);
1479
1736
  }, [initialTemplate, initialPdfUrl]);
1480
- const loadPdf = (0, import_react5.useCallback)(async (source) => {
1737
+ const loadPdf = (0, import_react6.useCallback)(async (source) => {
1481
1738
  setLoading(true);
1482
1739
  try {
1483
1740
  const rendered = await renderPdfPages(source);
@@ -1489,21 +1746,21 @@ function SignerView({
1489
1746
  setLoading(false);
1490
1747
  }
1491
1748
  }, []);
1492
- const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout").sort((a, b) => {
1749
+ const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout" && !f.formula).sort((a, b) => {
1493
1750
  if (a.page !== b.page) return a.page - b.page;
1494
1751
  const bandThreshold = 2;
1495
1752
  if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
1496
1753
  return a.x - b.x;
1497
1754
  });
1498
1755
  const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
1499
- const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" : false;
1500
- const handleFieldUpdate = (0, import_react5.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) => {
1501
1758
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
1502
1759
  }, []);
1503
- const handleFieldPropertyUpdate = (0, import_react5.useCallback)((id, updates) => {
1760
+ const handleFieldPropertyUpdate = (0, import_react6.useCallback)((id, updates) => {
1504
1761
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, ...updates } : f));
1505
1762
  }, []);
1506
- const handleNavigate = (0, import_react5.useCallback)((fieldId) => {
1763
+ const handleNavigate = (0, import_react6.useCallback)((fieldId) => {
1507
1764
  setSelectedFieldId(fieldId);
1508
1765
  const field = fields.find((f) => f.id === fieldId);
1509
1766
  if (field && containerRef.current) {
@@ -1518,7 +1775,7 @@ function SignerView({
1518
1775
  if (f.type === "checkbox") return true;
1519
1776
  return !!f.value;
1520
1777
  });
1521
- const handleAdvanceOrSubmit = (0, import_react5.useCallback)(async () => {
1778
+ const handleAdvanceOrSubmit = (0, import_react6.useCallback)(async () => {
1522
1779
  if (!allRequiredFilled) return;
1523
1780
  if (!isLastSigner) {
1524
1781
  setCurrentSignerIndex((prev) => prev + 1);
@@ -1532,7 +1789,8 @@ function SignerView({
1532
1789
  if (!pdfSource) return;
1533
1790
  setSubmitting(true);
1534
1791
  try {
1535
- const pdfBytes = await generateFilledPdf(pdfSource, fields);
1792
+ const finalFields = resolveAllFormulas(fields, transforms);
1793
+ const pdfBytes = await generateFilledPdf(pdfSource, finalFields);
1536
1794
  const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
1537
1795
  if (callbackUrl) {
1538
1796
  await postPdfToCallback(pdfBytes, callbackUrl, "signed-document.pdf");
@@ -1550,10 +1808,13 @@ function SignerView({
1550
1808
  setSubmitting(false);
1551
1809
  }
1552
1810
  }, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
1553
- const renderFieldContent = (0, import_react5.useCallback)((field) => {
1811
+ const renderFieldContent = (0, import_react6.useCallback)((field) => {
1554
1812
  if (field.type === "blackout" || field.type === "whiteout") {
1555
1813
  return null;
1556
1814
  }
1815
+ if (field.formula) {
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value formula", children: field.value || "..." });
1817
+ }
1557
1818
  const editable = field.assignee === signer;
1558
1819
  if (!editable) {
1559
1820
  if (field.type === "signature" || field.type === "initials") {
@@ -1586,6 +1847,28 @@ function SignerView({
1586
1847
  if (field.type === "signed-date") {
1587
1848
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-value", children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
1588
1849
  }
1850
+ const fontStyle = {
1851
+ fontSize: `${field.fontSize * 0.6}px`,
1852
+ letterSpacing: field.letterSpacing ? `${field.letterSpacing * 0.6}px` : void 0,
1853
+ fontFamily: field.fontFamily === "Courier" ? "monospace" : field.fontFamily === "TimesRoman" ? "serif" : void 0
1854
+ };
1855
+ if (field.options && field.options.length > 0) {
1856
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1857
+ "select",
1858
+ {
1859
+ className: "field-inline-input",
1860
+ value: field.value,
1861
+ onChange: (e) => handleFieldUpdate(field.id, e.target.value),
1862
+ onFocus: () => setSelectedFieldId(field.id),
1863
+ onClick: (e) => e.stopPropagation(),
1864
+ style: fontStyle,
1865
+ children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: field.placeholder || "Select..." }),
1867
+ field.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: opt, children: opt }, opt))
1868
+ ]
1869
+ }
1870
+ );
1871
+ }
1589
1872
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1590
1873
  "input",
1591
1874
  {
@@ -1593,14 +1876,15 @@ function SignerView({
1593
1876
  className: "field-inline-input",
1594
1877
  value: field.value,
1595
1878
  placeholder: field.placeholder,
1879
+ maxLength: field.maxLength || void 0,
1596
1880
  onChange: (e) => handleFieldUpdate(field.id, e.target.value),
1597
1881
  onFocus: () => setSelectedFieldId(field.id),
1598
1882
  onClick: (e) => e.stopPropagation(),
1599
- style: { fontSize: `${field.fontSize * 0.6}px` }
1883
+ style: fontStyle
1600
1884
  }
1601
1885
  );
1602
1886
  }, [signer, handleFieldUpdate, setSelectedFieldId]);
1603
- (0, import_react5.useEffect)(() => {
1887
+ (0, import_react6.useEffect)(() => {
1604
1888
  const sigFields = fields.filter((f) => f.assignee === signer && f.type === "signature" && f.value);
1605
1889
  if (sigFields.length > 0) {
1606
1890
  const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString();
@@ -1612,6 +1896,13 @@ function SignerView({
1612
1896
  }));
1613
1897
  }
1614
1898
  }, [fields.filter((f) => f.type === "signature" && f.value).length]);
1899
+ (0, import_react6.useEffect)(() => {
1900
+ const hasFormulas = fields.some((f) => f.formula);
1901
+ if (!hasFormulas) return;
1902
+ const resolved = resolveAllFormulas(fields, transforms);
1903
+ const changed = resolved.some((f, i) => f.value !== fields[i].value);
1904
+ if (changed) setFields(resolved);
1905
+ }, [fields, transforms]);
1615
1906
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-layout", ref: containerRef, children: [
1616
1907
  loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "loading-indicator", children: "Loading document..." }),
1617
1908
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-content", children: [
@@ -1654,13 +1945,25 @@ function SignerView({
1654
1945
  }
1655
1946
  ),
1656
1947
  selectedField.type === "text" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1657
- /* @__PURE__ */ (0, import_jsx_runtime6.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)(
1658
1960
  "input",
1659
1961
  {
1660
1962
  type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
1661
1963
  value: selectedField.value,
1662
1964
  onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
1663
1965
  placeholder: selectedField.placeholder,
1966
+ maxLength: selectedField.maxLength || void 0,
1664
1967
  className: "signer-text-input"
1665
1968
  }
1666
1969
  ),
@@ -1722,7 +2025,7 @@ function SignerView({
1722
2025
  }
1723
2026
 
1724
2027
  // src/components/pdf-builder/SignerRoleSelector.tsx
1725
- var import_react6 = require("react");
2028
+ var import_react7 = require("react");
1726
2029
  var import_jsx_runtime7 = require("react/jsx-runtime");
1727
2030
  function SignerRoleSelector({
1728
2031
  roles,
@@ -1731,8 +2034,8 @@ function SignerRoleSelector({
1731
2034
  onAddRole,
1732
2035
  onRemoveRole
1733
2036
  }) {
1734
- const [isAdding, setIsAdding] = (0, import_react6.useState)(false);
1735
- const [newRoleName, setNewRoleName] = (0, import_react6.useState)("");
2037
+ const [isAdding, setIsAdding] = (0, import_react7.useState)(false);
2038
+ const [newRoleName, setNewRoleName] = (0, import_react7.useState)("");
1736
2039
  const handleAdd = () => {
1737
2040
  if (newRoleName.trim()) {
1738
2041
  onAddRole(newRoleName.trim());
@@ -1797,9 +2100,11 @@ function SignerRoleSelector({
1797
2100
  }
1798
2101
  // Annotate the CommonJS export names for ESM import in node:
1799
2102
  0 && (module.exports = {
2103
+ BUILTIN_TRANSFORMS,
1800
2104
  DEFAULT_SIGNER_ROLES,
1801
2105
  DesignerView,
1802
2106
  FIELD_DEFAULTS,
2107
+ FONT_FAMILIES,
1803
2108
  FieldNavigator,
1804
2109
  FieldPropertyPanel,
1805
2110
  PdfViewer,
@@ -1810,9 +2115,12 @@ function SignerRoleSelector({
1810
2115
  createField,
1811
2116
  downloadPdf,
1812
2117
  generateFilledPdf,
2118
+ generateId,
1813
2119
  getSignerColor,
1814
2120
  postPdfToCallback,
1815
2121
  renderPdfPages,
2122
+ resolveAllFormulas,
2123
+ resolveFormula,
1816
2124
  uniqueLabel
1817
2125
  });
1818
2126
  //# sourceMappingURL=index.js.map