@signiphi/page-assembly 0.2.0-beta.17 → 0.2.0-beta.18

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 CHANGED
@@ -64,6 +64,13 @@ type TrackedFormField = {
64
64
  label?: string;
65
65
  required?: boolean;
66
66
  options?: string[];
67
+ /** RADIO: each option's circle rect, top-origin, on `position.page`. */
68
+ optionPositions?: Array<{
69
+ x: number;
70
+ y: number;
71
+ width: number;
72
+ height: number;
73
+ }>;
67
74
  placeholder?: string;
68
75
  defaultValue?: string;
69
76
  assignedSignerEmail?: string;
@@ -307,6 +314,17 @@ interface ExtractedField {
307
314
  options?: string[];
308
315
  fieldId?: string;
309
316
  signer?: string;
317
+ /**
318
+ * RADIO: each option's circle widget rect on this page, top-origin, in
319
+ * option order — exactly as read, so a re-add can put every circle back
320
+ * where it was. `x/y/width/height` above is only the first circle.
321
+ */
322
+ optionPositions?: Array<{
323
+ x: number;
324
+ y: number;
325
+ width: number;
326
+ height: number;
327
+ }>;
310
328
  }
311
329
  /**
312
330
  * One field's metadata entry, as stored in the block.
@@ -398,7 +416,8 @@ interface SigniphiMetadata {
398
416
  checkboxLabelsBaked?: boolean;
399
417
  }
400
418
  /**
401
- * Extract SigniphiMetadata from a PDF document
419
+ * Extract SigniphiMetadata from a PDF document. Delegates to the contract
420
+ * package's reader; null when there is no block or it will not parse.
402
421
  */
403
422
  declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null;
404
423
  /**
@@ -408,7 +427,8 @@ declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | nu
408
427
  */
409
428
  declare function extractFieldsFromPdf(pdfBytes: Uint8Array): Promise<ExtractedField[]>;
410
429
  /**
411
- * Set SigniphiMetadata in a PDF document
430
+ * Set SigniphiMetadata in a PDF document. Delegates to the contract package's
431
+ * writer, which stores hex and throws on failure.
412
432
  */
413
433
  declare function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void;
414
434
 
@@ -457,6 +477,17 @@ interface FormFieldForPdf {
457
477
  multiline?: boolean;
458
478
  maxLength?: number;
459
479
  assignedSignerEmail?: string;
480
+ /**
481
+ * RADIO: each option's circle widget rect, top-origin, on `position.page`,
482
+ * as `extractFieldsFromPdf` read it. When it covers every option, the circles
483
+ * are re-added exactly there instead of being laid out afresh in `position`.
484
+ */
485
+ optionPositions?: Array<{
486
+ x: number;
487
+ y: number;
488
+ width: number;
489
+ height: number;
490
+ }>;
460
491
  }
461
492
  /**
462
493
  * Add form fields to a PDF document
package/dist/index.d.ts CHANGED
@@ -64,6 +64,13 @@ type TrackedFormField = {
64
64
  label?: string;
65
65
  required?: boolean;
66
66
  options?: string[];
67
+ /** RADIO: each option's circle rect, top-origin, on `position.page`. */
68
+ optionPositions?: Array<{
69
+ x: number;
70
+ y: number;
71
+ width: number;
72
+ height: number;
73
+ }>;
67
74
  placeholder?: string;
68
75
  defaultValue?: string;
69
76
  assignedSignerEmail?: string;
@@ -307,6 +314,17 @@ interface ExtractedField {
307
314
  options?: string[];
308
315
  fieldId?: string;
309
316
  signer?: string;
317
+ /**
318
+ * RADIO: each option's circle widget rect on this page, top-origin, in
319
+ * option order — exactly as read, so a re-add can put every circle back
320
+ * where it was. `x/y/width/height` above is only the first circle.
321
+ */
322
+ optionPositions?: Array<{
323
+ x: number;
324
+ y: number;
325
+ width: number;
326
+ height: number;
327
+ }>;
310
328
  }
311
329
  /**
312
330
  * One field's metadata entry, as stored in the block.
@@ -398,7 +416,8 @@ interface SigniphiMetadata {
398
416
  checkboxLabelsBaked?: boolean;
399
417
  }
400
418
  /**
401
- * Extract SigniphiMetadata from a PDF document
419
+ * Extract SigniphiMetadata from a PDF document. Delegates to the contract
420
+ * package's reader; null when there is no block or it will not parse.
402
421
  */
403
422
  declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null;
404
423
  /**
@@ -408,7 +427,8 @@ declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | nu
408
427
  */
409
428
  declare function extractFieldsFromPdf(pdfBytes: Uint8Array): Promise<ExtractedField[]>;
410
429
  /**
411
- * Set SigniphiMetadata in a PDF document
430
+ * Set SigniphiMetadata in a PDF document. Delegates to the contract package's
431
+ * writer, which stores hex and throws on failure.
412
432
  */
413
433
  declare function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void;
414
434
 
@@ -457,6 +477,17 @@ interface FormFieldForPdf {
457
477
  multiline?: boolean;
458
478
  maxLength?: number;
459
479
  assignedSignerEmail?: string;
480
+ /**
481
+ * RADIO: each option's circle widget rect, top-origin, on `position.page`,
482
+ * as `extractFieldsFromPdf` read it. When it covers every option, the circles
483
+ * are re-added exactly there instead of being laid out afresh in `position`.
484
+ */
485
+ optionPositions?: Array<{
486
+ x: number;
487
+ y: number;
488
+ width: number;
489
+ height: number;
490
+ }>;
460
491
  }
461
492
  /**
462
493
  * Add form fields to a PDF document
package/dist/index.js CHANGED
@@ -343,16 +343,23 @@ var AlertDialogOverlay = React7__namespace.forwardRef(({ className, ...props },
343
343
  }
344
344
  ));
345
345
  AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
346
- var AlertDialogContent = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { container: document.querySelector(".signiphi-page-assembly"), children: [
346
+ var CENTERED = {
347
+ position: "fixed",
348
+ left: "50%",
349
+ top: "50%",
350
+ transform: "translate(-50%, -50%)"
351
+ };
352
+ var AlertDialogContent = React7__namespace.forwardRef(({ className, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { container: document.querySelector(".signiphi-page-assembly"), children: [
347
353
  /* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
348
354
  /* @__PURE__ */ jsxRuntime.jsx(
349
355
  AlertDialogPrimitive__namespace.Content,
350
356
  {
351
357
  ref,
352
358
  className: cn(
353
- "fixed left-[50%] top-[50%] z-[9999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
359
+ "z-[9999] grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg sm:rounded-lg",
354
360
  className
355
361
  ),
362
+ style: { ...CENTERED, ...style },
356
363
  ...props
357
364
  }
358
365
  )
@@ -1401,6 +1408,46 @@ function downloadPdf(pdfBytes, filename) {
1401
1408
  a.click();
1402
1409
  URL.revokeObjectURL(url);
1403
1410
  }
1411
+ var KEY = "SigniphiMetadata";
1412
+ function readMetadata(doc, pdfLib) {
1413
+ let blockPresent = false;
1414
+ try {
1415
+ const infoRef = doc.context.trailerInfo.Info;
1416
+ if (!infoRef) return { metadata: null, blockPresent };
1417
+ const info = doc.context.lookup(infoRef);
1418
+ if (!info || typeof info.get !== "function") return { metadata: null, blockPresent };
1419
+ const value = info.get(pdfLib.PDFName.of(KEY));
1420
+ if (!value) return { metadata: null, blockPresent };
1421
+ blockPresent = true;
1422
+ const json = typeof value.decodeText === "function" ? value.decodeText() : stripDelimiters(value.toString());
1423
+ return { metadata: JSON.parse(json), blockPresent };
1424
+ } catch {
1425
+ return { metadata: null, blockPresent };
1426
+ }
1427
+ }
1428
+ function writeMetadata(doc, metadata, pdfLib) {
1429
+ const info = doc.context.lookup(doc.context.trailerInfo.Info);
1430
+ if (!info || typeof info.set !== "function") {
1431
+ throw new Error("Cannot write SigniphiMetadata: the PDF has no Info dictionary");
1432
+ }
1433
+ info.set(pdfLib.PDFName.of(KEY), pdfLib.PDFHexString.fromText(JSON.stringify(metadata)));
1434
+ }
1435
+ function stripDelimiters(raw) {
1436
+ const wrapped = raw.startsWith("(") && raw.endsWith(")") || raw.startsWith("<") && raw.endsWith(">");
1437
+ return wrapped ? raw.slice(1, -1) : raw;
1438
+ }
1439
+ function textLabelPlacements(source) {
1440
+ const fields = source.metadata?.fields;
1441
+ if (!fields || !source.pages?.length) return [];
1442
+ const out = [];
1443
+ for (const [name, entry] of Object.entries(fields)) {
1444
+ if (entry.type !== "text_label" || !entry.position) continue;
1445
+ for (const { source: page, combined } of source.pages) {
1446
+ if (page === entry.position.page) out.push({ name, page: combined });
1447
+ }
1448
+ }
1449
+ return out;
1450
+ }
1404
1451
  function toCombinedPage(entry, page) {
1405
1452
  if (!entry.position && !entry.radioPositions && !entry.radioOptions) return entry;
1406
1453
  const carried = { ...entry };
@@ -1411,78 +1458,55 @@ function toCombinedPage(entry, page) {
1411
1458
  }
1412
1459
  return carried;
1413
1460
  }
1414
- function mergeSourceMetadata(sources) {
1461
+ function assembleMetadata(sources) {
1415
1462
  const merged = { version: "1.0", fields: {}, fieldIdIndex: {} };
1416
1463
  let radioLabelsBaked;
1417
1464
  let textLabelsBaked;
1418
1465
  let checkboxLabelsBaked;
1466
+ let legacyRadioStripped;
1419
1467
  for (const source of sources) {
1420
1468
  const meta = source.metadata;
1421
- if (!meta || source.fields.length === 0) continue;
1469
+ if (!meta || source.fields.length === 0 && !source.pages?.length) continue;
1422
1470
  if (meta.radioLabelsBaked === false) radioLabelsBaked = false;
1423
1471
  else if (meta.radioLabelsBaked === true && radioLabelsBaked === void 0) radioLabelsBaked = true;
1424
1472
  if (meta.textLabelsBaked === false) textLabelsBaked = false;
1425
1473
  else if (meta.textLabelsBaked === true && textLabelsBaked === void 0) textLabelsBaked = true;
1426
1474
  if (meta.checkboxLabelsBaked === false) checkboxLabelsBaked = false;
1427
1475
  else if (meta.checkboxLabelsBaked === true && checkboxLabelsBaked === void 0) checkboxLabelsBaked = true;
1476
+ legacyRadioStripped = meta.legacyRadioStripped === true && legacyRadioStripped !== false;
1428
1477
  }
1429
1478
  for (const source of sources) {
1430
1479
  const meta = source.metadata;
1431
1480
  if (!meta) continue;
1432
1481
  const sourceTextLabelsBaked = meta.textLabelsBaked !== false;
1433
- for (const { name, page } of source.fields) {
1482
+ for (const { name, page } of [...source.fields, ...textLabelPlacements(source)]) {
1434
1483
  const key = `${name}_p${page}`;
1435
1484
  const entry = meta.fields?.[name];
1436
- if (entry) {
1437
- const carried = toCombinedPage(entry, page);
1438
- merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
1439
- }
1440
- const fieldId = meta.fieldIdIndex?.[name];
1441
- if (fieldId) merged.fieldIdIndex[key] = fieldId;
1485
+ if (!entry) continue;
1486
+ const carried = toCombinedPage(entry, page);
1487
+ merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
1488
+ if (entry.fieldId) merged.fieldIdIndex[entry.fieldId] = key;
1442
1489
  }
1443
1490
  }
1444
1491
  if (radioLabelsBaked !== void 0) merged.radioLabelsBaked = radioLabelsBaked;
1445
1492
  if (textLabelsBaked !== void 0) merged.textLabelsBaked = textLabelsBaked;
1446
1493
  if (checkboxLabelsBaked !== void 0) merged.checkboxLabelsBaked = checkboxLabelsBaked;
1494
+ if (legacyRadioStripped) merged.legacyRadioStripped = true;
1447
1495
  const hasEntries = Object.keys(merged.fields).length > 0;
1448
1496
  const hasMarkers = radioLabelsBaked !== void 0 || textLabelsBaked !== void 0 || checkboxLabelsBaked !== void 0;
1449
1497
  if (!hasEntries && !hasMarkers) return null;
1450
1498
  if (Object.keys(merged.fieldIdIndex).length === 0) delete merged.fieldIdIndex;
1451
1499
  return merged;
1452
1500
  }
1501
+ function mergeSourceMetadata(sources) {
1502
+ return assembleMetadata(sources);
1503
+ }
1453
1504
  function getSigniphiMetadata(pdfDoc) {
1454
- try {
1455
- const infoRef = pdfDoc.context.trailerInfo.Info;
1456
- if (!infoRef) {
1457
- return null;
1458
- }
1459
- const infoObj = pdfDoc.context.lookup(infoRef);
1460
- if (!infoObj || typeof infoObj.get !== "function") {
1461
- return null;
1462
- }
1463
- const infoDict = infoObj;
1464
- const metadataObj = infoDict.get(pdfLib.PDFName.of("SigniphiMetadata"));
1465
- if (!metadataObj) {
1466
- return null;
1467
- }
1468
- let jsonStr;
1469
- if (typeof metadataObj.decodeText === "function") {
1470
- jsonStr = metadataObj.decodeText();
1471
- } else {
1472
- const metadataStr = metadataObj.toString();
1473
- jsonStr = metadataStr;
1474
- if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
1475
- jsonStr = metadataStr.slice(1, -1);
1476
- } else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
1477
- jsonStr = metadataStr.slice(1, -1);
1478
- }
1479
- }
1480
- const metadata = JSON.parse(jsonStr);
1481
- return metadata;
1482
- } catch (error) {
1483
- console.error("Failed to load Signiphi metadata:", error);
1484
- return null;
1505
+ const { metadata, blockPresent } = readMetadata(pdfDoc, { PDFName: pdfLib.PDFName });
1506
+ if (blockPresent && !metadata) {
1507
+ console.error("Failed to load Signiphi metadata: the block is present but will not parse");
1485
1508
  }
1509
+ return metadata;
1486
1510
  }
1487
1511
  function getBaseFieldName(encodedName) {
1488
1512
  let baseName = encodedName;
@@ -1541,6 +1565,10 @@ async function extractFieldsFromPdf(pdfBytes) {
1541
1565
  const metadata = getSigniphiMetadata(pdfDoc);
1542
1566
  const form = pdfDoc.getForm();
1543
1567
  const pdfFields = form.getFields();
1568
+ const pages = pdfDoc.getPages();
1569
+ const pageHeights = pages.map((p) => p.getHeight());
1570
+ const pageIndexByRef = new Map(pages.map((p, i) => [p.ref, i + 1]));
1571
+ const pageNumberOf = (ref) => ref && pageIndexByRef.get(ref) || 1;
1544
1572
  for (const field of pdfFields) {
1545
1573
  const fieldName = field.getName();
1546
1574
  const widgets = field.acroField.getWidgets();
@@ -1569,19 +1597,20 @@ async function extractFieldsFromPdf(pdfBytes) {
1569
1597
  } else {
1570
1598
  console.log(`[field-extraction] Unknown field type "${fieldName}" - defaulting required=false`);
1571
1599
  }
1600
+ const optionPositionsByPage = /* @__PURE__ */ new Map();
1601
+ if (widgetType === "radio") {
1602
+ for (const w of widgets) {
1603
+ const pageNumber = pageNumberOf(w.P());
1604
+ const r = w.getRectangle();
1605
+ const top = pageHeights[pageNumber - 1] - r.y - r.height;
1606
+ const bucket = optionPositionsByPage.get(pageNumber) ?? [];
1607
+ bucket.push({ x: r.x, y: top, width: r.width, height: r.height });
1608
+ optionPositionsByPage.set(pageNumber, bucket);
1609
+ }
1610
+ }
1572
1611
  for (const widget of widgets) {
1573
1612
  const rect = widget.getRectangle();
1574
- const pageRef = widget.P();
1575
- let pageNumber = 1;
1576
- if (pageRef) {
1577
- const pages = pdfDoc.getPages();
1578
- for (let i = 0; i < pages.length; i++) {
1579
- if (pages[i].ref === pageRef) {
1580
- pageNumber = i + 1;
1581
- break;
1582
- }
1583
- }
1584
- }
1613
+ const pageNumber = pageNumberOf(widget.P());
1585
1614
  const pageQualifiedKey = `${baseName}_p${pageNumber}`;
1586
1615
  let fieldMetadata = metadata?.fields?.[pageQualifiedKey];
1587
1616
  if (!fieldMetadata) {
@@ -1598,8 +1627,7 @@ async function extractFieldsFromPdf(pdfBytes) {
1598
1627
  if (fieldMetadata?.options?.length) {
1599
1628
  fieldOptions = fieldMetadata.options;
1600
1629
  }
1601
- const page = pdfDoc.getPage(pageNumber - 1);
1602
- const pageHeight = page.getHeight();
1630
+ const pageHeight = pageHeights[pageNumber - 1];
1603
1631
  const extractedField = {
1604
1632
  name: baseName,
1605
1633
  // Use clean base name without __SIGNER__ encoding (signer stored in signer property)
@@ -1616,6 +1644,9 @@ async function extractFieldsFromPdf(pdfBytes) {
1616
1644
  signer: signerFromName
1617
1645
  // Extract signer from encoded name
1618
1646
  };
1647
+ if (widgetType === "radio") {
1648
+ extractedField.optionPositions = optionPositionsByPage.get(pageNumber) ?? [];
1649
+ }
1619
1650
  if (fieldMetadata) {
1620
1651
  if (fieldMetadata.fieldId) {
1621
1652
  extractedField.fieldId = fieldMetadata.fieldId;
@@ -1661,20 +1692,14 @@ async function extractFieldsFromPdf(pdfBytes) {
1661
1692
  }
1662
1693
  function setSigniphiMetadata(pdfDoc, metadata) {
1663
1694
  try {
1664
- const infoRef = pdfDoc.context.trailerInfo.Info;
1665
- const infoObj = pdfDoc.context.lookup(infoRef);
1666
- if (!infoObj || typeof infoObj.set !== "function") {
1667
- throw new Error("Info object is not a PDFDict or does not have set method");
1668
- }
1669
- const infoDict = infoObj;
1670
- const metadataString = JSON.stringify(metadata);
1671
- infoDict.set(pdfLib.PDFName.of("SigniphiMetadata"), pdfLib.PDFHexString.fromText(metadataString));
1695
+ writeMetadata(pdfDoc, metadata, { PDFName: pdfLib.PDFName, PDFHexString: pdfLib.PDFHexString });
1672
1696
  } catch (error) {
1673
1697
  console.error("Failed to set Signiphi metadata:", error);
1674
1698
  throw error;
1675
1699
  }
1676
1700
  }
1677
1701
  var SIGNIPHI_CHECKBOX_LABEL_MARKER = "SiPL_Check";
1702
+ var RADIO_BORDER_WIDTH = 1;
1678
1703
  var FormFieldType = /* @__PURE__ */ ((FormFieldType2) => {
1679
1704
  FormFieldType2["TEXT"] = "text";
1680
1705
  FormFieldType2["SIGNATURE"] = "signature";
@@ -1971,7 +1996,24 @@ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
1971
1996
  case "radio" /* RADIO */: {
1972
1997
  const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1973
1998
  const radioGroup = form.createRadioGroup(encodedName);
1974
- if (field.options && field.options.length > 0) {
1999
+ if (field.options && field.options.length > 0 && field.optionPositions?.length === field.options.length) {
2000
+ const optionPositions = field.optionPositions;
2001
+ field.options.forEach((option, index) => {
2002
+ const at = optionPositions[index];
2003
+ radioGroup.addOptionToPage(option, page, {
2004
+ x: at.x + RADIO_BORDER_WIDTH / 2,
2005
+ y: pageHeight - at.y - at.height + RADIO_BORDER_WIDTH / 2,
2006
+ width: at.width - RADIO_BORDER_WIDTH,
2007
+ height: at.height - RADIO_BORDER_WIDTH,
2008
+ borderWidth: RADIO_BORDER_WIDTH,
2009
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
2010
+ backgroundColor: pdfLib.rgb(1, 1, 1)
2011
+ });
2012
+ });
2013
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
2014
+ radioGroup.select(field.defaultValue);
2015
+ }
2016
+ } else if (field.options && field.options.length > 0) {
1975
2017
  const optionHeight = Math.min(20, field.position.height / field.options.length);
1976
2018
  const spacing = field.position.height / field.options.length;
1977
2019
  field.options.forEach((option, index) => {
@@ -3116,12 +3158,19 @@ var PageAssembler = React7.forwardRef(
3116
3158
  if (sourcePdf && !sourceMetadata) {
3117
3159
  console.warn(`[PageAssembler] No readable SigniphiMetadata in "${fileName}"`);
3118
3160
  }
3161
+ const pageUsageForFile = filePageUsage.get(fileId) || /* @__PURE__ */ new Map();
3119
3162
  const placements = [];
3120
- metadataSources.push({ metadata: sourceMetadata, fields: placements });
3163
+ const pageLandings = [];
3164
+ for (const [srcIndex, pageInstances] of pageUsageForFile) {
3165
+ for (const pageInstance of pageInstances) {
3166
+ const combined = pageIdToNewPageNumber.get(pageInstance.id);
3167
+ if (combined !== void 0) pageLandings.push({ source: srcIndex + 1, combined });
3168
+ }
3169
+ }
3170
+ metadataSources.push({ metadata: sourceMetadata, fields: placements, pages: pageLandings });
3121
3171
  console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
3122
3172
  const extractedFields = await extractFieldsFromPdf(pdfBytes2);
3123
3173
  console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
3124
- const pageUsageForFile = filePageUsage.get(fileId) || /* @__PURE__ */ new Map();
3125
3174
  for (const field of extractedFields) {
3126
3175
  const originalPage = field.page;
3127
3176
  const srcIndex = originalPage - 1;
@@ -3145,6 +3194,7 @@ var PageAssembler = React7.forwardRef(
3145
3194
  label: field.label,
3146
3195
  required: field.required,
3147
3196
  options: field.options,
3197
+ optionPositions: field.optionPositions,
3148
3198
  placeholder: field.placeholder,
3149
3199
  fieldId: field.fieldId,
3150
3200
  assignedSignerEmail: field.signer
@@ -3249,6 +3299,7 @@ var PageAssembler = React7.forwardRef(
3249
3299
  label: field.label,
3250
3300
  required: field.required,
3251
3301
  options: field.options,
3302
+ optionPositions: field.optionPositions,
3252
3303
  placeholder: field.placeholder,
3253
3304
  assignedSignerEmail: field.assignedSignerEmail
3254
3305
  }));