@unlev/exeq 0.5.5 → 0.5.7
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.css +5 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +90 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +90 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -60,11 +60,17 @@ function getCssTextStyle(field) {
|
|
|
60
60
|
const decorations = [];
|
|
61
61
|
if (field.underline) decorations.push("underline");
|
|
62
62
|
if (field.strikethrough) decorations.push("line-through");
|
|
63
|
+
const align = field.align ?? "left";
|
|
63
64
|
return {
|
|
64
65
|
fontFamily: getCssFontFamily(field.fontFamily),
|
|
65
66
|
fontWeight: field.bold ? "bold" : void 0,
|
|
66
67
|
fontStyle: field.italic ? "italic" : void 0,
|
|
67
|
-
textDecorationLine: decorations.length ? decorations.join(" ") : void 0
|
|
68
|
+
textDecorationLine: decorations.length ? decorations.join(" ") : void 0,
|
|
69
|
+
textAlign: field.align,
|
|
70
|
+
// Hug the alignment edge — no padding on the trailing side — so text reaches
|
|
71
|
+
// the container edge (matches the PDF's 2pt offsets).
|
|
72
|
+
paddingLeft: align === "right" ? "0px" : "2px",
|
|
73
|
+
paddingRight: align === "left" ? "0px" : "2px"
|
|
68
74
|
};
|
|
69
75
|
}
|
|
70
76
|
function sortFieldsByPosition(fields) {
|
|
@@ -735,6 +741,27 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
|
|
|
735
741
|
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.strikethrough ? "active" : ""}`, style: { textDecorationLine: "line-through" }, title: "Strikethrough", onClick: () => onUpdate(field.id, { strikethrough: !field.strikethrough }), children: "S" })
|
|
736
742
|
] })
|
|
737
743
|
] }),
|
|
744
|
+
isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
|
|
745
|
+
/* @__PURE__ */ jsx2("label", { children: "Alignment" }),
|
|
746
|
+
/* @__PURE__ */ jsx2("div", { className: "text-format-buttons", children: [
|
|
747
|
+
["left", "Left", "\u2AF7"],
|
|
748
|
+
["center", "Center", "\u2261"],
|
|
749
|
+
["right", "Right", "\u2AF8"]
|
|
750
|
+
].map(([value, label, glyph]) => {
|
|
751
|
+
const active = (field.align || "left") === value;
|
|
752
|
+
return /* @__PURE__ */ jsx2(
|
|
753
|
+
"button",
|
|
754
|
+
{
|
|
755
|
+
type: "button",
|
|
756
|
+
className: `text-format-btn ${active ? "active" : ""}`,
|
|
757
|
+
title: `Align ${label}`,
|
|
758
|
+
onClick: () => onUpdate(field.id, { align: value === "left" ? void 0 : value }),
|
|
759
|
+
children: glyph
|
|
760
|
+
},
|
|
761
|
+
value
|
|
762
|
+
);
|
|
763
|
+
}) })
|
|
764
|
+
] }),
|
|
738
765
|
isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field-row", children: [
|
|
739
766
|
/* @__PURE__ */ jsxs2("div", { className: "panel-field panel-field-half", children: [
|
|
740
767
|
/* @__PURE__ */ jsx2("label", { children: "Letter Spacing" }),
|
|
@@ -2158,6 +2185,20 @@ var BUILTIN_TRANSFORMS = {
|
|
|
2158
2185
|
return parts[parts.length - 1] || "";
|
|
2159
2186
|
},
|
|
2160
2187
|
initials: (v) => v.split(/\s+/).map((w) => w[0] || "").join("").toUpperCase(),
|
|
2188
|
+
// Name parts. Handles "Last, First [Middle]" (comma form) and "First [Middle]
|
|
2189
|
+
// Last" (no comma). firstName → the given name(s); lastName → the surname.
|
|
2190
|
+
firstName: (v) => {
|
|
2191
|
+
const c = v.indexOf(",");
|
|
2192
|
+
if (c >= 0) return v.slice(c + 1).trim();
|
|
2193
|
+
const parts = v.trim().split(/\s+/).filter(Boolean);
|
|
2194
|
+
return parts.length > 1 ? parts.slice(0, -1).join(" ") : parts[0] || "";
|
|
2195
|
+
},
|
|
2196
|
+
lastName: (v) => {
|
|
2197
|
+
const c = v.indexOf(",");
|
|
2198
|
+
if (c >= 0) return v.slice(0, c).trim();
|
|
2199
|
+
const parts = v.trim().split(/\s+/).filter(Boolean);
|
|
2200
|
+
return parts.length > 1 ? parts[parts.length - 1] : parts[0] || "";
|
|
2201
|
+
},
|
|
2161
2202
|
// Numeric / substring
|
|
2162
2203
|
last4: (v) => v.slice(-4),
|
|
2163
2204
|
last2: (v) => v.slice(-2),
|
|
@@ -2187,11 +2228,17 @@ function resolveFormula(formula, fields, customTransforms, values) {
|
|
|
2187
2228
|
const transformName = pipeMatch ? pipeMatch[2].trim() : null;
|
|
2188
2229
|
const lowerLabel = sourceLabel.toLowerCase();
|
|
2189
2230
|
const sourceField = fields.find((f) => f.label.toLowerCase() === lowerLabel) || fields.find((f) => f.id === sourceLabel);
|
|
2190
|
-
let rawValue
|
|
2231
|
+
let rawValue;
|
|
2232
|
+
if (sourceField && sourceField.value) {
|
|
2233
|
+
rawValue = sourceField.value;
|
|
2234
|
+
}
|
|
2191
2235
|
if (rawValue === void 0 && values) {
|
|
2192
2236
|
const key = Object.keys(values).find((k) => k.toLowerCase() === lowerLabel);
|
|
2193
2237
|
if (key !== void 0) rawValue = values[key] || "";
|
|
2194
2238
|
}
|
|
2239
|
+
if (rawValue === void 0 && sourceField) {
|
|
2240
|
+
rawValue = sourceField.value || "";
|
|
2241
|
+
}
|
|
2195
2242
|
if (rawValue === void 0 && (lowerLabel === "today" || lowerLabel === "now")) {
|
|
2196
2243
|
rawValue = todayIso();
|
|
2197
2244
|
}
|
|
@@ -2326,7 +2373,9 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
|
|
|
2326
2373
|
fieldHeightPt: h,
|
|
2327
2374
|
measure: textWidthAtSize
|
|
2328
2375
|
});
|
|
2329
|
-
const
|
|
2376
|
+
const fullTextWidth = textWidthAtSize(field.value, fontSize);
|
|
2377
|
+
const pad = 2;
|
|
2378
|
+
const textX = field.align === "center" ? x + Math.max(pad, (w - fullTextWidth) / 2) : field.align === "right" ? x + Math.max(pad, w - fullTextWidth - pad) : x + pad;
|
|
2330
2379
|
const baselineY = y + h * 0.3;
|
|
2331
2380
|
if (spacing > 0) {
|
|
2332
2381
|
let cx = textX;
|
|
@@ -2580,37 +2629,54 @@ function FieldNavigator({
|
|
|
2580
2629
|
// src/components/pdf-builder/SignerView.tsx
|
|
2581
2630
|
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2582
2631
|
var useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect3;
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2632
|
+
var measureCtx = null;
|
|
2633
|
+
function fitFont(el, box, maxPt, text, shrink) {
|
|
2634
|
+
if (!shrink || typeof document === "undefined") {
|
|
2635
|
+
el.style.fontSize = `${maxPt}pt`;
|
|
2636
|
+
return;
|
|
2637
|
+
}
|
|
2638
|
+
if (!measureCtx) measureCtx = document.createElement("canvas").getContext("2d");
|
|
2639
|
+
const boxStyle = getComputedStyle(box);
|
|
2640
|
+
const padX = (parseFloat(boxStyle.paddingLeft) || 0) + (parseFloat(boxStyle.paddingRight) || 0);
|
|
2641
|
+
const avail = box.clientWidth - padX - 1;
|
|
2642
|
+
if (!text || !measureCtx || avail <= 0) {
|
|
2643
|
+
el.style.fontSize = `${maxPt}pt`;
|
|
2644
|
+
return;
|
|
2645
|
+
}
|
|
2646
|
+
const cs = getComputedStyle(el);
|
|
2647
|
+
const PX_PER_PT = 96 / 72;
|
|
2587
2648
|
let pt = Math.max(1, maxPt);
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2649
|
+
while (pt > 2) {
|
|
2650
|
+
measureCtx.font = `${cs.fontStyle} ${cs.fontWeight} ${pt * PX_PER_PT}px ${cs.fontFamily}`;
|
|
2651
|
+
if (measureCtx.measureText(text).width <= avail) break;
|
|
2591
2652
|
pt -= 0.5;
|
|
2592
|
-
el.style.fontSize = `${pt}pt`;
|
|
2593
2653
|
}
|
|
2654
|
+
el.style.fontSize = `${pt}pt`;
|
|
2594
2655
|
}
|
|
2595
2656
|
function FitInput({
|
|
2596
2657
|
maxPt,
|
|
2658
|
+
shrink,
|
|
2597
2659
|
...rest
|
|
2598
2660
|
}) {
|
|
2599
2661
|
const ref = useRef5(null);
|
|
2600
2662
|
useIsoLayoutEffect(() => {
|
|
2601
|
-
|
|
2663
|
+
const el = ref.current;
|
|
2664
|
+
if (el) fitFont(el, el, maxPt, String(el.value ?? ""), shrink);
|
|
2602
2665
|
});
|
|
2603
2666
|
return /* @__PURE__ */ jsx6("input", { ref, ...rest });
|
|
2604
2667
|
}
|
|
2605
2668
|
function FitText({
|
|
2606
2669
|
maxPt,
|
|
2670
|
+
shrink,
|
|
2607
2671
|
className,
|
|
2608
2672
|
style,
|
|
2609
2673
|
children
|
|
2610
2674
|
}) {
|
|
2611
2675
|
const ref = useRef5(null);
|
|
2612
2676
|
useIsoLayoutEffect(() => {
|
|
2613
|
-
|
|
2677
|
+
const el = ref.current;
|
|
2678
|
+
const box = el?.parentElement;
|
|
2679
|
+
if (el && box) fitFont(el, box, maxPt, el.textContent ?? "", shrink);
|
|
2614
2680
|
});
|
|
2615
2681
|
return /* @__PURE__ */ jsx6("div", { ref, className, style, children });
|
|
2616
2682
|
}
|
|
@@ -2869,8 +2935,13 @@ ${row.join(",")}`, "csv");
|
|
|
2869
2935
|
if (isRedactField(field)) {
|
|
2870
2936
|
return null;
|
|
2871
2937
|
}
|
|
2938
|
+
const textStyle = {
|
|
2939
|
+
letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
|
|
2940
|
+
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
|
|
2941
|
+
...getCssTextStyle(field)
|
|
2942
|
+
};
|
|
2872
2943
|
if (field.formula) {
|
|
2873
|
-
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, className: "field-overlay-value formula", style:
|
|
2944
|
+
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, shrink: !!field.autoShrink, className: "field-overlay-value formula", style: textStyle, children: field.value || "" });
|
|
2874
2945
|
}
|
|
2875
2946
|
const editable = field.assignee === signer;
|
|
2876
2947
|
if (!editable) {
|
|
@@ -2880,7 +2951,7 @@ ${row.join(",")}`, "csv");
|
|
|
2880
2951
|
if (field.type === "checkbox") {
|
|
2881
2952
|
return /* @__PURE__ */ jsx6("div", { className: "field-checkbox-display readonly", children: field.value === "true" ? "\u2713" : "" });
|
|
2882
2953
|
}
|
|
2883
|
-
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, className: "field-overlay-placeholder readonly", style:
|
|
2954
|
+
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, shrink: !!field.autoShrink, className: "field-overlay-placeholder readonly", style: textStyle, children: field.value || field.placeholder });
|
|
2884
2955
|
}
|
|
2885
2956
|
if (isSignatureField(field)) {
|
|
2886
2957
|
if (field.value) {
|
|
@@ -2902,13 +2973,8 @@ ${row.join(",")}`, "csv");
|
|
|
2902
2973
|
);
|
|
2903
2974
|
}
|
|
2904
2975
|
if (field.type === "signed-date") {
|
|
2905
|
-
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, className: "field-overlay-value", style:
|
|
2976
|
+
return /* @__PURE__ */ jsx6(FitText, { maxPt: field.fontSize, shrink: !!field.autoShrink, className: "field-overlay-value", style: textStyle, children: field.value || (/* @__PURE__ */ new Date()).toLocaleDateString() });
|
|
2906
2977
|
}
|
|
2907
|
-
const fontStyle = {
|
|
2908
|
-
letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
|
|
2909
|
-
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
|
|
2910
|
-
...getCssTextStyle(field)
|
|
2911
|
-
};
|
|
2912
2978
|
if (field.type === "dropdown" || field.options && field.options.length > 0) {
|
|
2913
2979
|
return /* @__PURE__ */ jsxs6(
|
|
2914
2980
|
"select",
|
|
@@ -2918,7 +2984,7 @@ ${row.join(",")}`, "csv");
|
|
|
2918
2984
|
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
2919
2985
|
onFocus: () => setSelectedFieldId(field.id),
|
|
2920
2986
|
onClick: (e) => e.stopPropagation(),
|
|
2921
|
-
style: { fontSize: `${field.fontSize}pt`, ...
|
|
2987
|
+
style: { fontSize: `${field.fontSize}pt`, ...textStyle },
|
|
2922
2988
|
children: [
|
|
2923
2989
|
/* @__PURE__ */ jsx6("option", { value: "", children: field.placeholder || "Select..." }),
|
|
2924
2990
|
(field.options || []).map((opt) => /* @__PURE__ */ jsx6("option", { value: opt, children: opt }, opt))
|
|
@@ -2930,6 +2996,7 @@ ${row.join(",")}`, "csv");
|
|
|
2930
2996
|
FitInput,
|
|
2931
2997
|
{
|
|
2932
2998
|
maxPt: field.fontSize,
|
|
2999
|
+
shrink: !!field.autoShrink,
|
|
2933
3000
|
type: field.textSubtype === "email" ? "email" : field.textSubtype === "number" ? "number" : field.textSubtype === "phone" ? "tel" : field.textSubtype === "date" ? "date" : "text",
|
|
2934
3001
|
className: "field-inline-input",
|
|
2935
3002
|
value: field.value,
|
|
@@ -2938,7 +3005,7 @@ ${row.join(",")}`, "csv");
|
|
|
2938
3005
|
onChange: (e) => handleFieldUpdate(field.id, e.target.value),
|
|
2939
3006
|
onFocus: () => setSelectedFieldId(field.id),
|
|
2940
3007
|
onClick: (e) => e.stopPropagation(),
|
|
2941
|
-
style:
|
|
3008
|
+
style: textStyle
|
|
2942
3009
|
}
|
|
2943
3010
|
);
|
|
2944
3011
|
}, [signer, handleFieldUpdate, setSelectedFieldId]);
|