@unlev/exeq 0.5.0 → 0.5.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/dist/index.d.mts +27 -3
- package/dist/index.d.ts +27 -3
- package/dist/index.js +54 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -95,19 +95,39 @@ declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave,
|
|
|
95
95
|
|
|
96
96
|
type TransformFn = (value: string) => string;
|
|
97
97
|
type TransformMap = Record<string, TransformFn>;
|
|
98
|
+
/**
|
|
99
|
+
* Parse a date string robustly into a local Date (midnight, local TZ) so that
|
|
100
|
+
* getMonth/getDate/getFullYear are calendar-correct. Handles:
|
|
101
|
+
* - ISO date-only "YYYY-MM-DD" → parsed as LOCAL (avoids the classic UTC
|
|
102
|
+
* off-by-one where "2024-03-15" becomes the 14th in western timezones).
|
|
103
|
+
* - Excel serial numbers (a bare integer, e.g. "45000") → converted.
|
|
104
|
+
* - Anything else → native `new Date` (handles "M/D/YYYY", ISO datetimes, …).
|
|
105
|
+
* Returns null when unparseable.
|
|
106
|
+
*/
|
|
107
|
+
declare function parseDate(value: string): Date | null;
|
|
98
108
|
/** Built-in transforms that ship with exeq. */
|
|
99
109
|
declare const BUILTIN_TRANSFORMS: TransformMap;
|
|
100
110
|
/**
|
|
101
111
|
* Resolve a single formula string against a set of fields and transforms.
|
|
102
112
|
* Formula format: "{{Source Field Label | transform}}" or "{{Source Field Label}}" (no transform = raw value).
|
|
103
113
|
* Multiple expressions can appear in one formula: "{{First}} {{Last}}" → "Jane Smith"
|
|
114
|
+
*
|
|
115
|
+
* Source resolution order for "{{Name}}":
|
|
116
|
+
* 1. a placed field whose label (case-insensitive) or id matches Name
|
|
117
|
+
* 2. `values[Name]` — imported/contextual data not tied to a placed field
|
|
118
|
+
* 3. the built-in `today` / `now` source (current date)
|
|
119
|
+
*
|
|
120
|
+
* @param values Extra named values (e.g. imported CSV/form data) made available
|
|
121
|
+
* to formula sources even when there is no placed field for them.
|
|
104
122
|
*/
|
|
105
|
-
declare function resolveFormula(formula: string, fields: FormField[], customTransforms?: TransformMap): string;
|
|
123
|
+
declare function resolveFormula(formula: string, fields: FormField[], customTransforms?: TransformMap, values?: Record<string, string>): string;
|
|
106
124
|
/**
|
|
107
125
|
* Resolve all formula fields in a fields array.
|
|
108
126
|
* Returns a new array with computed values filled in.
|
|
127
|
+
*
|
|
128
|
+
* @param values Extra named values available to formula sources (see resolveFormula).
|
|
109
129
|
*/
|
|
110
|
-
declare function resolveAllFormulas(fields: FormField[], customTransforms?: TransformMap): FormField[];
|
|
130
|
+
declare function resolveAllFormulas(fields: FormField[], customTransforms?: TransformMap, values?: Record<string, string>): FormField[];
|
|
111
131
|
|
|
112
132
|
interface SignerViewProps {
|
|
113
133
|
/** API key for authentication */
|
|
@@ -283,6 +303,10 @@ interface FillPdfOptions {
|
|
|
283
303
|
/** Custom transforms merged with `BUILTIN_TRANSFORMS` during formula
|
|
284
304
|
* resolution. Only meaningful when `resolveFormulas` is true. */
|
|
285
305
|
customTransforms?: TransformMap;
|
|
306
|
+
/** Extra named values made available to formula sources (e.g. imported CSV/
|
|
307
|
+
* form data) even when there is no placed field for them. Only meaningful
|
|
308
|
+
* when `resolveFormulas` is true. */
|
|
309
|
+
formulaValues?: Record<string, string>;
|
|
286
310
|
/** Linear calibration applied to field positions before rendering. */
|
|
287
311
|
calibration?: Calibration;
|
|
288
312
|
}
|
|
@@ -335,4 +359,4 @@ declare function createPdfBuilder(defaults?: CreatePdfBuilderOptions): Promise<P
|
|
|
335
359
|
declare function downloadPdf(bytes: Uint8Array, filename: string): void;
|
|
336
360
|
declare function postPdfToCallback(bytes: Uint8Array, callbackUrl: string, filename: string): Promise<void>;
|
|
337
361
|
|
|
338
|
-
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 };
|
|
362
|
+
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, parseDate, postPdfToCallback, preserveFieldValues, renderPdfPages, resolveAllFormulas, resolveFormula, sortFieldsByPosition, uniqueLabel };
|
package/dist/index.d.ts
CHANGED
|
@@ -95,19 +95,39 @@ declare function DesignerView({ apiKey, initialPdfUrl, initialTemplate, onSave,
|
|
|
95
95
|
|
|
96
96
|
type TransformFn = (value: string) => string;
|
|
97
97
|
type TransformMap = Record<string, TransformFn>;
|
|
98
|
+
/**
|
|
99
|
+
* Parse a date string robustly into a local Date (midnight, local TZ) so that
|
|
100
|
+
* getMonth/getDate/getFullYear are calendar-correct. Handles:
|
|
101
|
+
* - ISO date-only "YYYY-MM-DD" → parsed as LOCAL (avoids the classic UTC
|
|
102
|
+
* off-by-one where "2024-03-15" becomes the 14th in western timezones).
|
|
103
|
+
* - Excel serial numbers (a bare integer, e.g. "45000") → converted.
|
|
104
|
+
* - Anything else → native `new Date` (handles "M/D/YYYY", ISO datetimes, …).
|
|
105
|
+
* Returns null when unparseable.
|
|
106
|
+
*/
|
|
107
|
+
declare function parseDate(value: string): Date | null;
|
|
98
108
|
/** Built-in transforms that ship with exeq. */
|
|
99
109
|
declare const BUILTIN_TRANSFORMS: TransformMap;
|
|
100
110
|
/**
|
|
101
111
|
* Resolve a single formula string against a set of fields and transforms.
|
|
102
112
|
* Formula format: "{{Source Field Label | transform}}" or "{{Source Field Label}}" (no transform = raw value).
|
|
103
113
|
* Multiple expressions can appear in one formula: "{{First}} {{Last}}" → "Jane Smith"
|
|
114
|
+
*
|
|
115
|
+
* Source resolution order for "{{Name}}":
|
|
116
|
+
* 1. a placed field whose label (case-insensitive) or id matches Name
|
|
117
|
+
* 2. `values[Name]` — imported/contextual data not tied to a placed field
|
|
118
|
+
* 3. the built-in `today` / `now` source (current date)
|
|
119
|
+
*
|
|
120
|
+
* @param values Extra named values (e.g. imported CSV/form data) made available
|
|
121
|
+
* to formula sources even when there is no placed field for them.
|
|
104
122
|
*/
|
|
105
|
-
declare function resolveFormula(formula: string, fields: FormField[], customTransforms?: TransformMap): string;
|
|
123
|
+
declare function resolveFormula(formula: string, fields: FormField[], customTransforms?: TransformMap, values?: Record<string, string>): string;
|
|
106
124
|
/**
|
|
107
125
|
* Resolve all formula fields in a fields array.
|
|
108
126
|
* Returns a new array with computed values filled in.
|
|
127
|
+
*
|
|
128
|
+
* @param values Extra named values available to formula sources (see resolveFormula).
|
|
109
129
|
*/
|
|
110
|
-
declare function resolveAllFormulas(fields: FormField[], customTransforms?: TransformMap): FormField[];
|
|
130
|
+
declare function resolveAllFormulas(fields: FormField[], customTransforms?: TransformMap, values?: Record<string, string>): FormField[];
|
|
111
131
|
|
|
112
132
|
interface SignerViewProps {
|
|
113
133
|
/** API key for authentication */
|
|
@@ -283,6 +303,10 @@ interface FillPdfOptions {
|
|
|
283
303
|
/** Custom transforms merged with `BUILTIN_TRANSFORMS` during formula
|
|
284
304
|
* resolution. Only meaningful when `resolveFormulas` is true. */
|
|
285
305
|
customTransforms?: TransformMap;
|
|
306
|
+
/** Extra named values made available to formula sources (e.g. imported CSV/
|
|
307
|
+
* form data) even when there is no placed field for them. Only meaningful
|
|
308
|
+
* when `resolveFormulas` is true. */
|
|
309
|
+
formulaValues?: Record<string, string>;
|
|
286
310
|
/** Linear calibration applied to field positions before rendering. */
|
|
287
311
|
calibration?: Calibration;
|
|
288
312
|
}
|
|
@@ -335,4 +359,4 @@ declare function createPdfBuilder(defaults?: CreatePdfBuilderOptions): Promise<P
|
|
|
335
359
|
declare function downloadPdf(bytes: Uint8Array, filename: string): void;
|
|
336
360
|
declare function postPdfToCallback(bytes: Uint8Array, callbackUrl: string, filename: string): Promise<void>;
|
|
337
361
|
|
|
338
|
-
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 };
|
|
362
|
+
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, parseDate, postPdfToCallback, preserveFieldValues, renderPdfPages, resolveAllFormulas, resolveFormula, sortFieldsByPosition, uniqueLabel };
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ __export(lib_exports, {
|
|
|
59
59
|
isRedactField: () => isRedactField,
|
|
60
60
|
isSignatureField: () => isSignatureField,
|
|
61
61
|
isTextLikeField: () => isTextLikeField,
|
|
62
|
+
parseDate: () => parseDate,
|
|
62
63
|
postPdfToCallback: () => postPdfToCallback,
|
|
63
64
|
preserveFieldValues: () => preserveFieldValues,
|
|
64
65
|
renderPdfPages: () => renderPdfPages,
|
|
@@ -2160,39 +2161,56 @@ var import_react7 = require("react");
|
|
|
2160
2161
|
var import_pdf_lib = require("pdf-lib");
|
|
2161
2162
|
|
|
2162
2163
|
// src/utils/formulaResolver.ts
|
|
2164
|
+
function parseDate(value) {
|
|
2165
|
+
const s = value.trim();
|
|
2166
|
+
if (!s) return null;
|
|
2167
|
+
if (/^\d+(\.\d+)?$/.test(s)) {
|
|
2168
|
+
const serial = parseFloat(s);
|
|
2169
|
+
if (serial > 59) {
|
|
2170
|
+
const utc = new Date(Math.round((serial - 25569) * 864e5));
|
|
2171
|
+
if (!isNaN(utc.getTime())) {
|
|
2172
|
+
return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
const iso = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
2177
|
+
if (iso) return new Date(+iso[1], +iso[2] - 1, +iso[3]);
|
|
2178
|
+
const d = new Date(s);
|
|
2179
|
+
return isNaN(d.getTime()) ? null : d;
|
|
2180
|
+
}
|
|
2163
2181
|
var BUILTIN_TRANSFORMS = {
|
|
2164
2182
|
// Date transforms (expects a parseable date string)
|
|
2165
2183
|
month: (v) => {
|
|
2166
|
-
const d =
|
|
2167
|
-
return
|
|
2184
|
+
const d = parseDate(v);
|
|
2185
|
+
return d ? String(d.getMonth() + 1) : "";
|
|
2168
2186
|
},
|
|
2169
2187
|
month2: (v) => {
|
|
2170
|
-
const d =
|
|
2171
|
-
return
|
|
2188
|
+
const d = parseDate(v);
|
|
2189
|
+
return d ? String(d.getMonth() + 1).padStart(2, "0") : "";
|
|
2172
2190
|
},
|
|
2173
2191
|
monthname: (v) => {
|
|
2174
|
-
const d =
|
|
2175
|
-
return
|
|
2192
|
+
const d = parseDate(v);
|
|
2193
|
+
return d ? d.toLocaleString("en", { month: "long" }) : "";
|
|
2176
2194
|
},
|
|
2177
2195
|
monthshort: (v) => {
|
|
2178
|
-
const d =
|
|
2179
|
-
return
|
|
2196
|
+
const d = parseDate(v);
|
|
2197
|
+
return d ? d.toLocaleString("en", { month: "short" }) : "";
|
|
2180
2198
|
},
|
|
2181
2199
|
day: (v) => {
|
|
2182
|
-
const d =
|
|
2183
|
-
return
|
|
2200
|
+
const d = parseDate(v);
|
|
2201
|
+
return d ? String(d.getDate()) : "";
|
|
2184
2202
|
},
|
|
2185
2203
|
day2: (v) => {
|
|
2186
|
-
const d =
|
|
2187
|
-
return
|
|
2204
|
+
const d = parseDate(v);
|
|
2205
|
+
return d ? String(d.getDate()).padStart(2, "0") : "";
|
|
2188
2206
|
},
|
|
2189
2207
|
year: (v) => {
|
|
2190
|
-
const d =
|
|
2191
|
-
return
|
|
2208
|
+
const d = parseDate(v);
|
|
2209
|
+
return d ? String(d.getFullYear()) : "";
|
|
2192
2210
|
},
|
|
2193
2211
|
year2: (v) => {
|
|
2194
|
-
const d =
|
|
2195
|
-
return
|
|
2212
|
+
const d = parseDate(v);
|
|
2213
|
+
return d ? String(d.getFullYear()).slice(-2) : "";
|
|
2196
2214
|
},
|
|
2197
2215
|
// String transforms
|
|
2198
2216
|
upper: (v) => v.toUpperCase(),
|
|
@@ -2221,15 +2239,27 @@ var BUILTIN_TRANSFORMS = {
|
|
|
2221
2239
|
};
|
|
2222
2240
|
var FORMULA_RE = /\{\{(.+?)\}\}/g;
|
|
2223
2241
|
var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
|
|
2224
|
-
function
|
|
2242
|
+
function todayIso() {
|
|
2243
|
+
const d = /* @__PURE__ */ new Date();
|
|
2244
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
2245
|
+
}
|
|
2246
|
+
function resolveFormula(formula, fields, customTransforms, values) {
|
|
2225
2247
|
const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
|
|
2226
2248
|
return formula.replace(FORMULA_RE, (_match, expr) => {
|
|
2227
2249
|
const pipeMatch = expr.match(PIPE_RE);
|
|
2228
2250
|
const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
|
|
2229
2251
|
const transformName = pipeMatch ? pipeMatch[2].trim() : null;
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2252
|
+
const lowerLabel = sourceLabel.toLowerCase();
|
|
2253
|
+
const sourceField = fields.find((f) => f.label.toLowerCase() === lowerLabel) || fields.find((f) => f.id === sourceLabel);
|
|
2254
|
+
let rawValue = sourceField ? sourceField.value || "" : void 0;
|
|
2255
|
+
if (rawValue === void 0 && values) {
|
|
2256
|
+
const key = Object.keys(values).find((k) => k.toLowerCase() === lowerLabel);
|
|
2257
|
+
if (key !== void 0) rawValue = values[key] || "";
|
|
2258
|
+
}
|
|
2259
|
+
if (rawValue === void 0 && (lowerLabel === "today" || lowerLabel === "now")) {
|
|
2260
|
+
rawValue = todayIso();
|
|
2261
|
+
}
|
|
2262
|
+
if (rawValue === void 0) return "";
|
|
2233
2263
|
if (!transformName) return rawValue;
|
|
2234
2264
|
const fn = transforms[transformName];
|
|
2235
2265
|
if (!fn) return rawValue;
|
|
@@ -2240,10 +2270,10 @@ function resolveFormula(formula, fields, customTransforms) {
|
|
|
2240
2270
|
}
|
|
2241
2271
|
});
|
|
2242
2272
|
}
|
|
2243
|
-
function resolveAllFormulas(fields, customTransforms) {
|
|
2273
|
+
function resolveAllFormulas(fields, customTransforms, values) {
|
|
2244
2274
|
return fields.map((f) => {
|
|
2245
2275
|
if (!f.formula) return f;
|
|
2246
|
-
const computed = resolveFormula(f.formula, fields, customTransforms);
|
|
2276
|
+
const computed = resolveFormula(f.formula, fields, customTransforms, values);
|
|
2247
2277
|
return computed !== f.value ? { ...f, value: computed } : f;
|
|
2248
2278
|
});
|
|
2249
2279
|
}
|
|
@@ -2450,7 +2480,7 @@ async function createPdfBuilder(defaults = {}) {
|
|
|
2450
2480
|
doc,
|
|
2451
2481
|
async addRecord(opts) {
|
|
2452
2482
|
const pageSize = opts.pageSize ?? defaults.pageSize;
|
|
2453
|
-
let fields = opts.resolveFormulas ? resolveAllFormulas(opts.fields, opts.customTransforms) : opts.fields;
|
|
2483
|
+
let fields = opts.resolveFormulas ? resolveAllFormulas(opts.fields, opts.customTransforms, opts.formulaValues) : opts.fields;
|
|
2454
2484
|
if (opts.calibration) {
|
|
2455
2485
|
fields = applyCalibration(
|
|
2456
2486
|
fields,
|
|
@@ -3173,6 +3203,7 @@ function SignerRoleSelector({
|
|
|
3173
3203
|
isRedactField,
|
|
3174
3204
|
isSignatureField,
|
|
3175
3205
|
isTextLikeField,
|
|
3206
|
+
parseDate,
|
|
3176
3207
|
postPdfToCallback,
|
|
3177
3208
|
preserveFieldValues,
|
|
3178
3209
|
renderPdfPages,
|