@unlev/exeq 0.4.1 → 0.5.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.mjs CHANGED
@@ -56,6 +56,17 @@ var CSS_FONT_MAP = {
56
56
  function getCssFontFamily(fontFamily) {
57
57
  return fontFamily ? CSS_FONT_MAP[fontFamily] : void 0;
58
58
  }
59
+ function getCssTextStyle(field) {
60
+ const decorations = [];
61
+ if (field.underline) decorations.push("underline");
62
+ if (field.strikethrough) decorations.push("line-through");
63
+ return {
64
+ fontFamily: getCssFontFamily(field.fontFamily),
65
+ fontWeight: field.bold ? "bold" : void 0,
66
+ fontStyle: field.italic ? "italic" : void 0,
67
+ textDecorationLine: decorations.length ? decorations.join(" ") : void 0
68
+ };
69
+ }
59
70
  function sortFieldsByPosition(fields) {
60
71
  return [...fields].sort((a, b) => {
61
72
  if (a.page !== b.page) return a.page - b.page;
@@ -711,6 +722,15 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
711
722
  /* @__PURE__ */ jsx2("label", { children: "Font Size (pt)" }),
712
723
  /* @__PURE__ */ jsx2("input", { type: "number", min: "6", max: "72", value: field.fontSize, onChange: (e) => onUpdate(field.id, { fontSize: Number(e.target.value) }) })
713
724
  ] }),
725
+ isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
726
+ /* @__PURE__ */ jsx2("label", { children: "Formatting" }),
727
+ /* @__PURE__ */ jsxs2("div", { className: "text-format-buttons", children: [
728
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.bold ? "active" : ""}`, style: { fontWeight: "bold" }, title: "Bold", onClick: () => onUpdate(field.id, { bold: !field.bold }), children: "B" }),
729
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.italic ? "active" : ""}`, style: { fontStyle: "italic" }, title: "Italic", onClick: () => onUpdate(field.id, { italic: !field.italic }), children: "I" }),
730
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.underline ? "active" : ""}`, style: { textDecorationLine: "underline" }, title: "Underline", onClick: () => onUpdate(field.id, { underline: !field.underline }), children: "U" }),
731
+ /* @__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" })
732
+ ] })
733
+ ] }),
714
734
  isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field-row", children: [
715
735
  /* @__PURE__ */ jsxs2("div", { className: "panel-field panel-field-half", children: [
716
736
  /* @__PURE__ */ jsx2("label", { children: "Letter Spacing" }),
@@ -783,6 +803,10 @@ function BulkPropertyPanel({ fields, signerRoles, onUpdate, onAlign, onDelete })
783
803
  const sharedInkColor = sharedValue(fields.map((f) => f.inkColor || "#000000"));
784
804
  const sharedLetterSpacing = sharedValue(fields.map((f) => f.letterSpacing || 0));
785
805
  const sharedLineHeight = sharedValue(fields.map((f) => f.lineHeight || 1.2));
806
+ const allBold = fields.every((f) => f.bold);
807
+ const allItalic = fields.every((f) => f.italic);
808
+ const allUnderline = fields.every((f) => f.underline);
809
+ const allStrike = fields.every((f) => f.strikethrough);
786
810
  return /* @__PURE__ */ jsxs2("div", { className: "field-property-panel", children: [
787
811
  /* @__PURE__ */ jsxs2("div", { className: "panel-header", children: [
788
812
  /* @__PURE__ */ jsxs2("h3", { children: [
@@ -897,6 +921,15 @@ function BulkPropertyPanel({ fields, signerRoles, onUpdate, onAlign, onDelete })
897
921
  }
898
922
  )
899
923
  ] }),
924
+ hasText && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
925
+ /* @__PURE__ */ jsx2("label", { children: "Formatting" }),
926
+ /* @__PURE__ */ jsxs2("div", { className: "text-format-buttons", children: [
927
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allBold ? "active" : ""}`, style: { fontWeight: "bold" }, title: "Bold", onClick: () => onUpdate({ bold: !allBold }), children: "B" }),
928
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allItalic ? "active" : ""}`, style: { fontStyle: "italic" }, title: "Italic", onClick: () => onUpdate({ italic: !allItalic }), children: "I" }),
929
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allUnderline ? "active" : ""}`, style: { textDecorationLine: "underline" }, title: "Underline", onClick: () => onUpdate({ underline: !allUnderline }), children: "U" }),
930
+ /* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allStrike ? "active" : ""}`, style: { textDecorationLine: "line-through" }, title: "Strikethrough", onClick: () => onUpdate({ strikethrough: !allStrike }), children: "S" })
931
+ ] })
932
+ ] }),
900
933
  hasText && /* @__PURE__ */ jsxs2("div", { className: "panel-field-row", children: [
901
934
  /* @__PURE__ */ jsxs2("div", { className: "panel-field panel-field-half", children: [
902
935
  /* @__PURE__ */ jsx2("label", { children: "Letter Spacing" }),
@@ -1679,7 +1712,6 @@ function DesignerView({
1679
1712
  }
1680
1713
  }
1681
1714
  const inkColor = field.inkColor || "#000000";
1682
- const cssFontFamily = getCssFontFamily(field.fontFamily);
1683
1715
  return /* @__PURE__ */ jsx4(
1684
1716
  "div",
1685
1717
  {
@@ -1687,9 +1719,9 @@ function DesignerView({
1687
1719
  style: {
1688
1720
  color: field.value ? inkColor : void 0,
1689
1721
  fontSize: `${field.fontSize}pt`,
1690
- fontFamily: cssFontFamily,
1691
1722
  letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
1692
- lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0
1723
+ lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
1724
+ ...getCssTextStyle(field)
1693
1725
  },
1694
1726
  children: field.value || field.placeholder
1695
1727
  }
@@ -1704,7 +1736,6 @@ function DesignerView({
1704
1736
  ] }) : null;
1705
1737
  return /* @__PURE__ */ jsxs4("div", { className: "designer-layout", children: [
1706
1738
  headerPortalRef?.current && headerButtons && createPortal(headerButtons, headerPortalRef.current),
1707
- !hideHeader && !headerPortalRef && /* @__PURE__ */ jsx4("div", { className: "designer-header", children: /* @__PURE__ */ jsx4("div", { className: "designer-header-right", children: headerButtons }) }),
1708
1739
  /* @__PURE__ */ jsxs4("div", { className: "designer-body", children: [
1709
1740
  pages.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "designer-palette", children: [
1710
1741
  /* @__PURE__ */ jsx4("div", { className: "palette-heading", children: "New Field Role" }),
@@ -1818,6 +1849,7 @@ function DesignerView({
1818
1849
  pages.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1819
1850
  /* @__PURE__ */ jsx4("div", { className: "panel-resize-handle", onMouseDown: handleResizeStart }),
1820
1851
  /* @__PURE__ */ jsxs4("div", { className: "designer-panel", style: { width: panelWidth }, children: [
1852
+ !hideHeader && !headerPortalRef && headerButtons && /* @__PURE__ */ jsx4("div", { className: "designer-panel-actions", children: headerButtons }),
1821
1853
  /* @__PURE__ */ jsxs4("div", { className: "designer-panel-header", children: [
1822
1854
  /* @__PURE__ */ jsxs4("div", { className: "signer-role-indicator", children: [
1823
1855
  /* @__PURE__ */ jsx4("span", { className: "signer-role-indicator-label", children: "Editing as" }),
@@ -2150,11 +2182,19 @@ function resolveAllFormulas(fields, customTransforms) {
2150
2182
  }
2151
2183
 
2152
2184
  // src/utils/pdfFiller.ts
2153
- var FONT_MAP = {
2154
- Helvetica: StandardFonts.Helvetica,
2155
- Courier: StandardFonts.Courier,
2156
- TimesRoman: StandardFonts.TimesRoman
2185
+ var FONT_VARIANTS = {
2186
+ Helvetica: [StandardFonts.Helvetica, StandardFonts.HelveticaBold, StandardFonts.HelveticaOblique, StandardFonts.HelveticaBoldOblique],
2187
+ Courier: [StandardFonts.Courier, StandardFonts.CourierBold, StandardFonts.CourierOblique, StandardFonts.CourierBoldOblique],
2188
+ TimesRoman: [StandardFonts.TimesRoman, StandardFonts.TimesRomanBold, StandardFonts.TimesRomanItalic, StandardFonts.TimesRomanBoldItalic]
2157
2189
  };
2190
+ function resolveStandardFont(family, bold, italic) {
2191
+ const variants = FONT_VARIANTS[family] || FONT_VARIANTS.Helvetica;
2192
+ const idx = (bold ? 1 : 0) + (italic ? 2 : 0);
2193
+ return variants[idx];
2194
+ }
2195
+ function fontKey(family, bold, italic) {
2196
+ return `${family}|${bold ? "b" : ""}|${italic ? "i" : ""}`;
2197
+ }
2158
2198
  var US_LETTER = [612, 792];
2159
2199
  var US_LEGAL = [612, 1008];
2160
2200
  var A4 = [595.28, 841.89];
@@ -2229,7 +2269,7 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
2229
2269
  page.drawImage(img, { x, y, width: w, height: h });
2230
2270
  }
2231
2271
  } else {
2232
- const font = await getFont(field.fontFamily || "Helvetica");
2272
+ const font = await getFont(field.fontFamily || "Helvetica", field.bold, field.italic);
2233
2273
  const spacing = field.letterSpacing || 0;
2234
2274
  const textWidthAtSize = (text, size) => font.widthOfTextAtSize(text, size) + spacing * (text.length - 1);
2235
2275
  let fontSize = field.autoShrink ? Math.min(field.fontSize, h * 0.7) : field.fontSize;
@@ -2240,13 +2280,14 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
2240
2280
  fontSize -= 0.5;
2241
2281
  }
2242
2282
  }
2283
+ const textX = x + 2;
2284
+ const baselineY = y + h * 0.3;
2243
2285
  if (spacing > 0) {
2244
- let cx = x + 2;
2245
- const cy = y + h * 0.3;
2286
+ let cx = textX;
2246
2287
  for (const char of field.value) {
2247
2288
  page.drawText(char, {
2248
2289
  x: cx,
2249
- y: cy,
2290
+ y: baselineY,
2250
2291
  size: fontSize,
2251
2292
  font,
2252
2293
  color: inkColor
@@ -2255,13 +2296,35 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
2255
2296
  }
2256
2297
  } else {
2257
2298
  page.drawText(field.value, {
2258
- x: x + 2,
2259
- y: y + h * 0.3,
2299
+ x: textX,
2300
+ y: baselineY,
2260
2301
  size: fontSize,
2261
2302
  font,
2262
2303
  color: inkColor
2263
2304
  });
2264
2305
  }
2306
+ if (field.underline || field.strikethrough) {
2307
+ const textWidth = textWidthAtSize(field.value, fontSize);
2308
+ const lineThickness = Math.max(0.5, fontSize * 0.06);
2309
+ if (field.underline) {
2310
+ const uy = baselineY - fontSize * 0.12;
2311
+ page.drawLine({
2312
+ start: { x: textX, y: uy },
2313
+ end: { x: textX + textWidth, y: uy },
2314
+ thickness: lineThickness,
2315
+ color: inkColor
2316
+ });
2317
+ }
2318
+ if (field.strikethrough) {
2319
+ const sy = baselineY + fontSize * 0.3;
2320
+ page.drawLine({
2321
+ start: { x: textX, y: sy },
2322
+ end: { x: textX + textWidth, y: sy },
2323
+ thickness: lineThickness,
2324
+ color: inkColor
2325
+ });
2326
+ }
2327
+ }
2265
2328
  }
2266
2329
  }
2267
2330
  }
@@ -2275,18 +2338,19 @@ async function createPdfBuilder(defaults = {}) {
2275
2338
  const fontCache = /* @__PURE__ */ new Map();
2276
2339
  const embeddedPagesByUrl = /* @__PURE__ */ new Map();
2277
2340
  const signatureCache = /* @__PURE__ */ new Map();
2278
- async function getFont(family) {
2279
- let f = fontCache.get(family);
2341
+ async function getFont(family, bold, italic) {
2342
+ const key = fontKey(family, bold, italic);
2343
+ let f = fontCache.get(key);
2280
2344
  if (!f) {
2281
- const stdName = FONT_MAP[family] || StandardFonts.Helvetica;
2282
- f = await doc.embedFont(stdName);
2283
- fontCache.set(family, f);
2345
+ f = await doc.embedFont(resolveStandardFont(family, bold, italic));
2346
+ fontCache.set(key, f);
2284
2347
  }
2285
2348
  return f;
2286
2349
  }
2287
2350
  async function ensureFonts(fields) {
2288
- const keys = new Set(fields.map((f) => f.fontFamily || "Helvetica"));
2289
- for (const k of keys) await getFont(k);
2351
+ const keys = /* @__PURE__ */ new Map();
2352
+ for (const f of fields) keys.set(fontKey(f.fontFamily || "Helvetica", f.bold, f.italic), f);
2353
+ for (const f of keys.values()) await getFont(f.fontFamily || "Helvetica", f.bold, f.italic);
2290
2354
  }
2291
2355
  async function embedSource(source) {
2292
2356
  if (typeof source === "string") {
@@ -2763,7 +2827,7 @@ ${row.join(",")}`, "csv");
2763
2827
  fontSize: `${field.fontSize}pt`,
2764
2828
  letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
2765
2829
  lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
2766
- fontFamily: getCssFontFamily(field.fontFamily)
2830
+ ...getCssTextStyle(field)
2767
2831
  };
2768
2832
  if (field.type === "dropdown" || field.options && field.options.length > 0) {
2769
2833
  return /* @__PURE__ */ jsxs6(