@unlev/exeq 0.3.0 → 0.3.2

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.mjs CHANGED
@@ -165,6 +165,7 @@ function PdfViewer({
165
165
  onPageClick,
166
166
  onDropField,
167
167
  onGroupMove,
168
+ onMoveStart,
168
169
  onMoveEnd,
169
170
  mode,
170
171
  currentSigner,
@@ -274,6 +275,7 @@ function PdfViewer({
274
275
  onMove: onFieldMove,
275
276
  onResize: onFieldResize,
276
277
  onGroupMove: selectedFieldIds.size > 1 && selectedFieldIds.has(field.id) ? onGroupMove : void 0,
278
+ onMoveStart,
277
279
  onMoveEnd,
278
280
  otherFields: mode === "designer" ? pageFields.filter((f) => f.id !== field.id && !selectedFieldIds.has(f.id)) : void 0,
279
281
  setGuides: mode === "designer" ? setGuides : void 0,
@@ -363,6 +365,7 @@ function FieldOverlayItem({
363
365
  onMove,
364
366
  onResize,
365
367
  onGroupMove,
368
+ onMoveStart,
366
369
  onMoveEnd,
367
370
  otherFields,
368
371
  setGuides,
@@ -392,6 +395,7 @@ function FieldOverlayItem({
392
395
  onSelect(e);
393
396
  }
394
397
  if (field.locked) return;
398
+ onMoveStart?.();
395
399
  const pageEl = overlayRef.current?.closest(".pdf-page");
396
400
  if (!pageEl) return;
397
401
  didDragRef.current = false;
@@ -440,11 +444,12 @@ function FieldOverlayItem({
440
444
  };
441
445
  window.addEventListener("mousemove", handleMouseMove);
442
446
  window.addEventListener("mouseup", handleMouseUp);
443
- }, [field, mode, onMove, onSelect, isMultiSelected, onGroupMove, onMoveEnd, selectedIds, otherFields, setGuides, pageIndex]);
447
+ }, [field, mode, onMove, onSelect, isMultiSelected, onGroupMove, onMoveStart, onMoveEnd, selectedIds, otherFields, setGuides, pageIndex]);
444
448
  const handleResizeMouseDown = useCallback((e) => {
445
449
  if (mode !== "designer" || !onResize || field.locked) return;
446
450
  e.preventDefault();
447
451
  e.stopPropagation();
452
+ onMoveStart?.();
448
453
  const pageEl = overlayRef.current?.closest(".pdf-page");
449
454
  if (!pageEl) return;
450
455
  resizeStartRef.current = {
@@ -470,7 +475,7 @@ function FieldOverlayItem({
470
475
  };
471
476
  window.addEventListener("mousemove", handleMouseMove);
472
477
  window.addEventListener("mouseup", handleMouseUp);
473
- }, [field, mode, onResize, onMoveEnd]);
478
+ }, [field, mode, onResize, onMoveStart, onMoveEnd]);
474
479
  return /* @__PURE__ */ jsxs(
475
480
  "div",
476
481
  {
@@ -609,6 +614,13 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
609
614
  /* @__PURE__ */ jsx2("input", { type: "number", min: "0", max: "9999", value: field.maxLength || 0, onChange: (e) => onUpdate(field.id, { maxLength: Number(e.target.value) }) })
610
615
  ] })
611
616
  ] }),
617
+ isTextField && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
618
+ /* @__PURE__ */ jsxs2("label", { className: "panel-checkbox-label", children: [
619
+ /* @__PURE__ */ jsx2("input", { type: "checkbox", checked: field.autoShrink || false, onChange: (e) => onUpdate(field.id, { autoShrink: e.target.checked }) }),
620
+ "Auto-shrink to fit"
621
+ ] }),
622
+ field.autoShrink && /* @__PURE__ */ jsx2("span", { className: "panel-hint", children: "Font size reduces to fit text within the field width" })
623
+ ] }),
612
624
  (field.type === "text" || field.type === "dropdown") && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
613
625
  /* @__PURE__ */ jsx2("label", { children: field.type === "dropdown" ? "Options" : "Predefined Options" }),
614
626
  /* @__PURE__ */ jsxs2("div", { className: "panel-options-list", children: [
@@ -1031,13 +1043,13 @@ function useHistory(initialState, maxHistory = 50) {
1031
1043
  present: initialState,
1032
1044
  future: []
1033
1045
  });
1034
- const skipRef = useRef3(false);
1046
+ const batchRef = useRef3(false);
1047
+ const batchStartRef = useRef3(null);
1035
1048
  const set = useCallback3((updater) => {
1036
1049
  setState((prev) => {
1037
1050
  const newPresent = typeof updater === "function" ? updater(prev.present) : updater;
1038
1051
  if (newPresent === prev.present) return prev;
1039
- if (skipRef.current) {
1040
- skipRef.current = false;
1052
+ if (batchRef.current) {
1041
1053
  return { ...prev, present: newPresent };
1042
1054
  }
1043
1055
  return {
@@ -1048,15 +1060,31 @@ function useHistory(initialState, maxHistory = 50) {
1048
1060
  });
1049
1061
  }, [maxHistory]);
1050
1062
  const setWithoutHistory = useCallback3((updater) => {
1051
- skipRef.current = true;
1052
- set(updater);
1053
- }, [set]);
1054
- const snapshot = useCallback3(() => {
1055
- setState((prev) => ({
1056
- past: [...prev.past.slice(-maxHistory), prev.present],
1057
- present: prev.present,
1058
- future: []
1059
- }));
1063
+ setState((prev) => {
1064
+ const newPresent = typeof updater === "function" ? updater(prev.present) : updater;
1065
+ if (newPresent === prev.present) return prev;
1066
+ return { ...prev, present: newPresent };
1067
+ });
1068
+ }, []);
1069
+ const beginBatch = useCallback3(() => {
1070
+ batchRef.current = true;
1071
+ setState((prev) => {
1072
+ batchStartRef.current = prev.present;
1073
+ return prev;
1074
+ });
1075
+ }, []);
1076
+ const commitBatch = useCallback3(() => {
1077
+ batchRef.current = false;
1078
+ setState((prev) => {
1079
+ const startState = batchStartRef.current;
1080
+ batchStartRef.current = null;
1081
+ if (!startState || startState === prev.present) return prev;
1082
+ return {
1083
+ past: [...prev.past.slice(-maxHistory), startState],
1084
+ present: prev.present,
1085
+ future: []
1086
+ };
1087
+ });
1060
1088
  }, [maxHistory]);
1061
1089
  const undo = useCallback3(() => {
1062
1090
  setState((prev) => {
@@ -1084,7 +1112,8 @@ function useHistory(initialState, maxHistory = 50) {
1084
1112
  state: state.present,
1085
1113
  set,
1086
1114
  setWithoutHistory,
1087
- snapshot,
1115
+ beginBatch,
1116
+ commitBatch,
1088
1117
  undo,
1089
1118
  redo,
1090
1119
  canUndo: state.past.length > 0,
@@ -1123,7 +1152,7 @@ function DesignerView({
1123
1152
  ] }) });
1124
1153
  }
1125
1154
  const [pages, setPages] = useState5([]);
1126
- const { state: fields, set: setFields, setWithoutHistory: setFieldsSilent, snapshot: snapshotFields, undo: undoFields, redo: redoFields, canUndo, canRedo } = useHistory(initialTemplate?.fields ?? []);
1155
+ const { state: fields, set: setFields, setWithoutHistory: setFieldsSilent, beginBatch, commitBatch, undo: undoFields, redo: redoFields, canUndo, canRedo } = useHistory(initialTemplate?.fields ?? []);
1127
1156
  const [selectedFieldIds, setSelectedFieldIds] = useState5(/* @__PURE__ */ new Set());
1128
1157
  const [signerRoles, setSignerRoles] = useState5(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
1129
1158
  const [activeRole, setActiveRole] = useState5("Sender");
@@ -1708,7 +1737,8 @@ function DesignerView({
1708
1737
  onFieldMove: handleFieldMove,
1709
1738
  onFieldResize: handleFieldResize,
1710
1739
  onGroupMove: handleGroupMove,
1711
- onMoveEnd: snapshotFields,
1740
+ onMoveStart: beginBatch,
1741
+ onMoveEnd: commitBatch,
1712
1742
  onPageClick: handlePageClick,
1713
1743
  onDropField: handleDropOnPage,
1714
1744
  onMarqueeSelect: (ids) => setSelectedFieldIds(new Set(ids)),
@@ -1959,34 +1989,137 @@ function DesignerView({
1959
1989
  import { useState as useState7, useCallback as useCallback5, useEffect as useEffect3, useRef as useRef5 } from "react";
1960
1990
 
1961
1991
  // src/utils/pdfFiller.ts
1962
- import { PDFDocument, rgb, StandardFonts } from "pdf-lib";
1992
+ import {
1993
+ PDFDocument,
1994
+ rgb,
1995
+ StandardFonts
1996
+ } from "pdf-lib";
1997
+
1998
+ // src/utils/formulaResolver.ts
1999
+ var BUILTIN_TRANSFORMS = {
2000
+ // Date transforms (expects a parseable date string)
2001
+ month: (v) => {
2002
+ const d = new Date(v);
2003
+ return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1);
2004
+ },
2005
+ month2: (v) => {
2006
+ const d = new Date(v);
2007
+ return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1).padStart(2, "0");
2008
+ },
2009
+ monthname: (v) => {
2010
+ const d = new Date(v);
2011
+ return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "long" });
2012
+ },
2013
+ monthshort: (v) => {
2014
+ const d = new Date(v);
2015
+ return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "short" });
2016
+ },
2017
+ day: (v) => {
2018
+ const d = new Date(v);
2019
+ return isNaN(d.getTime()) ? "" : String(d.getDate());
2020
+ },
2021
+ day2: (v) => {
2022
+ const d = new Date(v);
2023
+ return isNaN(d.getTime()) ? "" : String(d.getDate()).padStart(2, "0");
2024
+ },
2025
+ year: (v) => {
2026
+ const d = new Date(v);
2027
+ return isNaN(d.getTime()) ? "" : String(d.getFullYear());
2028
+ },
2029
+ year2: (v) => {
2030
+ const d = new Date(v);
2031
+ return isNaN(d.getTime()) ? "" : String(d.getFullYear()).slice(-2);
2032
+ },
2033
+ // String transforms
2034
+ upper: (v) => v.toUpperCase(),
2035
+ lower: (v) => v.toLowerCase(),
2036
+ trim: (v) => v.trim(),
2037
+ first: (v) => v.split(/\s+/)[0] || "",
2038
+ last: (v) => {
2039
+ const parts = v.split(/\s+/);
2040
+ return parts[parts.length - 1] || "";
2041
+ },
2042
+ initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
2043
+ // Numeric / substring
2044
+ last4: (v) => v.slice(-4),
2045
+ last2: (v) => v.slice(-2),
2046
+ first4: (v) => v.slice(0, 4),
2047
+ first2: (v) => v.slice(0, 2),
2048
+ digits: (v) => v.replace(/\D/g, ""),
2049
+ number: (v) => {
2050
+ const n = parseFloat(v);
2051
+ return isNaN(n) ? "" : String(n);
2052
+ },
2053
+ currency: (v) => {
2054
+ const n = parseFloat(v.replace(/[^0-9.-]/g, ""));
2055
+ return isNaN(n) ? "" : `$${n.toFixed(2)}`;
2056
+ }
2057
+ };
2058
+ var FORMULA_RE = /\{\{(.+?)\}\}/g;
2059
+ var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
2060
+ function resolveFormula(formula, fields, customTransforms) {
2061
+ const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
2062
+ return formula.replace(FORMULA_RE, (_match, expr) => {
2063
+ const pipeMatch = expr.match(PIPE_RE);
2064
+ const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
2065
+ const transformName = pipeMatch ? pipeMatch[2].trim() : null;
2066
+ const sourceField = fields.find((f) => f.label.toLowerCase() === sourceLabel.toLowerCase()) || fields.find((f) => f.id === sourceLabel);
2067
+ if (!sourceField) return "";
2068
+ const rawValue = sourceField.value || "";
2069
+ if (!transformName) return rawValue;
2070
+ const fn = transforms[transformName];
2071
+ if (!fn) return rawValue;
2072
+ try {
2073
+ return fn(rawValue);
2074
+ } catch {
2075
+ return rawValue;
2076
+ }
2077
+ });
2078
+ }
2079
+ function resolveAllFormulas(fields, customTransforms) {
2080
+ return fields.map((f) => {
2081
+ if (!f.formula) return f;
2082
+ const computed = resolveFormula(f.formula, fields, customTransforms);
2083
+ return computed !== f.value ? { ...f, value: computed } : f;
2084
+ });
2085
+ }
2086
+
2087
+ // src/utils/pdfFiller.ts
1963
2088
  var FONT_MAP = {
1964
- "Helvetica": StandardFonts.Helvetica,
1965
- "Courier": StandardFonts.Courier,
1966
- "TimesRoman": StandardFonts.TimesRoman
2089
+ Helvetica: StandardFonts.Helvetica,
2090
+ Courier: StandardFonts.Courier,
2091
+ TimesRoman: StandardFonts.TimesRoman
1967
2092
  };
1968
- async function generateFilledPdf(pdfSource, fields) {
1969
- let pdfBytes;
1970
- if (typeof pdfSource === "string") {
1971
- const res = await fetch(pdfSource);
1972
- pdfBytes = await res.arrayBuffer();
1973
- } else {
1974
- pdfBytes = pdfSource;
1975
- }
1976
- const pdfDoc = await PDFDocument.load(pdfBytes);
1977
- const fontCache = /* @__PURE__ */ new Map();
1978
- const usedFontKeys = new Set(fields.map((f) => f.fontFamily || "Helvetica"));
1979
- for (const key of usedFontKeys) {
1980
- const stdFont = FONT_MAP[key] || StandardFonts.Helvetica;
1981
- fontCache.set(key, await pdfDoc.embedFont(stdFont));
1982
- }
1983
- const pages = pdfDoc.getPages();
1984
- function hexToRgb(hex) {
1985
- const r = parseInt(hex.slice(1, 3), 16) / 255;
1986
- const g = parseInt(hex.slice(3, 5), 16) / 255;
1987
- const b = parseInt(hex.slice(5, 7), 16) / 255;
1988
- return rgb(r, g, b);
2093
+ var US_LETTER = [612, 792];
2094
+ var US_LEGAL = [612, 1008];
2095
+ var A4 = [595.28, 841.89];
2096
+ var DEFAULT_CALIBRATION = {
2097
+ xOffset: 0,
2098
+ yOffset: 0,
2099
+ xScale: 1,
2100
+ yScale: 1
2101
+ };
2102
+ function applyCalibration(fields, calibration, pageSize = US_LETTER) {
2103
+ if (calibration.xOffset === 0 && calibration.yOffset === 0 && calibration.xScale === 1 && calibration.yScale === 1) {
2104
+ return fields;
1989
2105
  }
2106
+ const xPctOff = calibration.xOffset / pageSize[0] * 100;
2107
+ const yPctOff = calibration.yOffset / pageSize[1] * 100;
2108
+ return fields.map((f) => ({
2109
+ ...f,
2110
+ x: f.x * calibration.xScale + xPctOff,
2111
+ y: f.y * calibration.yScale + yPctOff,
2112
+ width: f.width * calibration.xScale,
2113
+ height: f.height * calibration.yScale
2114
+ }));
2115
+ }
2116
+ function hexToRgb(hex) {
2117
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
2118
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
2119
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
2120
+ return rgb(r, g, b);
2121
+ }
2122
+ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
1990
2123
  for (const field of fields) {
1991
2124
  const page = pages[field.page];
1992
2125
  if (!page) continue;
@@ -2027,37 +2160,32 @@ async function generateFilledPdf(pdfSource, fields) {
2027
2160
  }
2028
2161
  } else if (field.type === "signature" || field.type === "initials") {
2029
2162
  if (field.value.startsWith("data:image/png")) {
2030
- const pngBytes = Uint8Array.from(
2031
- atob(field.value.split(",")[1]),
2032
- (c) => c.charCodeAt(0)
2033
- );
2034
- const pngImage = await pdfDoc.embedPng(pngBytes);
2035
- page.drawImage(pngImage, {
2036
- x,
2037
- y,
2038
- width: w,
2039
- height: h
2040
- });
2163
+ const img = await getSignature(field.value);
2164
+ page.drawImage(img, { x, y, width: w, height: h });
2041
2165
  }
2042
2166
  } else {
2043
- const font = fontCache.get(field.fontFamily || "Helvetica");
2167
+ const font = await getFont(field.fontFamily || "Helvetica");
2044
2168
  const spacing = field.letterSpacing || 0;
2045
- const textWidthAtSize = (text, size) => {
2046
- const baseWidth = font.widthOfTextAtSize(text, size);
2047
- return baseWidth + spacing * (text.length - 1);
2048
- };
2049
- const maxFontSize = Math.min(field.fontSize, h * 0.7);
2050
- let fontSize = maxFontSize;
2051
- const padding = 4;
2052
- while (fontSize > 4) {
2053
- if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
2054
- fontSize -= 0.5;
2169
+ const textWidthAtSize = (text, size) => font.widthOfTextAtSize(text, size) + spacing * (text.length - 1);
2170
+ let fontSize = Math.min(field.fontSize, h * 0.7);
2171
+ if (field.autoShrink) {
2172
+ const padding = 4;
2173
+ while (fontSize > 4) {
2174
+ if (textWidthAtSize(field.value, fontSize) <= w - padding) break;
2175
+ fontSize -= 0.5;
2176
+ }
2055
2177
  }
2056
2178
  if (spacing > 0) {
2057
2179
  let cx = x + 2;
2058
2180
  const cy = y + h * 0.3;
2059
2181
  for (const char of field.value) {
2060
- page.drawText(char, { x: cx, y: cy, size: fontSize, font, color: inkColor });
2182
+ page.drawText(char, {
2183
+ x: cx,
2184
+ y: cy,
2185
+ size: fontSize,
2186
+ font,
2187
+ color: inkColor
2188
+ });
2061
2189
  cx += font.widthOfTextAtSize(char, fontSize) + spacing;
2062
2190
  }
2063
2191
  } else {
@@ -2071,7 +2199,98 @@ async function generateFilledPdf(pdfSource, fields) {
2071
2199
  }
2072
2200
  }
2073
2201
  }
2074
- return pdfDoc.save();
2202
+ }
2203
+ async function generateFilledPdf(opts) {
2204
+ const builder = await createPdfBuilder({ pageSize: opts.pageSize });
2205
+ await builder.addRecord(opts);
2206
+ return builder.save();
2207
+ }
2208
+ async function createPdfBuilder(defaults = {}) {
2209
+ const doc = await PDFDocument.create();
2210
+ const fontCache = /* @__PURE__ */ new Map();
2211
+ const embeddedPagesByUrl = /* @__PURE__ */ new Map();
2212
+ const signatureCache = /* @__PURE__ */ new Map();
2213
+ async function getFont(family) {
2214
+ let f = fontCache.get(family);
2215
+ if (!f) {
2216
+ const stdName = FONT_MAP[family] || StandardFonts.Helvetica;
2217
+ f = await doc.embedFont(stdName);
2218
+ fontCache.set(family, f);
2219
+ }
2220
+ return f;
2221
+ }
2222
+ async function ensureFonts(fields) {
2223
+ const keys = new Set(fields.map((f) => f.fontFamily || "Helvetica"));
2224
+ for (const k of keys) await getFont(k);
2225
+ }
2226
+ async function embedSource(source) {
2227
+ if (typeof source === "string") {
2228
+ let pages = embeddedPagesByUrl.get(source);
2229
+ if (!pages) {
2230
+ const res = await fetch(source);
2231
+ const bytes = await res.arrayBuffer();
2232
+ const srcDoc2 = await PDFDocument.load(bytes);
2233
+ pages = await Promise.all(
2234
+ srcDoc2.getPages().map((p) => doc.embedPage(p))
2235
+ );
2236
+ embeddedPagesByUrl.set(source, pages);
2237
+ }
2238
+ return pages;
2239
+ }
2240
+ const srcDoc = await PDFDocument.load(source);
2241
+ return Promise.all(srcDoc.getPages().map((p) => doc.embedPage(p)));
2242
+ }
2243
+ async function getSignature(dataUrl) {
2244
+ let img = signatureCache.get(dataUrl);
2245
+ if (!img) {
2246
+ const b64 = dataUrl.split(",")[1] ?? "";
2247
+ const pngBytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
2248
+ img = await doc.embedPng(pngBytes);
2249
+ signatureCache.set(dataUrl, img);
2250
+ }
2251
+ return img;
2252
+ }
2253
+ return {
2254
+ doc,
2255
+ async addRecord(opts) {
2256
+ const pageSize = opts.pageSize ?? defaults.pageSize;
2257
+ let fields = opts.resolveFormulas ? resolveAllFormulas(opts.fields, opts.customTransforms) : opts.fields;
2258
+ if (opts.calibration) {
2259
+ fields = applyCalibration(
2260
+ fields,
2261
+ opts.calibration,
2262
+ pageSize ?? US_LETTER
2263
+ );
2264
+ }
2265
+ await ensureFonts(fields);
2266
+ let sourcePages = [];
2267
+ let pageCount;
2268
+ if (opts.pdfSource !== null) {
2269
+ sourcePages = await embedSource(opts.pdfSource);
2270
+ pageCount = sourcePages.length;
2271
+ } else {
2272
+ pageCount = opts.pageCount ?? 1;
2273
+ }
2274
+ const newPages = [];
2275
+ for (let i = 0; i < pageCount; i++) {
2276
+ const size = pageSize ? pageSize : sourcePages[i] ? [sourcePages[i].width, sourcePages[i].height] : US_LETTER;
2277
+ const page = doc.addPage(size);
2278
+ newPages.push(page);
2279
+ if (sourcePages[i]) {
2280
+ page.drawPage(sourcePages[i], {
2281
+ x: 0,
2282
+ y: 0,
2283
+ width: size[0],
2284
+ height: size[1]
2285
+ });
2286
+ }
2287
+ }
2288
+ await renderFieldsOnPages(newPages, fields, getFont, getSignature);
2289
+ },
2290
+ async save() {
2291
+ return doc.save();
2292
+ }
2293
+ };
2075
2294
  }
2076
2295
  function downloadPdf(bytes, filename) {
2077
2296
  const blob = new Blob([bytes.slice().buffer], { type: "application/pdf" });
@@ -2183,95 +2402,6 @@ function FieldNavigator({
2183
2402
  ] });
2184
2403
  }
2185
2404
 
2186
- // src/utils/formulaResolver.ts
2187
- var BUILTIN_TRANSFORMS = {
2188
- // Date transforms (expects a parseable date string)
2189
- month: (v) => {
2190
- const d = new Date(v);
2191
- return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1);
2192
- },
2193
- month2: (v) => {
2194
- const d = new Date(v);
2195
- return isNaN(d.getTime()) ? "" : String(d.getMonth() + 1).padStart(2, "0");
2196
- },
2197
- monthname: (v) => {
2198
- const d = new Date(v);
2199
- return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "long" });
2200
- },
2201
- monthshort: (v) => {
2202
- const d = new Date(v);
2203
- return isNaN(d.getTime()) ? "" : d.toLocaleString("en", { month: "short" });
2204
- },
2205
- day: (v) => {
2206
- const d = new Date(v);
2207
- return isNaN(d.getTime()) ? "" : String(d.getDate());
2208
- },
2209
- day2: (v) => {
2210
- const d = new Date(v);
2211
- return isNaN(d.getTime()) ? "" : String(d.getDate()).padStart(2, "0");
2212
- },
2213
- year: (v) => {
2214
- const d = new Date(v);
2215
- return isNaN(d.getTime()) ? "" : String(d.getFullYear());
2216
- },
2217
- year2: (v) => {
2218
- const d = new Date(v);
2219
- return isNaN(d.getTime()) ? "" : String(d.getFullYear()).slice(-2);
2220
- },
2221
- // String transforms
2222
- upper: (v) => v.toUpperCase(),
2223
- lower: (v) => v.toLowerCase(),
2224
- trim: (v) => v.trim(),
2225
- first: (v) => v.split(/\s+/)[0] || "",
2226
- last: (v) => {
2227
- const parts = v.split(/\s+/);
2228
- return parts[parts.length - 1] || "";
2229
- },
2230
- initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
2231
- // Numeric / substring
2232
- last4: (v) => v.slice(-4),
2233
- last2: (v) => v.slice(-2),
2234
- first4: (v) => v.slice(0, 4),
2235
- first2: (v) => v.slice(0, 2),
2236
- digits: (v) => v.replace(/\D/g, ""),
2237
- number: (v) => {
2238
- const n = parseFloat(v);
2239
- return isNaN(n) ? "" : String(n);
2240
- },
2241
- currency: (v) => {
2242
- const n = parseFloat(v.replace(/[^0-9.-]/g, ""));
2243
- return isNaN(n) ? "" : `$${n.toFixed(2)}`;
2244
- }
2245
- };
2246
- var FORMULA_RE = /\{\{(.+?)\}\}/g;
2247
- var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
2248
- function resolveFormula(formula, fields, customTransforms) {
2249
- const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
2250
- return formula.replace(FORMULA_RE, (_match, expr) => {
2251
- const pipeMatch = expr.match(PIPE_RE);
2252
- const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
2253
- const transformName = pipeMatch ? pipeMatch[2].trim() : null;
2254
- const sourceField = fields.find((f) => f.label.toLowerCase() === sourceLabel.toLowerCase()) || fields.find((f) => f.id === sourceLabel);
2255
- if (!sourceField) return "";
2256
- const rawValue = sourceField.value || "";
2257
- if (!transformName) return rawValue;
2258
- const fn = transforms[transformName];
2259
- if (!fn) return rawValue;
2260
- try {
2261
- return fn(rawValue);
2262
- } catch {
2263
- return rawValue;
2264
- }
2265
- });
2266
- }
2267
- function resolveAllFormulas(fields, customTransforms) {
2268
- return fields.map((f) => {
2269
- if (!f.formula) return f;
2270
- const computed = resolveFormula(f.formula, fields, customTransforms);
2271
- return computed !== f.value ? { ...f, value: computed } : f;
2272
- });
2273
- }
2274
-
2275
2405
  // src/components/pdf-builder/SignerView.tsx
2276
2406
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2277
2407
  function SignerView({
@@ -2489,7 +2619,7 @@ function SignerView({
2489
2619
  let pdfBytes;
2490
2620
  if (includeAuditTrail) {
2491
2621
  const { PDFDocument: PDFDocument2, StandardFonts: StandardFonts2, rgb: rgb2 } = await import("pdf-lib");
2492
- const basePdf = await generateFilledPdf(pdfSource, finalFields);
2622
+ const basePdf = await generateFilledPdf({ pdfSource, fields: finalFields });
2493
2623
  const pdfDoc = await PDFDocument2.load(basePdf);
2494
2624
  const font = await pdfDoc.embedFont(StandardFonts2.Helvetica);
2495
2625
  const boldFont = await pdfDoc.embedFont(StandardFonts2.HelveticaBold);
@@ -2506,7 +2636,7 @@ function SignerView({
2506
2636
  }
2507
2637
  pdfBytes = await pdfDoc.save();
2508
2638
  } else {
2509
- pdfBytes = await generateFilledPdf(pdfSource, finalFields);
2639
+ pdfBytes = await generateFilledPdf({ pdfSource, fields: finalFields });
2510
2640
  }
2511
2641
  const blob = new Blob([pdfBytes.slice().buffer], { type: "application/pdf" });
2512
2642
  if (onExport && exportFormat) {
@@ -2828,7 +2958,9 @@ function SignerRoleSelector({
2828
2958
  ] });
2829
2959
  }
2830
2960
  export {
2961
+ A4,
2831
2962
  BUILTIN_TRANSFORMS,
2963
+ DEFAULT_CALIBRATION,
2832
2964
  DEFAULT_SIGNER_ROLES,
2833
2965
  DesignerView,
2834
2966
  FIELD_DEFAULTS,
@@ -2840,7 +2972,11 @@ export {
2840
2972
  SignatureCanvas,
2841
2973
  SignerRoleSelector,
2842
2974
  SignerView,
2975
+ US_LEGAL,
2976
+ US_LETTER,
2977
+ applyCalibration,
2843
2978
  createField,
2979
+ createPdfBuilder,
2844
2980
  downloadPdf,
2845
2981
  generateFilledPdf,
2846
2982
  generateId,