@unlev/exeq 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,6 +74,7 @@ function MultiPartySigner() {
74
74
  | `initialPdfUrl` | `string` | No | URL to a PDF to pre-load |
75
75
  | `initialTemplate` | `Template` | No | Existing template to resume editing |
76
76
  | `onSave` | `(template: Template) => void` | No | Called on "Export Template". If omitted, downloads JSON. |
77
+ | `onChange` | `(template: Template) => void` | No | Fires on every change to fields / signer roles / loaded PDF. Use for draft persistence (e.g. `localStorage`) so accidental refresh or tab close doesn't lose work. |
77
78
 
78
79
  ### `SignerView` Props
79
80
 
package/dist/index.d.mts CHANGED
@@ -38,6 +38,20 @@ interface Template {
38
38
  declare const DEFAULT_SIGNER_ROLES: string[];
39
39
  declare const SIGNER_ROLE_COLORS: Record<string, string>;
40
40
  declare function getSignerColor(role: string): string;
41
+ declare function isRedactField(f: FormField | {
42
+ type: FieldType;
43
+ }): boolean;
44
+ declare function isSignatureField(f: FormField | {
45
+ type: FieldType;
46
+ }): boolean;
47
+ declare function isTextLikeField(f: FormField | {
48
+ type: FieldType;
49
+ }): boolean;
50
+ declare function getInputType(subtype?: TextSubtype): string;
51
+ declare function getCssFontFamily(fontFamily?: string): string | undefined;
52
+ declare function sortFieldsByPosition(fields: FormField[]): FormField[];
53
+ declare function preserveFieldValues(oldFields: FormField[], newFields: FormField[]): FormField[];
54
+ declare function getFieldValues(fields: FormField[]): Record<string, string>;
41
55
  declare const FONT_FAMILIES: readonly [{
42
56
  readonly value: "Helvetica";
43
57
  readonly label: "Helvetica";
@@ -62,12 +76,18 @@ interface DesignerViewProps {
62
76
  initialTemplate?: Template;
63
77
  /** Called when the user clicks "Export Template" */
64
78
  onSave?: (template: Template) => void;
79
+ /** Called whenever the template changes (field added/moved/edited, signer
80
+ * role changed, PDF loaded). Use for draft persistence — e.g. save to
81
+ * localStorage so a refresh or accidental tab close doesn't lose work.
82
+ * Fires on every change, including programmatic ones from `initialTemplate`.
83
+ * Debounce on the caller side if you want fewer writes. */
84
+ onChange?: (template: Template) => void;
65
85
  /** When true, the built-in header bar is hidden (use headerPortalRef to place buttons externally) */
66
86
  hideHeader?: boolean;
67
87
  /** Ref to an element where the header action buttons should be portalled into */
68
88
  headerPortalRef?: React.RefObject<HTMLElement | null>;
69
89
  }
70
- declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave, hideHeader, headerPortalRef, }?: DesignerViewProps): react_jsx_runtime.JSX.Element;
90
+ declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave, onChange, hideHeader, headerPortalRef, }?: DesignerViewProps): react_jsx_runtime.JSX.Element;
71
91
 
72
92
  type TransformFn = (value: string) => string;
73
93
  type TransformMap = Record<string, TransformFn>;
@@ -311,4 +331,4 @@ declare function createPdfBuilder(defaults?: CreatePdfBuilderOptions): Promise<P
311
331
  declare function downloadPdf(bytes: Uint8Array, filename: string): void;
312
332
  declare function postPdfToCallback(bytes: Uint8Array, callbackUrl: string, filename: string): Promise<void>;
313
333
 
314
- export { A4, BUILTIN_TRANSFORMS, type Calibration, type CreatePdfBuilderOptions, DEFAULT_CALIBRATION, DEFAULT_SIGNER_ROLES, DesignerView, type DesignerViewProps, FIELD_DEFAULTS, FONT_FAMILIES, FieldNavigator, FieldPropertyPanel, type FieldType, type FillPdfOptions, type FormField, type PdfBuilder, PdfViewer, type RenderedPage, SIGNER_ROLE_COLORS, SignatureCanvas, SignerRoleSelector, SignerView, type SignerViewProps, type Template, type TextSubtype, type TransformFn, type TransformMap, US_LEGAL, US_LETTER, applyCalibration, createField, createPdfBuilder, downloadPdf, generateFilledPdf, generateId, getSignerColor, postPdfToCallback, renderPdfPages, resolveAllFormulas, resolveFormula, uniqueLabel };
334
+ export { A4, BUILTIN_TRANSFORMS, type Calibration, type CreatePdfBuilderOptions, DEFAULT_CALIBRATION, DEFAULT_SIGNER_ROLES, DesignerView, type DesignerViewProps, FIELD_DEFAULTS, FONT_FAMILIES, FieldNavigator, FieldPropertyPanel, type FieldType, type FillPdfOptions, type FormField, type PdfBuilder, PdfViewer, type RenderedPage, SIGNER_ROLE_COLORS, SignatureCanvas, SignerRoleSelector, SignerView, type SignerViewProps, type Template, type TextSubtype, type TransformFn, type TransformMap, US_LEGAL, US_LETTER, applyCalibration, createField, createPdfBuilder, downloadPdf, generateFilledPdf, generateId, getCssFontFamily, getFieldValues, getInputType, getSignerColor, isRedactField, isSignatureField, isTextLikeField, postPdfToCallback, preserveFieldValues, renderPdfPages, resolveAllFormulas, resolveFormula, sortFieldsByPosition, uniqueLabel };
package/dist/index.d.ts CHANGED
@@ -38,6 +38,20 @@ interface Template {
38
38
  declare const DEFAULT_SIGNER_ROLES: string[];
39
39
  declare const SIGNER_ROLE_COLORS: Record<string, string>;
40
40
  declare function getSignerColor(role: string): string;
41
+ declare function isRedactField(f: FormField | {
42
+ type: FieldType;
43
+ }): boolean;
44
+ declare function isSignatureField(f: FormField | {
45
+ type: FieldType;
46
+ }): boolean;
47
+ declare function isTextLikeField(f: FormField | {
48
+ type: FieldType;
49
+ }): boolean;
50
+ declare function getInputType(subtype?: TextSubtype): string;
51
+ declare function getCssFontFamily(fontFamily?: string): string | undefined;
52
+ declare function sortFieldsByPosition(fields: FormField[]): FormField[];
53
+ declare function preserveFieldValues(oldFields: FormField[], newFields: FormField[]): FormField[];
54
+ declare function getFieldValues(fields: FormField[]): Record<string, string>;
41
55
  declare const FONT_FAMILIES: readonly [{
42
56
  readonly value: "Helvetica";
43
57
  readonly label: "Helvetica";
@@ -62,12 +76,18 @@ interface DesignerViewProps {
62
76
  initialTemplate?: Template;
63
77
  /** Called when the user clicks "Export Template" */
64
78
  onSave?: (template: Template) => void;
79
+ /** Called whenever the template changes (field added/moved/edited, signer
80
+ * role changed, PDF loaded). Use for draft persistence — e.g. save to
81
+ * localStorage so a refresh or accidental tab close doesn't lose work.
82
+ * Fires on every change, including programmatic ones from `initialTemplate`.
83
+ * Debounce on the caller side if you want fewer writes. */
84
+ onChange?: (template: Template) => void;
65
85
  /** When true, the built-in header bar is hidden (use headerPortalRef to place buttons externally) */
66
86
  hideHeader?: boolean;
67
87
  /** Ref to an element where the header action buttons should be portalled into */
68
88
  headerPortalRef?: React.RefObject<HTMLElement | null>;
69
89
  }
70
- declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave, hideHeader, headerPortalRef, }?: DesignerViewProps): react_jsx_runtime.JSX.Element;
90
+ declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave, onChange, hideHeader, headerPortalRef, }?: DesignerViewProps): react_jsx_runtime.JSX.Element;
71
91
 
72
92
  type TransformFn = (value: string) => string;
73
93
  type TransformMap = Record<string, TransformFn>;
@@ -311,4 +331,4 @@ declare function createPdfBuilder(defaults?: CreatePdfBuilderOptions): Promise<P
311
331
  declare function downloadPdf(bytes: Uint8Array, filename: string): void;
312
332
  declare function postPdfToCallback(bytes: Uint8Array, callbackUrl: string, filename: string): Promise<void>;
313
333
 
314
- export { A4, BUILTIN_TRANSFORMS, type Calibration, type CreatePdfBuilderOptions, DEFAULT_CALIBRATION, DEFAULT_SIGNER_ROLES, DesignerView, type DesignerViewProps, FIELD_DEFAULTS, FONT_FAMILIES, FieldNavigator, FieldPropertyPanel, type FieldType, type FillPdfOptions, type FormField, type PdfBuilder, PdfViewer, type RenderedPage, SIGNER_ROLE_COLORS, SignatureCanvas, SignerRoleSelector, SignerView, type SignerViewProps, type Template, type TextSubtype, type TransformFn, type TransformMap, US_LEGAL, US_LETTER, applyCalibration, createField, createPdfBuilder, downloadPdf, generateFilledPdf, generateId, getSignerColor, postPdfToCallback, renderPdfPages, resolveAllFormulas, resolveFormula, uniqueLabel };
334
+ export { A4, BUILTIN_TRANSFORMS, type Calibration, type CreatePdfBuilderOptions, DEFAULT_CALIBRATION, DEFAULT_SIGNER_ROLES, DesignerView, type DesignerViewProps, FIELD_DEFAULTS, FONT_FAMILIES, FieldNavigator, FieldPropertyPanel, type FieldType, type FillPdfOptions, type FormField, type PdfBuilder, PdfViewer, type RenderedPage, SIGNER_ROLE_COLORS, SignatureCanvas, SignerRoleSelector, SignerView, type SignerViewProps, type Template, type TextSubtype, type TransformFn, type TransformMap, US_LEGAL, US_LETTER, applyCalibration, createField, createPdfBuilder, downloadPdf, generateFilledPdf, generateId, getCssFontFamily, getFieldValues, getInputType, getSignerColor, isRedactField, isSignatureField, isTextLikeField, postPdfToCallback, preserveFieldValues, renderPdfPages, resolveAllFormulas, resolveFormula, sortFieldsByPosition, uniqueLabel };
package/dist/index.js CHANGED
@@ -52,11 +52,19 @@ __export(lib_exports, {
52
52
  downloadPdf: () => downloadPdf,
53
53
  generateFilledPdf: () => generateFilledPdf,
54
54
  generateId: () => generateId,
55
+ getCssFontFamily: () => getCssFontFamily,
56
+ getFieldValues: () => getFieldValues,
57
+ getInputType: () => getInputType,
55
58
  getSignerColor: () => getSignerColor,
59
+ isRedactField: () => isRedactField,
60
+ isSignatureField: () => isSignatureField,
61
+ isTextLikeField: () => isTextLikeField,
56
62
  postPdfToCallback: () => postPdfToCallback,
63
+ preserveFieldValues: () => preserveFieldValues,
57
64
  renderPdfPages: () => renderPdfPages,
58
65
  resolveAllFormulas: () => resolveAllFormulas,
59
66
  resolveFormula: () => resolveFormula,
67
+ sortFieldsByPosition: () => sortFieldsByPosition,
60
68
  uniqueLabel: () => uniqueLabel
61
69
  });
62
70
  module.exports = __toCommonJS(lib_exports);
@@ -88,6 +96,56 @@ var SIGNER_ROLE_COLORS = {
88
96
  function getSignerColor(role) {
89
97
  return SIGNER_ROLE_COLORS[role] || "#888888";
90
98
  }
99
+ function isRedactField(f) {
100
+ return f.type === "blackout" || f.type === "whiteout";
101
+ }
102
+ function isSignatureField(f) {
103
+ return f.type === "signature" || f.type === "initials";
104
+ }
105
+ function isTextLikeField(f) {
106
+ return f.type === "text" || f.type === "dropdown" || f.type === "signed-date";
107
+ }
108
+ function getInputType(subtype) {
109
+ switch (subtype) {
110
+ case "email":
111
+ return "email";
112
+ case "number":
113
+ return "number";
114
+ case "phone":
115
+ return "tel";
116
+ case "date":
117
+ return "date";
118
+ default:
119
+ return "text";
120
+ }
121
+ }
122
+ var CSS_FONT_MAP = {
123
+ Courier: '"Courier New", Courier, monospace',
124
+ TimesRoman: '"Times New Roman", Times, serif',
125
+ Helvetica: "Helvetica, Arial, sans-serif"
126
+ };
127
+ function getCssFontFamily(fontFamily) {
128
+ return fontFamily ? CSS_FONT_MAP[fontFamily] : void 0;
129
+ }
130
+ function sortFieldsByPosition(fields) {
131
+ return [...fields].sort((a, b) => {
132
+ if (a.page !== b.page) return a.page - b.page;
133
+ const bandThreshold = 2;
134
+ if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
135
+ return a.x - b.x;
136
+ });
137
+ }
138
+ function preserveFieldValues(oldFields, newFields) {
139
+ const valueMap = new Map(oldFields.filter((f) => f.value).map((f) => [f.id, f.value]));
140
+ return newFields.map((f) => valueMap.has(f.id) ? { ...f, value: valueMap.get(f.id) } : f);
141
+ }
142
+ function getFieldValues(fields) {
143
+ const values = {};
144
+ fields.forEach((f) => {
145
+ if (!isRedactField(f)) values[f.label] = f.value || "";
146
+ });
147
+ return values;
148
+ }
91
149
  var FONT_FAMILIES = [
92
150
  { value: "Helvetica", label: "Helvetica" },
93
151
  { value: "Courier", label: "Courier New" },
@@ -443,7 +501,7 @@ function FieldOverlayItem({
443
501
  const dragPosRef = (0, import_react.useRef)({ x: field.x, y: field.y });
444
502
  const didDragRef = (0, import_react.useRef)(false);
445
503
  const resizeStartRef = (0, import_react.useRef)(null);
446
- const isRedact = field.type === "blackout" || field.type === "whiteout";
504
+ const isRedact = isRedactField(field);
447
505
  const isEditable = mode === "designer" || mode === "signer" && field.assignee === currentSigner;
448
506
  const isInactiveSigner = mode === "signer" && !isRedact && field.assignee !== currentSigner;
449
507
  const isFilled = mode === "signer" && isEditable && !isRedact && (field.type === "checkbox" ? true : field.formula ? true : !!field.value);
@@ -584,9 +642,9 @@ var INK_COLORS = [
584
642
  ];
585
643
  function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillContent, pageSize }) {
586
644
  const color = getSignerColor(field.assignee);
587
- const isRedactField = field.type === "blackout" || field.type === "whiteout";
588
- const isTextField = field.type === "text" || field.type === "signed-date" || field.type === "dropdown";
589
- const showInkColor = field.type === "text" || field.type === "dropdown" || field.type === "signature" || field.type === "initials" || field.type === "signed-date";
645
+ const isRedact = isRedactField(field);
646
+ const isText = isTextLikeField(field);
647
+ const showInkColor = isText || isSignatureField(field);
590
648
  const [newOption, setNewOption] = (0, import_react2.useState)("");
591
649
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "field-property-panel", children: [
592
650
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-header", children: [
@@ -618,7 +676,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
618
676
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: () => onDelete(field.id), className: "panel-icon-btn panel-icon-btn-danger", title: "Delete", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5 1h4v1H5V1zM2 3v1h1v8.5A1.5 1.5 0 004.5 14h5a1.5 1.5 0 001.5-1.5V4h1V3H2zm2 1h6v8.5a.5.5 0 01-.5.5h-5a.5.5 0 01-.5-.5V4z" }) }) })
619
677
  ] })
620
678
  ] }),
621
- !isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-section", children: [
679
+ !isRedact && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-section", children: [
622
680
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-section-heading", children: "Assigned To" }),
623
681
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
624
682
  "select",
@@ -633,7 +691,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
633
691
  ] }),
634
692
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-section", children: [
635
693
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-section-heading", children: "Content" }),
636
- !isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
694
+ !isRedact && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
637
695
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Field Type" }),
638
696
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: field.type, onChange: (e) => onUpdate(field.id, { type: e.target.value }), children: [
639
697
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "text", children: "Text" }),
@@ -654,15 +712,15 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
654
712
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "phone", children: "Phone" })
655
713
  ] })
656
714
  ] }),
657
- !isRedactField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
715
+ !isRedact && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
658
716
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Placeholder" }),
659
717
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "text", value: field.placeholder, onChange: (e) => onUpdate(field.id, { placeholder: e.target.value }) })
660
718
  ] }),
661
- !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: [
719
+ !isRedact && 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: [
662
720
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: field.required, onChange: (e) => onUpdate(field.id, { required: e.target.checked }) }),
663
721
  "Required"
664
722
  ] }) }),
665
- isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
723
+ isText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
666
724
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Formula" }),
667
725
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "text", value: field.formula || "", onChange: (e) => onUpdate(field.id, { formula: e.target.value || void 0 }), placeholder: "e.g. {{Date Field | month}}" }),
668
726
  field.formula && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "panel-hint", children: "Auto-computed. Signer cannot edit." })
@@ -677,7 +735,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
677
735
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", min: "0", max: "9999", value: field.maxLength || 0, onChange: (e) => onUpdate(field.id, { maxLength: Number(e.target.value) }) })
678
736
  ] })
679
737
  ] }),
680
- isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
738
+ isText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
681
739
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "panel-checkbox-label", children: [
682
740
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: field.autoShrink || false, onChange: (e) => onUpdate(field.id, { autoShrink: e.target.checked }) }),
683
741
  "Auto-shrink to fit"
@@ -714,17 +772,17 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
714
772
  ] }),
715
773
  prefillContent
716
774
  ] }),
717
- (isTextField || showInkColor) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-section", children: [
775
+ (isText || showInkColor) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-section", children: [
718
776
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "panel-section-heading", children: "Style" }),
719
- isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
777
+ isText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
720
778
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font" }),
721
779
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { value: field.fontFamily || "Helvetica", onChange: (e) => onUpdate(field.id, { fontFamily: e.target.value }), children: FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: f.value, children: f.label }, f.value)) })
722
780
  ] }),
723
- isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
781
+ isText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field", children: [
724
782
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Font Size (pt)" }),
725
783
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", min: "6", max: "72", value: field.fontSize, onChange: (e) => onUpdate(field.id, { fontSize: Number(e.target.value) }) })
726
784
  ] }),
727
- isTextField && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field-row", children: [
785
+ isText && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field-row", children: [
728
786
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "panel-field panel-field-half", children: [
729
787
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { children: "Letter Spacing" }),
730
788
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", min: "0", max: "20", step: "0.5", value: field.letterSpacing || 0, onChange: (e) => onUpdate(field.id, { letterSpacing: Number(e.target.value) }) })
@@ -1201,6 +1259,7 @@ function DesignerView({
1201
1259
  initialPdfUrl,
1202
1260
  initialTemplate,
1203
1261
  onSave,
1262
+ onChange,
1204
1263
  hideHeader,
1205
1264
  headerPortalRef
1206
1265
  } = {}) {
@@ -1235,6 +1294,20 @@ function DesignerView({
1235
1294
  const dragGhostRef = (0, import_react5.useRef)(null);
1236
1295
  const resizingRef = (0, import_react5.useRef)(false);
1237
1296
  const lastStylesRef = (0, import_react5.useRef)({});
1297
+ const onChangeMountedRef = (0, import_react5.useRef)(false);
1298
+ (0, import_react5.useEffect)(() => {
1299
+ if (!onChange) return;
1300
+ if (!onChangeMountedRef.current) {
1301
+ onChangeMountedRef.current = true;
1302
+ return;
1303
+ }
1304
+ const template = {
1305
+ fields,
1306
+ signerRoles,
1307
+ pdfUrl: typeof pdfSource === "string" ? pdfSource : ""
1308
+ };
1309
+ onChange(template);
1310
+ }, [fields, signerRoles, pdfSource, onChange]);
1238
1311
  (0, import_react5.useEffect)(() => {
1239
1312
  const pdfUrl = initialPdfUrl || initialTemplate?.pdfUrl;
1240
1313
  if (pdfUrl) {
@@ -1281,11 +1354,16 @@ function DesignerView({
1281
1354
  reader.readAsArrayBuffer(file);
1282
1355
  }, [loadPdf]);
1283
1356
  const handlePageClick = (0, import_react5.useCallback)((page, x, y) => {
1357
+ const scrollEl = pdfAreaRef.current;
1358
+ const scrollTop = scrollEl?.scrollTop ?? 0;
1284
1359
  const field = createField(activeFieldType, activeRole, page, x, y, fields);
1285
1360
  const sticky = lastStylesRef.current[activeFieldType];
1286
1361
  const styledField = sticky ? { ...field, ...sticky } : field;
1287
1362
  setFields((prev) => [...prev, styledField]);
1288
1363
  setSelectedFieldIds(/* @__PURE__ */ new Set([styledField.id]));
1364
+ requestAnimationFrame(() => {
1365
+ if (scrollEl) scrollEl.scrollTop = scrollTop;
1366
+ });
1289
1367
  setRightTab("properties");
1290
1368
  }, [activeFieldType, activeRole, fields]);
1291
1369
  const handleFieldMove = (0, import_react5.useCallback)((id, page, x, y) => {
@@ -1660,24 +1738,19 @@ function DesignerView({
1660
1738
  window.addEventListener("mousemove", handleMouseMove);
1661
1739
  window.addEventListener("mouseup", handleMouseUp);
1662
1740
  }, [panelWidth]);
1663
- const sortedFields = [...fields].sort((a, b) => {
1664
- if (a.page !== b.page) return a.page - b.page;
1665
- const bandThreshold = 2;
1666
- if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
1667
- return a.x - b.x;
1668
- });
1741
+ const sortedFields = sortFieldsByPosition(fields);
1669
1742
  const selectedField = selectedFieldIds.size === 1 ? fields.find((f) => f.id === Array.from(selectedFieldIds)[0]) || null : null;
1670
1743
  const renderFieldContent = (0, import_react5.useCallback)((field) => {
1671
- if (field.type === "blackout" || field.type === "whiteout") {
1744
+ if (isRedactField(field)) {
1672
1745
  return null;
1673
1746
  }
1674
- if (field.type === "signature" || field.type === "initials") {
1747
+ if (isSignatureField(field)) {
1675
1748
  if (field.value) {
1676
1749
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" });
1677
1750
  }
1678
1751
  }
1679
1752
  const inkColor = field.inkColor || "#000000";
1680
- const cssFontFamily = field.fontFamily === "Courier" ? '"Courier New", Courier, monospace' : field.fontFamily === "TimesRoman" ? '"Times New Roman", Times, serif' : field.fontFamily === "Helvetica" ? "Helvetica, Arial, sans-serif" : void 0;
1753
+ const cssFontFamily = getCssFontFamily(field.fontFamily);
1681
1754
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1682
1755
  "div",
1683
1756
  {
@@ -1906,9 +1979,9 @@ function DesignerView({
1906
1979
  onUpdate: handleFieldUpdate,
1907
1980
  onDelete: handleFieldDelete,
1908
1981
  pageSize: pages[selectedField.page] ? { width: pages[selectedField.page].pdfWidth, height: pages[selectedField.page].pdfHeight } : void 0,
1909
- prefillContent: selectedField.type !== "blackout" && selectedField.type !== "whiteout" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "prefill-section", children: [
1982
+ prefillContent: !isRedactField(selectedField) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "prefill-section", children: [
1910
1983
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { children: "Pre-fill Value" }),
1911
- selectedField.type === "signature" || selectedField.type === "initials" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1984
+ isSignatureField(selectedField) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1912
1985
  SignatureCanvas,
1913
1986
  {
1914
1987
  width: panelWidth - 40,
@@ -2188,7 +2261,7 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
2188
2261
  const y = pageHeight - field.y / 100 * pageHeight - field.height / 100 * pageHeight;
2189
2262
  const w = field.width / 100 * pageWidth;
2190
2263
  const h = field.height / 100 * pageHeight;
2191
- if (field.type === "blackout" || field.type === "whiteout") {
2264
+ if (isRedactField(field)) {
2192
2265
  page.drawRectangle({
2193
2266
  x,
2194
2267
  y,
@@ -2217,7 +2290,7 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
2217
2290
  color: inkColor
2218
2291
  });
2219
2292
  }
2220
- } else if (field.type === "signature" || field.type === "initials") {
2293
+ } else if (isSignatureField(field)) {
2221
2294
  if (field.value.startsWith("data:image/png")) {
2222
2295
  const img = await getSignature(field.value);
2223
2296
  page.drawImage(img, { x, y, width: w, height: h });
@@ -2515,7 +2588,7 @@ function SignerView({
2515
2588
  (0, import_react7.useEffect)(() => {
2516
2589
  if (fields.length === 0 || !isMultiSigner) return;
2517
2590
  const signerFields = fields.filter(
2518
- (f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout"
2591
+ (f) => f.assignee === signer && !isRedactField(f)
2519
2592
  );
2520
2593
  const allFilled = signerFields.length > 0 && signerFields.every((f) => {
2521
2594
  if (!f.required) return true;
@@ -2609,14 +2682,9 @@ function SignerView({
2609
2682
  setLoading(false);
2610
2683
  }
2611
2684
  }, []);
2612
- const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout" && !f.formula).sort((a, b) => {
2613
- if (a.page !== b.page) return a.page - b.page;
2614
- const bandThreshold = 2;
2615
- if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
2616
- return a.x - b.x;
2617
- });
2685
+ const editableFields = sortFieldsByPosition(fields.filter((f) => f.assignee === signer && !isRedactField(f) && !f.formula));
2618
2686
  const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
2619
- const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" && !selectedField.formula : false;
2687
+ const isFieldEditable = selectedField ? selectedField.assignee === signer && !isRedactField(selectedField) && !selectedField.formula : false;
2620
2688
  const handleFieldUpdate = (0, import_react7.useCallback)((id, value) => {
2621
2689
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
2622
2690
  }, []);
@@ -2628,7 +2696,7 @@ function SignerView({
2628
2696
  if (!onChange) return;
2629
2697
  const values = {};
2630
2698
  fields.forEach((f) => {
2631
- if (f.type !== "blackout" && f.type !== "whiteout") values[f.label] = f.value || "";
2699
+ if (!isRedactField(f)) values[f.label] = f.value || "";
2632
2700
  });
2633
2701
  onChange(values);
2634
2702
  }, [fieldValuesKey]);
@@ -2649,18 +2717,12 @@ function SignerView({
2649
2717
  if (f.minLength && f.value.length < f.minLength) return false;
2650
2718
  return true;
2651
2719
  });
2652
- const getFieldValues = (0, import_react7.useCallback)(() => {
2653
- const values = {};
2654
- fields.forEach((f) => {
2655
- if (f.type !== "blackout" && f.type !== "whiteout") values[f.label] = f.value || "";
2656
- });
2657
- return values;
2658
- }, [fields]);
2720
+ const getValues = (0, import_react7.useCallback)(() => getFieldValues(fields), [fields]);
2659
2721
  const handleAdvanceOrSubmit = (0, import_react7.useCallback)(async () => {
2660
2722
  if (!allRequiredFilled) return;
2661
2723
  auditLogRef.current.push({ signer, completedAt: (/* @__PURE__ */ new Date()).toISOString() });
2662
2724
  if (onSignerComplete) {
2663
- onSignerComplete(signer, getFieldValues());
2725
+ onSignerComplete(signer, getValues());
2664
2726
  }
2665
2727
  if (!isLastSigner) {
2666
2728
  setCurrentSignerIndex((prev) => prev + 1);
@@ -2699,7 +2761,7 @@ function SignerView({
2699
2761
  }
2700
2762
  const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
2701
2763
  if (onExport && exportFormat) {
2702
- const values = getFieldValues();
2764
+ const values = getValues();
2703
2765
  if (exportFormat === "json") {
2704
2766
  onExport(JSON.stringify(values, null, 2), "json");
2705
2767
  } else {
@@ -2724,9 +2786,9 @@ ${row.join(",")}`, "csv");
2724
2786
  } finally {
2725
2787
  setSubmitting(false);
2726
2788
  }
2727
- }, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner, signer, onSignerComplete, includeAuditTrail, exportFormat, onExport, getFieldValues, transforms]);
2789
+ }, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner, signer, onSignerComplete, includeAuditTrail, exportFormat, onExport, getValues, transforms]);
2728
2790
  const renderFieldContent = (0, import_react7.useCallback)((field) => {
2729
- if (field.type === "blackout" || field.type === "whiteout") {
2791
+ if (isRedactField(field)) {
2730
2792
  return null;
2731
2793
  }
2732
2794
  if (field.formula) {
@@ -2734,7 +2796,7 @@ ${row.join(",")}`, "csv");
2734
2796
  }
2735
2797
  const editable = field.assignee === signer;
2736
2798
  if (!editable) {
2737
- if (field.type === "signature" || field.type === "initials") {
2799
+ if (isSignatureField(field)) {
2738
2800
  return field.value ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-placeholder readonly", children: field.placeholder });
2739
2801
  }
2740
2802
  if (field.type === "checkbox") {
@@ -2742,7 +2804,7 @@ ${row.join(",")}`, "csv");
2742
2804
  }
2743
2805
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-overlay-placeholder readonly", children: field.value || field.placeholder });
2744
2806
  }
2745
- if (field.type === "signature" || field.type === "initials") {
2807
+ if (isSignatureField(field)) {
2746
2808
  if (field.value) {
2747
2809
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "field-signature-filled", onClick: () => handleFieldUpdate(field.id, ""), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: field.value, alt: field.label, className: "field-signature-preview" }) });
2748
2810
  }
@@ -2768,7 +2830,7 @@ ${row.join(",")}`, "csv");
2768
2830
  fontSize: `${field.fontSize}pt`,
2769
2831
  letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
2770
2832
  lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
2771
- fontFamily: field.fontFamily === "Courier" ? '"Courier New", Courier, monospace' : field.fontFamily === "TimesRoman" ? '"Times New Roman", Times, serif' : field.fontFamily === "Helvetica" ? "Helvetica, Arial, sans-serif" : void 0
2833
+ fontFamily: getCssFontFamily(field.fontFamily)
2772
2834
  };
2773
2835
  if (field.type === "dropdown" || field.options && field.options.length > 0) {
2774
2836
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
@@ -2853,7 +2915,7 @@ ${row.join(",")}`, "csv");
2853
2915
  selectedField && isFieldEditable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "signer-field-input", children: [
2854
2916
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: selectedField.label }),
2855
2917
  selectedField.required && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "required-badge", children: "Required" }),
2856
- (selectedField.type === "signature" || selectedField.type === "initials") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2918
+ isSignatureField(selectedField) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2857
2919
  SignatureCanvas,
2858
2920
  {
2859
2921
  width: 280,
@@ -3040,11 +3102,19 @@ function SignerRoleSelector({
3040
3102
  downloadPdf,
3041
3103
  generateFilledPdf,
3042
3104
  generateId,
3105
+ getCssFontFamily,
3106
+ getFieldValues,
3107
+ getInputType,
3043
3108
  getSignerColor,
3109
+ isRedactField,
3110
+ isSignatureField,
3111
+ isTextLikeField,
3044
3112
  postPdfToCallback,
3113
+ preserveFieldValues,
3045
3114
  renderPdfPages,
3046
3115
  resolveAllFormulas,
3047
3116
  resolveFormula,
3117
+ sortFieldsByPosition,
3048
3118
  uniqueLabel
3049
3119
  });
3050
3120
  //# sourceMappingURL=index.js.map