@unlev/exeq 0.1.7 → 0.1.10
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/README.md +2 -1
- package/dist/index.css +53 -6
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +114 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -74
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -235,9 +235,10 @@ function FieldOverlayItem({
|
|
|
235
235
|
const overlayRef = useRef(null);
|
|
236
236
|
const dragStartRef = useRef(null);
|
|
237
237
|
const resizeStartRef = useRef(null);
|
|
238
|
-
const color = getSignerColor(field.assignee);
|
|
239
238
|
const isRedact = field.type === "blackout" || field.type === "whiteout";
|
|
240
239
|
const isEditable = mode === "designer" || mode === "signer" && field.assignee === currentSigner;
|
|
240
|
+
const isInactiveSigner = mode === "signer" && !isRedact && field.assignee !== currentSigner;
|
|
241
|
+
const color = isInactiveSigner ? "#cccccc" : getSignerColor(field.assignee);
|
|
241
242
|
const isPreFilled = !isEditable && !!field.value;
|
|
242
243
|
const handleMouseDown = useCallback((e) => {
|
|
243
244
|
if (mode !== "designer" || !onMove) return;
|
|
@@ -302,7 +303,7 @@ function FieldOverlayItem({
|
|
|
302
303
|
"div",
|
|
303
304
|
{
|
|
304
305
|
ref: overlayRef,
|
|
305
|
-
className: `field-overlay ${isSelected ? "selected" : ""} ${isEditable ? "editable" : "readonly"} ${isPreFilled ? "prefilled" : ""} ${isRedact ? "redact" : ""}`,
|
|
306
|
+
className: `field-overlay ${isSelected ? "selected" : ""} ${isEditable ? "editable" : "readonly"} ${isPreFilled ? "prefilled" : ""} ${isRedact ? "redact" : ""} ${isInactiveSigner ? "inactive-signer" : ""}`,
|
|
306
307
|
style: {
|
|
307
308
|
left: `${field.x}%`,
|
|
308
309
|
top: `${field.y}%`,
|
|
@@ -310,9 +311,9 @@ function FieldOverlayItem({
|
|
|
310
311
|
height: `${field.height}%`,
|
|
311
312
|
borderColor: isRedact ? field.type === "blackout" ? "#666" : "#bbb" : color,
|
|
312
313
|
borderStyle: isRedact ? "dashed" : "solid",
|
|
313
|
-
backgroundColor: isRedact ? field.type === "blackout" ? "#000000" : "#ffffff" : isSelected ? `${color}22` : `${color}11`,
|
|
314
|
-
cursor: mode === "designer" ? "move" : "default",
|
|
315
|
-
pointerEvents: mode === "signer" && isRedact ? "none" : void 0
|
|
314
|
+
backgroundColor: isRedact ? field.type === "blackout" ? "#000000" : "#ffffff" : isInactiveSigner ? "#f5f5f5" : isSelected ? `${color}22` : `${color}11`,
|
|
315
|
+
cursor: mode === "designer" ? "move" : isInactiveSigner ? "default" : "default",
|
|
316
|
+
pointerEvents: mode === "signer" && (isRedact || isInactiveSigner) ? "none" : void 0
|
|
316
317
|
},
|
|
317
318
|
onClick: (e) => {
|
|
318
319
|
e.stopPropagation();
|
|
@@ -999,6 +1000,10 @@ function DesignerView({
|
|
|
999
1000
|
pages.length > 0 && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1000
1001
|
/* @__PURE__ */ jsx4("div", { className: "panel-resize-handle", onMouseDown: handleResizeStart }),
|
|
1001
1002
|
/* @__PURE__ */ jsxs4("div", { className: "designer-panel", style: { width: panelWidth }, children: [
|
|
1003
|
+
/* @__PURE__ */ jsxs4("div", { className: "signer-role-indicator", children: [
|
|
1004
|
+
/* @__PURE__ */ jsx4("span", { className: "signer-role-indicator-label", children: "Editing as" }),
|
|
1005
|
+
/* @__PURE__ */ jsx4("strong", { children: activeRole })
|
|
1006
|
+
] }),
|
|
1002
1007
|
/* @__PURE__ */ jsxs4("div", { className: "panel-tabs", children: [
|
|
1003
1008
|
/* @__PURE__ */ jsx4(
|
|
1004
1009
|
"button",
|
|
@@ -1216,8 +1221,8 @@ function FieldNavigator({
|
|
|
1216
1221
|
currentFieldId,
|
|
1217
1222
|
onNavigate,
|
|
1218
1223
|
allRequiredFilled,
|
|
1219
|
-
|
|
1220
|
-
|
|
1224
|
+
onComplete,
|
|
1225
|
+
completeLabel = "Complete"
|
|
1221
1226
|
}) {
|
|
1222
1227
|
const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
|
|
1223
1228
|
const hasPrev = currentIndex > 0;
|
|
@@ -1268,10 +1273,10 @@ function FieldNavigator({
|
|
|
1268
1273
|
/* @__PURE__ */ jsx5(
|
|
1269
1274
|
"button",
|
|
1270
1275
|
{
|
|
1271
|
-
onClick:
|
|
1276
|
+
onClick: onComplete,
|
|
1272
1277
|
disabled: !allRequiredFilled,
|
|
1273
|
-
className: "
|
|
1274
|
-
children:
|
|
1278
|
+
className: "complete-btn",
|
|
1279
|
+
children: completeLabel
|
|
1275
1280
|
}
|
|
1276
1281
|
)
|
|
1277
1282
|
] });
|
|
@@ -1287,7 +1292,8 @@ function SignerView({
|
|
|
1287
1292
|
callbackUrl: initialCallbackUrl,
|
|
1288
1293
|
onComplete,
|
|
1289
1294
|
initialValues,
|
|
1290
|
-
submitLabel
|
|
1295
|
+
submitLabel,
|
|
1296
|
+
signerOrder: signerOrderProp
|
|
1291
1297
|
} = {}) {
|
|
1292
1298
|
if (!isValidApiKey(apiKey)) {
|
|
1293
1299
|
return /* @__PURE__ */ jsx6("div", { className: "signer-layout", children: /* @__PURE__ */ jsxs6("div", { className: "empty-state", children: [
|
|
@@ -1302,22 +1308,28 @@ function SignerView({
|
|
|
1302
1308
|
const [pages, setPages] = useState3([]);
|
|
1303
1309
|
const [fields, setFields] = useState3([]);
|
|
1304
1310
|
const [selectedFieldId, setSelectedFieldId] = useState3(null);
|
|
1305
|
-
const [
|
|
1311
|
+
const [signerRoles, setSignerRoles] = useState3([]);
|
|
1312
|
+
const [currentSignerIndex, setCurrentSignerIndex] = useState3(() => {
|
|
1313
|
+
if (initialSigner && signerOrderProp) {
|
|
1314
|
+
const idx = signerOrderProp.indexOf(initialSigner);
|
|
1315
|
+
return idx >= 0 ? idx : 0;
|
|
1316
|
+
}
|
|
1317
|
+
return 0;
|
|
1318
|
+
});
|
|
1306
1319
|
const initializedRef = useRef4(false);
|
|
1307
1320
|
const [loading, setLoading] = useState3(false);
|
|
1308
1321
|
const [submitting, setSubmitting] = useState3(false);
|
|
1309
1322
|
const [pdfSource, setPdfSource] = useState3(null);
|
|
1310
1323
|
const [callbackUrl, setCallbackUrl] = useState3(initialCallbackUrl || "");
|
|
1311
1324
|
const containerRef = useRef4(null);
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1317
|
-
}, [initialSigner]);
|
|
1325
|
+
const signerOrder = signerOrderProp || (signerRoles.length > 0 ? [...signerRoles.filter((r) => r !== "Sender"), ...signerRoles.filter((r) => r === "Sender")] : [initialSigner || "Signer 1"]);
|
|
1326
|
+
const signer = signerOrder[currentSignerIndex] || signerOrder[0] || "Signer 1";
|
|
1327
|
+
const isLastSigner = currentSignerIndex >= signerOrder.length - 1;
|
|
1328
|
+
const isMultiSigner = signerOrder.length > 1;
|
|
1318
1329
|
useEffect3(() => {
|
|
1319
1330
|
if (initialTemplate) {
|
|
1320
1331
|
let templateFields = initialTemplate.fields;
|
|
1332
|
+
if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
|
|
1321
1333
|
if (initialValues) {
|
|
1322
1334
|
templateFields = templateFields.map((f) => {
|
|
1323
1335
|
const byLabel = Object.entries(initialValues).find(
|
|
@@ -1343,13 +1355,12 @@ function SignerView({
|
|
|
1343
1355
|
const params = new URLSearchParams(window.location.search);
|
|
1344
1356
|
const pdfUrl = params.get("pdf");
|
|
1345
1357
|
const fieldsUrl = params.get("fields");
|
|
1346
|
-
const signerParam = params.get("signer");
|
|
1347
1358
|
const cbUrl = params.get("callbackUrl");
|
|
1348
|
-
if (signerParam) setSigner(signerParam);
|
|
1349
1359
|
if (cbUrl) setCallbackUrl(cbUrl);
|
|
1350
1360
|
if (pdfUrl) loadPdf(pdfUrl);
|
|
1351
1361
|
if (fieldsUrl) {
|
|
1352
1362
|
fetch(fieldsUrl).then((r) => r.json()).then((template) => {
|
|
1363
|
+
if (template.signerRoles) setSignerRoles(template.signerRoles);
|
|
1353
1364
|
if (initializedRef.current) {
|
|
1354
1365
|
setFields((prev) => {
|
|
1355
1366
|
const valueMap = new Map(prev.filter((f) => f.value).map((f) => [f.id, f.value]));
|
|
@@ -1375,7 +1386,10 @@ function SignerView({
|
|
|
1375
1386
|
}
|
|
1376
1387
|
}
|
|
1377
1388
|
if (e.data.pdfUrl) loadPdf(e.data.pdfUrl);
|
|
1378
|
-
if (e.data.signer)
|
|
1389
|
+
if (e.data.signer) {
|
|
1390
|
+
const idx = signerOrder.indexOf(e.data.signer);
|
|
1391
|
+
if (idx >= 0) setCurrentSignerIndex(idx);
|
|
1392
|
+
}
|
|
1379
1393
|
if (e.data.callbackUrl) setCallbackUrl(e.data.callbackUrl);
|
|
1380
1394
|
}
|
|
1381
1395
|
};
|
|
@@ -1420,8 +1434,18 @@ function SignerView({
|
|
|
1420
1434
|
if (f.type === "checkbox") return true;
|
|
1421
1435
|
return !!f.value;
|
|
1422
1436
|
});
|
|
1423
|
-
const
|
|
1424
|
-
if (!
|
|
1437
|
+
const handleAdvanceOrSubmit = useCallback4(async () => {
|
|
1438
|
+
if (!allRequiredFilled) return;
|
|
1439
|
+
if (!isLastSigner) {
|
|
1440
|
+
setCurrentSignerIndex((prev) => prev + 1);
|
|
1441
|
+
setSelectedFieldId(null);
|
|
1442
|
+
const pdfArea = containerRef.current?.querySelector(".signer-pdf-area");
|
|
1443
|
+
if (pdfArea) {
|
|
1444
|
+
pdfArea.scrollTo({ top: 0, behavior: "smooth" });
|
|
1445
|
+
}
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (!pdfSource) return;
|
|
1425
1449
|
setSubmitting(true);
|
|
1426
1450
|
try {
|
|
1427
1451
|
const pdfBytes = await generateFilledPdf(pdfSource, fields);
|
|
@@ -1441,7 +1465,7 @@ function SignerView({
|
|
|
1441
1465
|
} finally {
|
|
1442
1466
|
setSubmitting(false);
|
|
1443
1467
|
}
|
|
1444
|
-
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete]);
|
|
1468
|
+
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
|
|
1445
1469
|
const renderFieldContent = useCallback4((field) => {
|
|
1446
1470
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1447
1471
|
return null;
|
|
@@ -1520,63 +1544,79 @@ function SignerView({
|
|
|
1520
1544
|
}
|
|
1521
1545
|
) }),
|
|
1522
1546
|
/* @__PURE__ */ jsxs6("div", { className: "signer-panel", children: [
|
|
1523
|
-
|
|
1524
|
-
/* @__PURE__ */
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
{
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
+
/* @__PURE__ */ jsxs6("div", { className: "signer-panel-header", children: [
|
|
1548
|
+
/* @__PURE__ */ jsxs6("div", { className: "signer-role-indicator", children: [
|
|
1549
|
+
/* @__PURE__ */ jsx6("span", { className: "signer-role-indicator-label", children: "Signing as" }),
|
|
1550
|
+
/* @__PURE__ */ jsx6("strong", { children: signer })
|
|
1551
|
+
] }),
|
|
1552
|
+
isMultiSigner && /* @__PURE__ */ jsxs6("div", { className: "signer-step-badge", children: [
|
|
1553
|
+
"Step ",
|
|
1554
|
+
currentSignerIndex + 1,
|
|
1555
|
+
" of ",
|
|
1556
|
+
signerOrder.length
|
|
1557
|
+
] })
|
|
1558
|
+
] }),
|
|
1559
|
+
/* @__PURE__ */ jsxs6("div", { className: "signer-panel-body", children: [
|
|
1560
|
+
selectedField && isFieldEditable && /* @__PURE__ */ jsxs6("div", { className: "signer-field-input", children: [
|
|
1561
|
+
/* @__PURE__ */ jsx6("h3", { children: selectedField.label }),
|
|
1562
|
+
selectedField.required && /* @__PURE__ */ jsx6("span", { className: "required-badge", children: "Required" }),
|
|
1563
|
+
(selectedField.type === "signature" || selectedField.type === "initials") && /* @__PURE__ */ jsx6(
|
|
1564
|
+
SignatureCanvas,
|
|
1565
|
+
{
|
|
1566
|
+
width: 280,
|
|
1567
|
+
height: selectedField.type === "initials" ? 80 : 120,
|
|
1568
|
+
onSign: (dataUrl) => handleFieldUpdate(selectedField.id, dataUrl),
|
|
1569
|
+
initialValue: selectedField.value
|
|
1570
|
+
}
|
|
1571
|
+
),
|
|
1572
|
+
selectedField.type === "text" && /* @__PURE__ */ jsx6(
|
|
1547
1573
|
"input",
|
|
1548
1574
|
{
|
|
1549
|
-
type: "
|
|
1550
|
-
|
|
1551
|
-
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.
|
|
1575
|
+
type: selectedField.textSubtype === "email" ? "email" : selectedField.textSubtype === "number" ? "number" : selectedField.textSubtype === "phone" ? "tel" : selectedField.textSubtype === "date" ? "date" : "text",
|
|
1576
|
+
value: selectedField.value,
|
|
1577
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.value),
|
|
1578
|
+
placeholder: selectedField.placeholder,
|
|
1579
|
+
className: "signer-text-input"
|
|
1552
1580
|
}
|
|
1553
1581
|
),
|
|
1554
|
-
selectedField.
|
|
1582
|
+
selectedField.type === "checkbox" && /* @__PURE__ */ jsxs6("label", { className: "signer-checkbox-label", children: [
|
|
1583
|
+
/* @__PURE__ */ jsx6(
|
|
1584
|
+
"input",
|
|
1585
|
+
{
|
|
1586
|
+
type: "checkbox",
|
|
1587
|
+
checked: selectedField.value === "true",
|
|
1588
|
+
onChange: (e) => handleFieldUpdate(selectedField.id, e.target.checked ? "true" : "")
|
|
1589
|
+
}
|
|
1590
|
+
),
|
|
1591
|
+
selectedField.placeholder || "Check this box"
|
|
1592
|
+
] }),
|
|
1593
|
+
selectedField.type === "signed-date" && /* @__PURE__ */ jsx6("div", { className: "signer-date-display", children: selectedField.value || "Will auto-fill when you sign" })
|
|
1555
1594
|
] }),
|
|
1556
|
-
selectedField
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
/* @__PURE__ */ jsx6("
|
|
1595
|
+
selectedField && !isFieldEditable && /* @__PURE__ */ jsxs6("div", { className: "signer-field-readonly", children: [
|
|
1596
|
+
/* @__PURE__ */ jsx6("h3", { children: selectedField.label }),
|
|
1597
|
+
/* @__PURE__ */ jsx6("p", { children: "This field belongs to another signer." })
|
|
1598
|
+
] }),
|
|
1599
|
+
!selectedField && editableFields.length > 0 && /* @__PURE__ */ jsx6("div", { className: "panel-empty", children: "Select a field to fill it in, or use the navigation below." })
|
|
1561
1600
|
] }),
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1601
|
+
/* @__PURE__ */ jsxs6("div", { className: "signer-panel-footer", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx6(
|
|
1603
|
+
FieldNavigator,
|
|
1604
|
+
{
|
|
1605
|
+
fields: editableFields,
|
|
1606
|
+
currentFieldId: selectedFieldId,
|
|
1607
|
+
onNavigate: handleNavigate,
|
|
1608
|
+
allRequiredFilled,
|
|
1609
|
+
onComplete: handleAdvanceOrSubmit,
|
|
1610
|
+
completeLabel: isLastSigner ? submitLabel || "Complete" : `Next: ${signerOrder[currentSignerIndex + 1]}`
|
|
1611
|
+
}
|
|
1612
|
+
),
|
|
1613
|
+
submitting && /* @__PURE__ */ jsx6("div", { className: "loading-indicator", children: "Generating PDF..." }),
|
|
1614
|
+
/* @__PURE__ */ jsxs6("div", { className: "powered-by", children: [
|
|
1615
|
+
"Powered by ",
|
|
1616
|
+
/* @__PURE__ */ jsx6("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1617
|
+
] })
|
|
1618
|
+
] })
|
|
1575
1619
|
] })
|
|
1576
|
-
] }),
|
|
1577
|
-
/* @__PURE__ */ jsxs6("div", { className: "powered-by", children: [
|
|
1578
|
-
"Powered by ",
|
|
1579
|
-
/* @__PURE__ */ jsx6("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1580
1620
|
] })
|
|
1581
1621
|
] });
|
|
1582
1622
|
}
|