@unlev/exeq 0.2.1 → 0.2.2
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 +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +115 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -155,12 +155,13 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
155
155
|
function PdfViewer({
|
|
156
156
|
pages,
|
|
157
157
|
fields,
|
|
158
|
-
|
|
158
|
+
selectedFieldIds,
|
|
159
159
|
onSelectField,
|
|
160
160
|
onFieldMove,
|
|
161
161
|
onFieldResize,
|
|
162
162
|
onPageClick,
|
|
163
163
|
onDropField,
|
|
164
|
+
onGroupMove,
|
|
164
165
|
mode,
|
|
165
166
|
currentSigner,
|
|
166
167
|
renderFieldContent
|
|
@@ -218,10 +219,13 @@ function PdfViewer({
|
|
|
218
219
|
FieldOverlayItem,
|
|
219
220
|
{
|
|
220
221
|
field,
|
|
221
|
-
isSelected: field.id
|
|
222
|
-
|
|
222
|
+
isSelected: selectedFieldIds.has(field.id),
|
|
223
|
+
isMultiSelected: selectedFieldIds.size > 1 && selectedFieldIds.has(field.id),
|
|
224
|
+
onSelect: (e) => onSelectField(field.id, e),
|
|
223
225
|
onMove: onFieldMove,
|
|
224
226
|
onResize: onFieldResize,
|
|
227
|
+
onGroupMove: selectedFieldIds.size > 1 && selectedFieldIds.has(field.id) ? onGroupMove : void 0,
|
|
228
|
+
selectedIds: selectedFieldIds,
|
|
225
229
|
mode,
|
|
226
230
|
currentSigner,
|
|
227
231
|
renderContent: renderFieldContent
|
|
@@ -237,9 +241,12 @@ function PdfViewer({
|
|
|
237
241
|
function FieldOverlayItem({
|
|
238
242
|
field,
|
|
239
243
|
isSelected,
|
|
244
|
+
isMultiSelected,
|
|
240
245
|
onSelect,
|
|
241
246
|
onMove,
|
|
242
247
|
onResize,
|
|
248
|
+
onGroupMove,
|
|
249
|
+
selectedIds,
|
|
243
250
|
mode,
|
|
244
251
|
currentSigner,
|
|
245
252
|
renderContent
|
|
@@ -256,7 +263,7 @@ function FieldOverlayItem({
|
|
|
256
263
|
if (mode !== "designer" || !onMove) return;
|
|
257
264
|
e.preventDefault();
|
|
258
265
|
e.stopPropagation();
|
|
259
|
-
onSelect();
|
|
266
|
+
onSelect(e);
|
|
260
267
|
const pageEl = overlayRef.current?.closest(".pdf-page");
|
|
261
268
|
if (!pageEl) return;
|
|
262
269
|
dragStartRef.current = {
|
|
@@ -265,14 +272,20 @@ function FieldOverlayItem({
|
|
|
265
272
|
fieldX: field.x,
|
|
266
273
|
fieldY: field.y
|
|
267
274
|
};
|
|
268
|
-
const handleMouseMove = (
|
|
275
|
+
const handleMouseMove = (ev) => {
|
|
269
276
|
if (!dragStartRef.current) return;
|
|
270
277
|
const rect = pageEl.getBoundingClientRect();
|
|
271
|
-
const dx = (
|
|
272
|
-
const dy = (
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
278
|
+
const dx = (ev.clientX - dragStartRef.current.startX) / rect.width * 100;
|
|
279
|
+
const dy = (ev.clientY - dragStartRef.current.startY) / rect.height * 100;
|
|
280
|
+
if (isMultiSelected && onGroupMove) {
|
|
281
|
+
onGroupMove(Array.from(selectedIds), dx, dy);
|
|
282
|
+
dragStartRef.current.startX = ev.clientX;
|
|
283
|
+
dragStartRef.current.startY = ev.clientY;
|
|
284
|
+
} else {
|
|
285
|
+
const newX = Math.max(0, Math.min(100 - field.width, dragStartRef.current.fieldX + dx));
|
|
286
|
+
const newY = Math.max(0, Math.min(100 - field.height, dragStartRef.current.fieldY + dy));
|
|
287
|
+
onMove(field.id, field.page, newX, newY);
|
|
288
|
+
}
|
|
276
289
|
};
|
|
277
290
|
const handleMouseUp = () => {
|
|
278
291
|
dragStartRef.current = null;
|
|
@@ -281,7 +294,7 @@ function FieldOverlayItem({
|
|
|
281
294
|
};
|
|
282
295
|
window.addEventListener("mousemove", handleMouseMove);
|
|
283
296
|
window.addEventListener("mouseup", handleMouseUp);
|
|
284
|
-
}, [field, mode, onMove, onSelect]);
|
|
297
|
+
}, [field, mode, onMove, onSelect, isMultiSelected, onGroupMove, selectedIds]);
|
|
285
298
|
const handleResizeMouseDown = useCallback((e) => {
|
|
286
299
|
if (mode !== "designer" || !onResize) return;
|
|
287
300
|
e.preventDefault();
|
|
@@ -329,7 +342,7 @@ function FieldOverlayItem({
|
|
|
329
342
|
},
|
|
330
343
|
onClick: (e) => {
|
|
331
344
|
e.stopPropagation();
|
|
332
|
-
onSelect();
|
|
345
|
+
onSelect(e);
|
|
333
346
|
},
|
|
334
347
|
onMouseDown: handleMouseDown,
|
|
335
348
|
children: [
|
|
@@ -762,7 +775,7 @@ function DesignerView({
|
|
|
762
775
|
}
|
|
763
776
|
const [pages, setPages] = useState3([]);
|
|
764
777
|
const [fields, setFields] = useState3(initialTemplate?.fields ?? []);
|
|
765
|
-
const [
|
|
778
|
+
const [selectedFieldIds, setSelectedFieldIds] = useState3(/* @__PURE__ */ new Set());
|
|
766
779
|
const [signerRoles, setSignerRoles] = useState3(initialTemplate?.signerRoles ?? [...DEFAULT_SIGNER_ROLES]);
|
|
767
780
|
const [activeRole, setActiveRole] = useState3("Sender");
|
|
768
781
|
const [activeFieldType, setActiveFieldType] = useState3("text");
|
|
@@ -773,7 +786,7 @@ function DesignerView({
|
|
|
773
786
|
const [newRoleName, setNewRoleName] = useState3("");
|
|
774
787
|
const [draggingFieldType, setDraggingFieldType] = useState3(null);
|
|
775
788
|
const [panelWidth, setPanelWidth] = useState3(380);
|
|
776
|
-
const [
|
|
789
|
+
const [clipboardFields, setClipboardFields] = useState3([]);
|
|
777
790
|
const dragGhostRef = useRef3(null);
|
|
778
791
|
const resizingRef = useRef3(false);
|
|
779
792
|
const lastStylesRef = useRef3({});
|
|
@@ -827,7 +840,7 @@ function DesignerView({
|
|
|
827
840
|
const sticky = lastStylesRef.current[activeFieldType];
|
|
828
841
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
829
842
|
setFields((prev) => [...prev, styledField]);
|
|
830
|
-
|
|
843
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set([styledField.id]));
|
|
831
844
|
setRightTab("properties");
|
|
832
845
|
}, [activeFieldType, activeRole, fields]);
|
|
833
846
|
const handleFieldMove = useCallback3((id, page, x, y) => {
|
|
@@ -865,8 +878,54 @@ function DesignerView({
|
|
|
865
878
|
}, []);
|
|
866
879
|
const handleFieldDelete = useCallback3((id) => {
|
|
867
880
|
setFields((prev) => prev.filter((f) => f.id !== id));
|
|
868
|
-
|
|
869
|
-
|
|
881
|
+
setSelectedFieldIds((prev) => {
|
|
882
|
+
const next = new Set(prev);
|
|
883
|
+
next.delete(id);
|
|
884
|
+
return next;
|
|
885
|
+
});
|
|
886
|
+
}, []);
|
|
887
|
+
const handleSelectField = useCallback3((id, e) => {
|
|
888
|
+
if (!id) {
|
|
889
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set());
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (e && (e.metaKey || e.ctrlKey)) {
|
|
893
|
+
setSelectedFieldIds((prev) => {
|
|
894
|
+
const next = new Set(prev);
|
|
895
|
+
if (next.has(id)) next.delete(id);
|
|
896
|
+
else next.add(id);
|
|
897
|
+
return next;
|
|
898
|
+
});
|
|
899
|
+
} else if (e && e.shiftKey && selectedFieldIds.size > 0) {
|
|
900
|
+
const lastId = Array.from(selectedFieldIds).pop();
|
|
901
|
+
const sorted = sortedFields.map((f) => f.id);
|
|
902
|
+
const a = sorted.indexOf(lastId);
|
|
903
|
+
const b = sorted.indexOf(id);
|
|
904
|
+
if (a >= 0 && b >= 0) {
|
|
905
|
+
const start = Math.min(a, b);
|
|
906
|
+
const end = Math.max(a, b);
|
|
907
|
+
const range = sorted.slice(start, end + 1);
|
|
908
|
+
setSelectedFieldIds((prev) => {
|
|
909
|
+
const next = new Set(prev);
|
|
910
|
+
range.forEach((fid) => next.add(fid));
|
|
911
|
+
return next;
|
|
912
|
+
});
|
|
913
|
+
} else {
|
|
914
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set([id]));
|
|
915
|
+
}
|
|
916
|
+
} else {
|
|
917
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set([id]));
|
|
918
|
+
}
|
|
919
|
+
setRightTab("properties");
|
|
920
|
+
}, [selectedFieldIds]);
|
|
921
|
+
const handleGroupMove = useCallback3((ids, dx, dy) => {
|
|
922
|
+
setFields((prev) => prev.map((f) => {
|
|
923
|
+
if (!ids.includes(f.id)) return f;
|
|
924
|
+
const newX = Math.max(0, Math.min(100 - f.width, f.x + dx));
|
|
925
|
+
const newY = Math.max(0, Math.min(100 - f.height, f.y + dy));
|
|
926
|
+
return { ...f, x: newX, y: newY };
|
|
927
|
+
}));
|
|
928
|
+
}, []);
|
|
870
929
|
const handleAddRole = useCallback3(() => {
|
|
871
930
|
const name = newRoleName.trim();
|
|
872
931
|
if (name && !signerRoles.includes(name)) {
|
|
@@ -929,56 +988,58 @@ function DesignerView({
|
|
|
929
988
|
const sticky = lastStylesRef.current[fieldType];
|
|
930
989
|
const styledField = sticky ? { ...field, ...sticky } : field;
|
|
931
990
|
setFields((prev) => [...prev, styledField]);
|
|
932
|
-
|
|
991
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set([styledField.id]));
|
|
933
992
|
setRightTab("properties");
|
|
934
993
|
}, [activeRole, fields]);
|
|
935
994
|
useEffect2(() => {
|
|
936
995
|
const handleKeyDown = (e) => {
|
|
937
996
|
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
938
|
-
if (
|
|
997
|
+
if (selectedFieldIds.size === 0) return;
|
|
939
998
|
const tag = (document.activeElement?.tagName || "").toLowerCase();
|
|
940
999
|
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
941
1000
|
if (document.activeElement?.isContentEditable) return;
|
|
942
1001
|
e.preventDefault();
|
|
943
|
-
|
|
944
|
-
|
|
1002
|
+
const count = selectedFieldIds.size;
|
|
1003
|
+
if (window.confirm(`Delete ${count > 1 ? `${count} fields` : "this field"}?`)) {
|
|
1004
|
+
setFields((prev) => prev.filter((f) => !selectedFieldIds.has(f.id)));
|
|
1005
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set());
|
|
945
1006
|
}
|
|
946
1007
|
};
|
|
947
1008
|
window.addEventListener("keydown", handleKeyDown);
|
|
948
1009
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
949
|
-
}, [
|
|
1010
|
+
}, [selectedFieldIds]);
|
|
950
1011
|
useEffect2(() => {
|
|
951
1012
|
const handleKeyDown = (e) => {
|
|
952
1013
|
const tag = (document.activeElement?.tagName || "").toLowerCase();
|
|
953
1014
|
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
954
1015
|
if (document.activeElement?.isContentEditable) return;
|
|
955
1016
|
const isMod = e.metaKey || e.ctrlKey;
|
|
956
|
-
if (isMod && e.key === "c" &&
|
|
957
|
-
const
|
|
958
|
-
if (
|
|
1017
|
+
if (isMod && e.key === "c" && selectedFieldIds.size > 0) {
|
|
1018
|
+
const selected = fields.filter((f) => selectedFieldIds.has(f.id));
|
|
1019
|
+
if (selected.length > 0) {
|
|
959
1020
|
e.preventDefault();
|
|
960
|
-
|
|
1021
|
+
setClipboardFields(selected);
|
|
961
1022
|
}
|
|
962
1023
|
}
|
|
963
|
-
if (isMod && e.key === "v" &&
|
|
1024
|
+
if (isMod && e.key === "v" && clipboardFields.length > 0) {
|
|
964
1025
|
e.preventDefault();
|
|
965
|
-
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
value: ""
|
|
973
|
-
};
|
|
974
|
-
setFields((prev) => [...prev,
|
|
975
|
-
|
|
1026
|
+
let existingLabels = fields.map((f) => f.label);
|
|
1027
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
1028
|
+
const newFields = clipboardFields.map((cf) => {
|
|
1029
|
+
const label = uniqueLabel(cf.label, existingLabels);
|
|
1030
|
+
existingLabels.push(label);
|
|
1031
|
+
const id = generateId();
|
|
1032
|
+
newIds.add(id);
|
|
1033
|
+
return { ...cf, id, label, x: cf.x + 2, y: cf.y + 2, value: "" };
|
|
1034
|
+
});
|
|
1035
|
+
setFields((prev) => [...prev, ...newFields]);
|
|
1036
|
+
setSelectedFieldIds(newIds);
|
|
976
1037
|
setRightTab("properties");
|
|
977
1038
|
}
|
|
978
1039
|
};
|
|
979
1040
|
window.addEventListener("keydown", handleKeyDown);
|
|
980
1041
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
981
|
-
}, [
|
|
1042
|
+
}, [selectedFieldIds, fields, clipboardFields]);
|
|
982
1043
|
const handleResizeStart = useCallback3((e) => {
|
|
983
1044
|
e.preventDefault();
|
|
984
1045
|
resizingRef.current = true;
|
|
@@ -1003,7 +1064,7 @@ function DesignerView({
|
|
|
1003
1064
|
if (Math.abs(a.y - b.y) > bandThreshold) return a.y - b.y;
|
|
1004
1065
|
return a.x - b.x;
|
|
1005
1066
|
});
|
|
1006
|
-
const selectedField = fields.find((f) => f.id ===
|
|
1067
|
+
const selectedField = selectedFieldIds.size === 1 ? fields.find((f) => f.id === Array.from(selectedFieldIds)[0]) || null : null;
|
|
1007
1068
|
const renderFieldContent = useCallback3((field) => {
|
|
1008
1069
|
if (field.type === "blackout" || field.type === "whiteout") {
|
|
1009
1070
|
return null;
|
|
@@ -1123,13 +1184,11 @@ function DesignerView({
|
|
|
1123
1184
|
{
|
|
1124
1185
|
pages,
|
|
1125
1186
|
fields,
|
|
1126
|
-
|
|
1127
|
-
onSelectField:
|
|
1128
|
-
setSelectedFieldId(id);
|
|
1129
|
-
if (id) setRightTab("properties");
|
|
1130
|
-
},
|
|
1187
|
+
selectedFieldIds,
|
|
1188
|
+
onSelectField: handleSelectField,
|
|
1131
1189
|
onFieldMove: handleFieldMove,
|
|
1132
1190
|
onFieldResize: handleFieldResize,
|
|
1191
|
+
onGroupMove: handleGroupMove,
|
|
1133
1192
|
onPageClick: handlePageClick,
|
|
1134
1193
|
onDropField: handleDropOnPage,
|
|
1135
1194
|
mode: "designer",
|
|
@@ -1166,7 +1225,13 @@ function DesignerView({
|
|
|
1166
1225
|
)
|
|
1167
1226
|
] }),
|
|
1168
1227
|
/* @__PURE__ */ jsxs4("div", { className: "panel-tab-content", children: [
|
|
1169
|
-
rightTab === "properties" && /* @__PURE__ */ jsx4(Fragment, { children:
|
|
1228
|
+
rightTab === "properties" && /* @__PURE__ */ jsx4(Fragment, { children: selectedFieldIds.size > 1 ? /* @__PURE__ */ jsxs4("div", { className: "panel-empty", children: [
|
|
1229
|
+
/* @__PURE__ */ jsxs4("strong", { children: [
|
|
1230
|
+
selectedFieldIds.size,
|
|
1231
|
+
" fields selected"
|
|
1232
|
+
] }),
|
|
1233
|
+
/* @__PURE__ */ jsx4("p", { children: "Drag to move as a group. Press Delete to remove all. Cmd/Ctrl+C to copy." })
|
|
1234
|
+
] }) : selectedField ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1170
1235
|
/* @__PURE__ */ jsx4(
|
|
1171
1236
|
FieldPropertyPanel,
|
|
1172
1237
|
{
|
|
@@ -1213,9 +1278,9 @@ function DesignerView({
|
|
|
1213
1278
|
rightTab === "fields" && /* @__PURE__ */ jsx4(Fragment, { children: fields.length === 0 ? /* @__PURE__ */ jsx4("div", { className: "panel-empty", children: "No fields yet. Drag a field from the left palette onto the PDF, or click on the PDF to place one." }) : /* @__PURE__ */ jsx4("div", { className: "field-list", children: sortedFields.map((f) => /* @__PURE__ */ jsxs4(
|
|
1214
1279
|
"div",
|
|
1215
1280
|
{
|
|
1216
|
-
className: `field-list-item ${f.id
|
|
1281
|
+
className: `field-list-item ${selectedFieldIds.has(f.id) ? "active" : ""}`,
|
|
1217
1282
|
onClick: () => {
|
|
1218
|
-
|
|
1283
|
+
setSelectedFieldIds(/* @__PURE__ */ new Set([f.id]));
|
|
1219
1284
|
setRightTab("properties");
|
|
1220
1285
|
},
|
|
1221
1286
|
children: [
|
|
@@ -1872,8 +1937,8 @@ function SignerView({
|
|
|
1872
1937
|
{
|
|
1873
1938
|
pages,
|
|
1874
1939
|
fields,
|
|
1875
|
-
selectedFieldId,
|
|
1876
|
-
onSelectField: setSelectedFieldId,
|
|
1940
|
+
selectedFieldIds: new Set(selectedFieldId ? [selectedFieldId] : []),
|
|
1941
|
+
onSelectField: (id) => setSelectedFieldId(id),
|
|
1877
1942
|
mode: "signer",
|
|
1878
1943
|
currentSigner: signer,
|
|
1879
1944
|
renderFieldContent
|