@unlev/exeq 0.1.5 → 0.1.6

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
@@ -95,7 +95,7 @@ function createField(type, assignee, page, x, y, existingFields) {
95
95
  type,
96
96
  label: uniqueLabel(baseLabel, existingLabels),
97
97
  placeholder: defaults.placeholder || "",
98
- required: true,
98
+ required: type === "checkbox" || type === "blackout" || type === "whiteout" ? false : true,
99
99
  assignee,
100
100
  page,
101
101
  x,
@@ -311,7 +311,8 @@ function FieldOverlayItem({
311
311
  borderColor: isRedact ? field.type === "blackout" ? "#666" : "#bbb" : color,
312
312
  borderStyle: isRedact ? "dashed" : "solid",
313
313
  backgroundColor: isRedact ? field.type === "blackout" ? "#000000" : "#ffffff" : isSelected ? `${color}22` : `${color}11`,
314
- cursor: mode === "designer" ? "move" : "default"
314
+ cursor: mode === "designer" ? "move" : "default",
315
+ pointerEvents: mode === "signer" && isRedact ? "none" : void 0
315
316
  },
316
317
  onClick: (e) => {
317
318
  e.stopPropagation();
@@ -416,7 +417,7 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete }) {
416
417
  }
417
418
  )
418
419
  ] }),
419
- !isRedactField && /* @__PURE__ */ jsx2("div", { className: "panel-field", children: /* @__PURE__ */ jsxs2("label", { className: "panel-checkbox-label", children: [
420
+ !isRedactField && field.type !== "checkbox" && /* @__PURE__ */ jsx2("div", { className: "panel-field", children: /* @__PURE__ */ jsxs2("label", { className: "panel-checkbox-label", children: [
420
421
  /* @__PURE__ */ jsx2(
421
422
  "input",
422
423
  {
@@ -516,10 +517,20 @@ function SignatureCanvas({
516
517
  }
517
518
  }, [paths, currentPath, width, height]);
518
519
  const getPoint = useCallback2((e) => {
519
- const rect = canvasRef.current.getBoundingClientRect();
520
+ const canvas = canvasRef.current;
521
+ const rect = canvas.getBoundingClientRect();
522
+ const style = getComputedStyle(canvas);
523
+ const borderL = parseFloat(style.borderLeftWidth) || 0;
524
+ const borderT = parseFloat(style.borderTopWidth) || 0;
525
+ const borderR = parseFloat(style.borderRightWidth) || 0;
526
+ const borderB = parseFloat(style.borderBottomWidth) || 0;
527
+ const contentW = rect.width - borderL - borderR;
528
+ const contentH = rect.height - borderT - borderB;
529
+ const scaleX = canvas.width / contentW;
530
+ const scaleY = canvas.height / contentH;
520
531
  return [
521
- e.clientX - rect.left,
522
- e.clientY - rect.top,
532
+ (e.clientX - rect.left - borderL) * scaleX,
533
+ (e.clientY - rect.top - borderT) * scaleY,
523
534
  e.pressure
524
535
  ];
525
536
  }, []);
@@ -628,8 +639,10 @@ function DesignerView({
628
639
  const [newRoleName, setNewRoleName] = useState2("");
629
640
  const [draggingFieldType, setDraggingFieldType] = useState2(null);
630
641
  const [panelWidth, setPanelWidth] = useState2(380);
642
+ const [clipboardField, setClipboardField] = useState2(null);
631
643
  const dragGhostRef = useRef3(null);
632
644
  const resizingRef = useRef3(false);
645
+ const lastStylesRef = useRef3({});
633
646
  useEffect2(() => {
634
647
  const pdfUrl = initialPdfUrl || initialTemplate?.pdfUrl;
635
648
  if (pdfUrl) {
@@ -677,15 +690,24 @@ function DesignerView({
677
690
  }, [loadPdf]);
678
691
  const handlePageClick = useCallback3((page, x, y) => {
679
692
  const field = createField(activeFieldType, activeRole, page, x, y, fields);
680
- setFields((prev) => [...prev, field]);
681
- setSelectedFieldId(field.id);
693
+ const sticky = lastStylesRef.current[activeFieldType];
694
+ const styledField = sticky ? { ...field, ...sticky } : field;
695
+ setFields((prev) => [...prev, styledField]);
696
+ setSelectedFieldId(styledField.id);
682
697
  setRightTab("properties");
683
698
  }, [activeFieldType, activeRole, fields]);
684
699
  const handleFieldMove = useCallback3((id, page, x, y) => {
685
700
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, page, x, y } : f));
686
701
  }, []);
687
702
  const handleFieldResize = useCallback3((id, width, height) => {
688
- setFields((prev) => prev.map((f) => f.id === id ? { ...f, width, height } : f));
703
+ setFields((prev) => {
704
+ const field = prev.find((f) => f.id === id);
705
+ if (field) {
706
+ const existing = lastStylesRef.current[field.type] || {};
707
+ lastStylesRef.current[field.type] = { ...existing, width, height, fontSize: field.fontSize };
708
+ }
709
+ return prev.map((f) => f.id === id ? { ...f, width, height } : f);
710
+ });
689
711
  }, []);
690
712
  const handleFieldUpdate = useCallback3((id, updates) => {
691
713
  setFields((prev) => {
@@ -693,7 +715,18 @@ function DesignerView({
693
715
  const otherLabels = prev.filter((f) => f.id !== id).map((f) => f.label);
694
716
  updates.label = uniqueLabel(updates.label, otherLabels);
695
717
  }
696
- return prev.map((f) => f.id === id ? { ...f, ...updates } : f);
718
+ const updated = prev.map((f) => f.id === id ? { ...f, ...updates } : f);
719
+ const field = prev.find((f) => f.id === id);
720
+ if (field && (updates.fontSize !== void 0 || updates.width !== void 0 || updates.height !== void 0 || updates.inkColor !== void 0)) {
721
+ const merged = { ...field, ...updates };
722
+ lastStylesRef.current[field.type] = {
723
+ width: merged.width,
724
+ height: merged.height,
725
+ fontSize: merged.fontSize,
726
+ inkColor: merged.inkColor
727
+ };
728
+ }
729
+ return updated;
697
730
  });
698
731
  }, []);
699
732
  const handleFieldDelete = useCallback3((id) => {
@@ -759,8 +792,10 @@ function DesignerView({
759
792
  }, []);
760
793
  const handleDropOnPage = useCallback3((page, x, y, fieldType) => {
761
794
  const field = createField(fieldType, activeRole, page, x, y, fields);
762
- setFields((prev) => [...prev, field]);
763
- setSelectedFieldId(field.id);
795
+ const sticky = lastStylesRef.current[fieldType];
796
+ const styledField = sticky ? { ...field, ...sticky } : field;
797
+ setFields((prev) => [...prev, styledField]);
798
+ setSelectedFieldId(styledField.id);
764
799
  setRightTab("properties");
765
800
  }, [activeRole, fields]);
766
801
  useEffect2(() => {
@@ -778,6 +813,38 @@ function DesignerView({
778
813
  window.addEventListener("keydown", handleKeyDown);
779
814
  return () => window.removeEventListener("keydown", handleKeyDown);
780
815
  }, [selectedFieldId, handleFieldDelete]);
816
+ useEffect2(() => {
817
+ const handleKeyDown = (e) => {
818
+ const tag = (document.activeElement?.tagName || "").toLowerCase();
819
+ if (tag === "input" || tag === "textarea" || tag === "select") return;
820
+ if (document.activeElement?.isContentEditable) return;
821
+ const isMod = e.metaKey || e.ctrlKey;
822
+ if (isMod && e.key === "c" && selectedFieldId) {
823
+ const field = fields.find((f) => f.id === selectedFieldId);
824
+ if (field) {
825
+ e.preventDefault();
826
+ setClipboardField(field);
827
+ }
828
+ }
829
+ if (isMod && e.key === "v" && clipboardField) {
830
+ e.preventDefault();
831
+ const existingLabels = fields.map((f) => f.label);
832
+ const newField = {
833
+ ...clipboardField,
834
+ id: generateId(),
835
+ label: uniqueLabel(clipboardField.label, existingLabels),
836
+ x: clipboardField.x + 2,
837
+ y: clipboardField.y + 2,
838
+ value: ""
839
+ };
840
+ setFields((prev) => [...prev, newField]);
841
+ setSelectedFieldId(newField.id);
842
+ setRightTab("properties");
843
+ }
844
+ };
845
+ window.addEventListener("keydown", handleKeyDown);
846
+ return () => window.removeEventListener("keydown", handleKeyDown);
847
+ }, [selectedFieldId, fields, clipboardField]);
781
848
  const handleResizeStart = useCallback3((e) => {
782
849
  e.preventDefault();
783
850
  resizingRef.current = true;
@@ -1149,7 +1216,8 @@ function FieldNavigator({
1149
1216
  currentFieldId,
1150
1217
  onNavigate,
1151
1218
  allRequiredFilled,
1152
- onSubmit
1219
+ onSubmit,
1220
+ submitLabel = "Complete"
1153
1221
  }) {
1154
1222
  const currentIndex = fields.findIndex((f) => f.id === currentFieldId);
1155
1223
  const hasPrev = currentIndex > 0;
@@ -1203,7 +1271,7 @@ function FieldNavigator({
1203
1271
  onClick: onSubmit,
1204
1272
  disabled: !allRequiredFilled,
1205
1273
  className: "submit-btn",
1206
- children: "Complete & Download"
1274
+ children: submitLabel
1207
1275
  }
1208
1276
  )
1209
1277
  ] });
@@ -1218,7 +1286,8 @@ function SignerView({
1218
1286
  initialSigner,
1219
1287
  callbackUrl: initialCallbackUrl,
1220
1288
  onComplete,
1221
- initialValues
1289
+ initialValues,
1290
+ submitLabel
1222
1291
  } = {}) {
1223
1292
  if (!isValidApiKey(apiKey)) {
1224
1293
  return /* @__PURE__ */ jsx6("div", { className: "signer-layout", children: /* @__PURE__ */ jsxs6("div", { className: "empty-state", children: [
@@ -1290,14 +1359,14 @@ function SignerView({
1290
1359
  setLoading(false);
1291
1360
  }
1292
1361
  }, []);
1293
- const editableFields = fields.filter((f) => f.assignee === signer).sort((a, b) => {
1362
+ const editableFields = fields.filter((f) => f.assignee === signer && f.type !== "blackout" && f.type !== "whiteout").sort((a, b) => {
1294
1363
  if (a.page !== b.page) return a.page - b.page;
1295
1364
  const bandThreshold = 2;
1296
1365
  if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
1297
1366
  return a.x - b.x;
1298
1367
  });
1299
1368
  const selectedField = fields.find((f) => f.id === selectedFieldId) || null;
1300
- const isFieldEditable = selectedField ? selectedField.assignee === signer : false;
1369
+ const isFieldEditable = selectedField ? selectedField.assignee === signer && selectedField.type !== "blackout" && selectedField.type !== "whiteout" : false;
1301
1370
  const handleFieldUpdate = useCallback4((id, value) => {
1302
1371
  setFields((prev) => prev.map((f) => f.id === id ? { ...f, value } : f));
1303
1372
  }, []);
@@ -1339,6 +1408,9 @@ function SignerView({
1339
1408
  }
1340
1409
  }, [pdfSource, fields, callbackUrl, allRequiredFilled, onComplete]);
1341
1410
  const renderFieldContent = useCallback4((field) => {
1411
+ if (field.type === "blackout" || field.type === "whiteout") {
1412
+ return null;
1413
+ }
1342
1414
  const editable = field.assignee === signer;
1343
1415
  if (!editable) {
1344
1416
  if (field.type === "signature" || field.type === "initials") {
@@ -1460,7 +1532,8 @@ function SignerView({
1460
1532
  currentFieldId: selectedFieldId,
1461
1533
  onNavigate: handleNavigate,
1462
1534
  allRequiredFilled,
1463
- onSubmit: handleSubmit
1535
+ onSubmit: handleSubmit,
1536
+ submitLabel
1464
1537
  }
1465
1538
  ),
1466
1539
  submitting && /* @__PURE__ */ jsx6("div", { className: "loading-indicator", children: "Generating PDF..." })