@unlev/exeq 0.1.6 → 0.1.9
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 +79 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +98 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +98 -23
- 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",
|
|
@@ -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,15 +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
|
+
});
|
|
1319
|
+
const initializedRef = useRef4(false);
|
|
1306
1320
|
const [loading, setLoading] = useState3(false);
|
|
1307
1321
|
const [submitting, setSubmitting] = useState3(false);
|
|
1308
1322
|
const [pdfSource, setPdfSource] = useState3(null);
|
|
1309
1323
|
const [callbackUrl, setCallbackUrl] = useState3(initialCallbackUrl || "");
|
|
1310
1324
|
const containerRef = useRef4(null);
|
|
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;
|
|
1311
1329
|
useEffect3(() => {
|
|
1312
1330
|
if (initialTemplate) {
|
|
1313
1331
|
let templateFields = initialTemplate.fields;
|
|
1332
|
+
if (initialTemplate.signerRoles) setSignerRoles(initialTemplate.signerRoles);
|
|
1314
1333
|
if (initialValues) {
|
|
1315
1334
|
templateFields = templateFields.map((f) => {
|
|
1316
1335
|
const byLabel = Object.entries(initialValues).find(
|
|
@@ -1321,26 +1340,56 @@ function SignerView({
|
|
|
1321
1340
|
return value !== void 0 ? { ...f, value } : f;
|
|
1322
1341
|
});
|
|
1323
1342
|
}
|
|
1324
|
-
|
|
1343
|
+
if (initializedRef.current) {
|
|
1344
|
+
setFields((prev) => {
|
|
1345
|
+
const valueMap = new Map(prev.filter((f) => f.value).map((f) => [f.id, f.value]));
|
|
1346
|
+
return templateFields.map((f) => valueMap.has(f.id) ? { ...f, value: valueMap.get(f.id) } : f);
|
|
1347
|
+
});
|
|
1348
|
+
} else {
|
|
1349
|
+
setFields(templateFields);
|
|
1350
|
+
initializedRef.current = true;
|
|
1351
|
+
}
|
|
1325
1352
|
if (initialPdfUrl) loadPdf(initialPdfUrl);
|
|
1326
1353
|
return;
|
|
1327
1354
|
}
|
|
1328
1355
|
const params = new URLSearchParams(window.location.search);
|
|
1329
1356
|
const pdfUrl = params.get("pdf");
|
|
1330
1357
|
const fieldsUrl = params.get("fields");
|
|
1331
|
-
const signerParam = params.get("signer");
|
|
1332
1358
|
const cbUrl = params.get("callbackUrl");
|
|
1333
|
-
if (signerParam) setSigner(signerParam);
|
|
1334
1359
|
if (cbUrl) setCallbackUrl(cbUrl);
|
|
1335
1360
|
if (pdfUrl) loadPdf(pdfUrl);
|
|
1336
1361
|
if (fieldsUrl) {
|
|
1337
|
-
fetch(fieldsUrl).then((r) => r.json()).then((template) =>
|
|
1362
|
+
fetch(fieldsUrl).then((r) => r.json()).then((template) => {
|
|
1363
|
+
if (template.signerRoles) setSignerRoles(template.signerRoles);
|
|
1364
|
+
if (initializedRef.current) {
|
|
1365
|
+
setFields((prev) => {
|
|
1366
|
+
const valueMap = new Map(prev.filter((f) => f.value).map((f) => [f.id, f.value]));
|
|
1367
|
+
return template.fields.map((f) => valueMap.has(f.id) ? { ...f, value: valueMap.get(f.id) } : f);
|
|
1368
|
+
});
|
|
1369
|
+
} else {
|
|
1370
|
+
setFields(template.fields);
|
|
1371
|
+
initializedRef.current = true;
|
|
1372
|
+
}
|
|
1373
|
+
}).catch((err) => console.error("Failed to load fields:", err));
|
|
1338
1374
|
}
|
|
1339
1375
|
const handleMessage = (e) => {
|
|
1340
1376
|
if (e.data?.type === "load-signing") {
|
|
1341
|
-
if (e.data.fields)
|
|
1377
|
+
if (e.data.fields) {
|
|
1378
|
+
if (initializedRef.current) {
|
|
1379
|
+
setFields((prev) => {
|
|
1380
|
+
const valueMap = new Map(prev.filter((f) => f.value).map((f) => [f.id, f.value]));
|
|
1381
|
+
return e.data.fields.map((f) => valueMap.has(f.id) ? { ...f, value: valueMap.get(f.id) } : f);
|
|
1382
|
+
});
|
|
1383
|
+
} else {
|
|
1384
|
+
setFields(e.data.fields);
|
|
1385
|
+
initializedRef.current = true;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1342
1388
|
if (e.data.pdfUrl) loadPdf(e.data.pdfUrl);
|
|
1343
|
-
if (e.data.signer)
|
|
1389
|
+
if (e.data.signer) {
|
|
1390
|
+
const idx = signerOrder.indexOf(e.data.signer);
|
|
1391
|
+
if (idx >= 0) setCurrentSignerIndex(idx);
|
|
1392
|
+
}
|
|
1344
1393
|
if (e.data.callbackUrl) setCallbackUrl(e.data.callbackUrl);
|
|
1345
1394
|
}
|
|
1346
1395
|
};
|
|
@@ -1385,8 +1434,18 @@ function SignerView({
|
|
|
1385
1434
|
if (f.type === "checkbox") return true;
|
|
1386
1435
|
return !!f.value;
|
|
1387
1436
|
});
|
|
1388
|
-
const
|
|
1389
|
-
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;
|
|
1390
1449
|
setSubmitting(true);
|
|
1391
1450
|
try {
|
|
1392
1451
|
const pdfBytes = await generateFilledPdf(pdfSource, fields);
|
|
@@ -1406,7 +1465,7 @@ function SignerView({
|
|
|
1406
1465
|
} finally {
|
|
1407
1466
|
setSubmitting(false);
|
|
1408
1467
|
}
|
|
1409
|
-
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete]);
|
|
1468
|
+
}, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete, isLastSigner]);
|
|
1410
1469
|
const renderFieldContent = useCallback4((field) => {
|
|
1411
1470
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1412
1471
|
return null;
|
|
@@ -1469,8 +1528,20 @@ function SignerView({
|
|
|
1469
1528
|
}));
|
|
1470
1529
|
}
|
|
1471
1530
|
}, [fields.filter((f) => f.type === "signature" && f.value).length]);
|
|
1531
|
+
const stepLabel = isLastSigner ? submitLabel || "Complete" : `Next: ${signerOrder[currentSignerIndex + 1]}`;
|
|
1472
1532
|
return /* @__PURE__ */ jsxs6("div", { className: "signer-layout", ref: containerRef, children: [
|
|
1473
1533
|
loading && /* @__PURE__ */ jsx6("div", { className: "loading-indicator", children: "Loading document..." }),
|
|
1534
|
+
isMultiSigner && /* @__PURE__ */ jsx6("div", { className: "signer-progress-bar", children: signerOrder.map((role, i) => /* @__PURE__ */ jsxs6(
|
|
1535
|
+
"div",
|
|
1536
|
+
{
|
|
1537
|
+
className: `signer-progress-step ${i < currentSignerIndex ? "completed" : ""} ${i === currentSignerIndex ? "active" : ""} ${i > currentSignerIndex ? "upcoming" : ""}`,
|
|
1538
|
+
children: [
|
|
1539
|
+
/* @__PURE__ */ jsx6("div", { className: "signer-progress-dot", children: i < currentSignerIndex ? "\u2713" : i + 1 }),
|
|
1540
|
+
/* @__PURE__ */ jsx6("span", { className: "signer-progress-label", children: role })
|
|
1541
|
+
]
|
|
1542
|
+
},
|
|
1543
|
+
role
|
|
1544
|
+
)) }),
|
|
1474
1545
|
/* @__PURE__ */ jsxs6("div", { className: "signer-content", children: [
|
|
1475
1546
|
/* @__PURE__ */ jsx6("div", { className: "signer-pdf-area", children: pages.length > 0 && /* @__PURE__ */ jsx6(
|
|
1476
1547
|
PdfViewer,
|
|
@@ -1485,6 +1556,10 @@ function SignerView({
|
|
|
1485
1556
|
}
|
|
1486
1557
|
) }),
|
|
1487
1558
|
/* @__PURE__ */ jsxs6("div", { className: "signer-panel", children: [
|
|
1559
|
+
/* @__PURE__ */ jsxs6("div", { className: "signer-role-indicator", children: [
|
|
1560
|
+
/* @__PURE__ */ jsx6("span", { className: "signer-role-indicator-label", children: "Signing as" }),
|
|
1561
|
+
/* @__PURE__ */ jsx6("strong", { children: signer })
|
|
1562
|
+
] }),
|
|
1488
1563
|
selectedField && isFieldEditable && /* @__PURE__ */ jsxs6("div", { className: "signer-field-input", children: [
|
|
1489
1564
|
/* @__PURE__ */ jsx6("h3", { children: selectedField.label }),
|
|
1490
1565
|
selectedField.required && /* @__PURE__ */ jsx6("span", { className: "required-badge", children: "Required" }),
|
|
@@ -1532,16 +1607,16 @@ function SignerView({
|
|
|
1532
1607
|
currentFieldId: selectedFieldId,
|
|
1533
1608
|
onNavigate: handleNavigate,
|
|
1534
1609
|
allRequiredFilled,
|
|
1535
|
-
onSubmit:
|
|
1536
|
-
submitLabel
|
|
1610
|
+
onSubmit: handleAdvanceOrSubmit,
|
|
1611
|
+
submitLabel: stepLabel
|
|
1537
1612
|
}
|
|
1538
1613
|
),
|
|
1539
|
-
submitting && /* @__PURE__ */ jsx6("div", { className: "loading-indicator", children: "Generating PDF..." })
|
|
1614
|
+
submitting && /* @__PURE__ */ jsx6("div", { className: "loading-indicator", children: "Generating PDF..." }),
|
|
1615
|
+
/* @__PURE__ */ jsxs6("div", { className: "powered-by", children: [
|
|
1616
|
+
"Powered by ",
|
|
1617
|
+
/* @__PURE__ */ jsx6("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1618
|
+
] })
|
|
1540
1619
|
] })
|
|
1541
|
-
] }),
|
|
1542
|
-
/* @__PURE__ */ jsxs6("div", { className: "powered-by", children: [
|
|
1543
|
-
"Powered by ",
|
|
1544
|
-
/* @__PURE__ */ jsx6("a", { href: "https://exeq.org", target: "_blank", rel: "noopener noreferrer", children: "Exeq.org" })
|
|
1545
1620
|
] })
|
|
1546
1621
|
] });
|
|
1547
1622
|
}
|