@josephomills/esign 0.3.0 → 0.5.0

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.
@@ -38,8 +38,8 @@ interface ViewerPlacement {
38
38
  interface PdfViewerProps {
39
39
  /** Token-gated source PDF URL. */
40
40
  url: string;
41
- /** Optional signature-box hint, drawn on its page at normalized coords. */
42
- placement?: ViewerPlacement;
41
+ /** Signature-box hints, each drawn on its page at normalized coords. */
42
+ placements?: ViewerPlacement[];
43
43
  /** Override the pdf.js worker (defaults to the unpkg .mjs for the bundled version). */
44
44
  workerSrc?: string;
45
45
  primaryColor?: string;
@@ -49,7 +49,32 @@ interface PdfViewerProps {
49
49
  * box overlaid where the manager placed it. Falls back to an <iframe> + download
50
50
  * link if pdf.js fails to load — so the document is always readable.
51
51
  */
52
- declare function PdfViewer({ url, placement, workerSrc, primaryColor }: PdfViewerProps): react.JSX.Element;
52
+ declare function PdfViewer({ url, placements, workerSrc, primaryColor }: PdfViewerProps): react.JSX.Element;
53
+
54
+ interface DesignerPlacement {
55
+ id: string;
56
+ label: string;
57
+ page: number;
58
+ x: number;
59
+ y: number;
60
+ w: number;
61
+ h: number;
62
+ }
63
+ interface FieldDesignerProps {
64
+ /** The chosen PDF's bytes (read client-side before upload). */
65
+ pdfData: Uint8Array;
66
+ value: DesignerPlacement[];
67
+ onChange: (fields: DesignerPlacement[]) => void;
68
+ workerSrc?: string;
69
+ primaryColor?: string;
70
+ }
71
+ /**
72
+ * Place + edit one or more named signature fields on a pdf.js-rendered page.
73
+ * Touch + mouse (Pointer Events): drag empty space to add a field, drag a field
74
+ * to move, drag a corner to resize, × to remove. Fields are listed and renameable
75
+ * on the side (and wrap below on narrow screens). Each box shows its name.
76
+ */
77
+ declare function FieldDesigner({ pdfData, value, onChange, workerSrc, primaryColor, }: FieldDesignerProps): react.JSX.Element;
53
78
 
54
79
  interface SigningBranding {
55
80
  appName?: string;
@@ -62,7 +87,7 @@ interface SigningExperienceProps {
62
87
  /** Submit endpoint (POST /sign/<token>/submit). */
63
88
  submitUrl: string;
64
89
  documentTitle: string;
65
- placement?: ViewerPlacement;
90
+ placements?: ViewerPlacement[];
66
91
  branding?: SigningBranding;
67
92
  /** Called after a successful signature submit (host navigates to /done). */
68
93
  onSigned?: () => void;
@@ -75,4 +100,4 @@ interface SigningExperienceProps {
75
100
  */
76
101
  declare function SigningExperience(props: SigningExperienceProps): react.JSX.Element;
77
102
 
78
- export { ConsentBlock, type ConsentBlockProps, type ConsentValue, PdfViewer, type PdfViewerProps, SignaturePad, type SignaturePadProps, type SigningBranding, SigningExperience, type SigningExperienceProps, type ViewerPlacement };
103
+ export { ConsentBlock, type ConsentBlockProps, type ConsentValue, type DesignerPlacement, FieldDesigner, type FieldDesignerProps, PdfViewer, type PdfViewerProps, SignaturePad, type SignaturePadProps, type SigningBranding, SigningExperience, type SigningExperienceProps, type ViewerPlacement };
@@ -38,8 +38,8 @@ interface ViewerPlacement {
38
38
  interface PdfViewerProps {
39
39
  /** Token-gated source PDF URL. */
40
40
  url: string;
41
- /** Optional signature-box hint, drawn on its page at normalized coords. */
42
- placement?: ViewerPlacement;
41
+ /** Signature-box hints, each drawn on its page at normalized coords. */
42
+ placements?: ViewerPlacement[];
43
43
  /** Override the pdf.js worker (defaults to the unpkg .mjs for the bundled version). */
44
44
  workerSrc?: string;
45
45
  primaryColor?: string;
@@ -49,7 +49,32 @@ interface PdfViewerProps {
49
49
  * box overlaid where the manager placed it. Falls back to an <iframe> + download
50
50
  * link if pdf.js fails to load — so the document is always readable.
51
51
  */
52
- declare function PdfViewer({ url, placement, workerSrc, primaryColor }: PdfViewerProps): react.JSX.Element;
52
+ declare function PdfViewer({ url, placements, workerSrc, primaryColor }: PdfViewerProps): react.JSX.Element;
53
+
54
+ interface DesignerPlacement {
55
+ id: string;
56
+ label: string;
57
+ page: number;
58
+ x: number;
59
+ y: number;
60
+ w: number;
61
+ h: number;
62
+ }
63
+ interface FieldDesignerProps {
64
+ /** The chosen PDF's bytes (read client-side before upload). */
65
+ pdfData: Uint8Array;
66
+ value: DesignerPlacement[];
67
+ onChange: (fields: DesignerPlacement[]) => void;
68
+ workerSrc?: string;
69
+ primaryColor?: string;
70
+ }
71
+ /**
72
+ * Place + edit one or more named signature fields on a pdf.js-rendered page.
73
+ * Touch + mouse (Pointer Events): drag empty space to add a field, drag a field
74
+ * to move, drag a corner to resize, × to remove. Fields are listed and renameable
75
+ * on the side (and wrap below on narrow screens). Each box shows its name.
76
+ */
77
+ declare function FieldDesigner({ pdfData, value, onChange, workerSrc, primaryColor, }: FieldDesignerProps): react.JSX.Element;
53
78
 
54
79
  interface SigningBranding {
55
80
  appName?: string;
@@ -62,7 +87,7 @@ interface SigningExperienceProps {
62
87
  /** Submit endpoint (POST /sign/<token>/submit). */
63
88
  submitUrl: string;
64
89
  documentTitle: string;
65
- placement?: ViewerPlacement;
90
+ placements?: ViewerPlacement[];
66
91
  branding?: SigningBranding;
67
92
  /** Called after a successful signature submit (host navigates to /done). */
68
93
  onSigned?: () => void;
@@ -75,4 +100,4 @@ interface SigningExperienceProps {
75
100
  */
76
101
  declare function SigningExperience(props: SigningExperienceProps): react.JSX.Element;
77
102
 
78
- export { ConsentBlock, type ConsentBlockProps, type ConsentValue, PdfViewer, type PdfViewerProps, SignaturePad, type SignaturePadProps, type SigningBranding, SigningExperience, type SigningExperienceProps, type ViewerPlacement };
103
+ export { ConsentBlock, type ConsentBlockProps, type ConsentValue, type DesignerPlacement, FieldDesigner, type FieldDesignerProps, PdfViewer, type PdfViewerProps, SignaturePad, type SignaturePadProps, type SigningBranding, SigningExperience, type SigningExperienceProps, type ViewerPlacement };
package/dist/ui/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import SignaturePadLib from 'signature_pad';
3
3
  import { useState, useRef, useEffect } from 'react';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  // src/ui/SignaturePad.tsx
7
7
  function SignaturePad({ primaryColor = "#4f46e5", onChange }) {
@@ -165,7 +165,7 @@ function ConsentBlock({ value, onChange, primaryColor = "#4f46e5" }) {
165
165
  ] })
166
166
  ] });
167
167
  }
168
- function PdfViewer({ url, placement, workerSrc, primaryColor = "#4f46e5" }) {
168
+ function PdfViewer({ url, placements, workerSrc, primaryColor = "#4f46e5" }) {
169
169
  const containerRef = useRef(null);
170
170
  const [failed, setFailed] = useState(false);
171
171
  useEffect(() => {
@@ -196,12 +196,13 @@ function PdfViewer({ url, placement, workerSrc, primaryColor = "#4f46e5" }) {
196
196
  wrap.style.marginBottom = "14px";
197
197
  wrap.style.boxShadow = "0 1px 4px rgba(0,0,0,0.12)";
198
198
  wrap.appendChild(canvas);
199
- if (placement && placement.page === p) {
199
+ for (const pl of placements ?? []) {
200
+ if (pl.page !== p) continue;
200
201
  const box = document.createElement("div");
201
- box.style.cssText = `position:absolute;left:${placement.x * 100}%;top:${placement.y * 100}%;width:${placement.w * 100}%;height:${placement.h * 100}%;border:2px dashed ${primaryColor};background:${primaryColor}1a;border-radius:4px;pointer-events:none;`;
202
+ box.style.cssText = `position:absolute;left:${pl.x * 100}%;top:${pl.y * 100}%;width:${pl.w * 100}%;height:${pl.h * 100}%;border:2px dashed ${primaryColor};background:${primaryColor}1a;border-radius:4px;pointer-events:none;display:flex;align-items:center;justify-content:center;overflow:hidden;`;
202
203
  const label = document.createElement("span");
203
- label.textContent = "Signature";
204
- label.style.cssText = `position:absolute;top:-18px;left:0;font-size:11px;font-weight:600;color:${primaryColor};`;
204
+ label.textContent = "\u270D Sign here";
205
+ label.style.cssText = `font-size:11px;font-weight:600;color:${primaryColor};opacity:0.85;white-space:nowrap;`;
205
206
  box.appendChild(label);
206
207
  wrap.appendChild(box);
207
208
  }
@@ -218,7 +219,7 @@ function PdfViewer({ url, placement, workerSrc, primaryColor = "#4f46e5" }) {
218
219
  return () => {
219
220
  cancelled = true;
220
221
  };
221
- }, [url, placement, workerSrc, primaryColor]);
222
+ }, [url, placements, workerSrc, primaryColor]);
222
223
  if (failed) {
223
224
  return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
224
225
  /* @__PURE__ */ jsx(
@@ -234,6 +235,374 @@ function PdfViewer({ url, placement, workerSrc, primaryColor = "#4f46e5" }) {
234
235
  }
235
236
  return /* @__PURE__ */ jsx("div", { ref: containerRef, style: { width: "100%" } });
236
237
  }
238
+ var clamp = (v, min, max) => Math.min(Math.max(v, min), max);
239
+ var MIN_W = 0.04;
240
+ var MIN_H = 0.02;
241
+ var newId = () => typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
242
+ function FieldDesigner({
243
+ pdfData,
244
+ value,
245
+ onChange,
246
+ workerSrc,
247
+ primaryColor = "#4f46e5"
248
+ }) {
249
+ const [numPages, setNumPages] = useState(0);
250
+ const [page, setPage] = useState(value[0]?.page ?? 1);
251
+ const [failed, setFailed] = useState(false);
252
+ const [selectedId, setSelectedId] = useState(value[0]?.id ?? null);
253
+ const [drag, setDrag] = useState(null);
254
+ const [live, setLive] = useState(null);
255
+ const stageRef = useRef(null);
256
+ const canvasRef = useRef(null);
257
+ const docRef = useRef(null);
258
+ useEffect(() => {
259
+ let cancelled = false;
260
+ void (async () => {
261
+ try {
262
+ const pdfjs = await import('pdfjs-dist');
263
+ pdfjs.GlobalWorkerOptions.workerSrc = workerSrc ?? `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
264
+ const doc = await pdfjs.getDocument({ data: pdfData.slice() }).promise;
265
+ if (cancelled) return;
266
+ docRef.current = doc;
267
+ setNumPages(doc.numPages);
268
+ setPage((p) => Math.min(p, doc.numPages));
269
+ } catch {
270
+ if (!cancelled) setFailed(true);
271
+ }
272
+ })();
273
+ return () => {
274
+ cancelled = true;
275
+ };
276
+ }, [pdfData, workerSrc]);
277
+ useEffect(() => {
278
+ let cancelled = false;
279
+ void (async () => {
280
+ const doc = docRef.current;
281
+ const canvas = canvasRef.current;
282
+ if (!doc || !canvas) return;
283
+ const pageObj = await doc.getPage(page);
284
+ if (cancelled) return;
285
+ const width = stageRef.current?.clientWidth || 480;
286
+ const base = pageObj.getViewport({ scale: 1 });
287
+ const viewport = pageObj.getViewport({ scale: width / base.width });
288
+ const ratio = Math.max(window.devicePixelRatio || 1, 1);
289
+ canvas.width = Math.floor(viewport.width * ratio);
290
+ canvas.height = Math.floor(viewport.height * ratio);
291
+ canvas.style.width = "100%";
292
+ canvas.style.display = "block";
293
+ const ctx = canvas.getContext("2d");
294
+ if (!ctx) return;
295
+ ctx.scale(ratio, ratio);
296
+ await pageObj.render({ canvasContext: ctx, viewport, canvas }).promise;
297
+ })();
298
+ return () => {
299
+ cancelled = true;
300
+ };
301
+ }, [page, numPages]);
302
+ function rel(e) {
303
+ const r = stageRef.current.getBoundingClientRect();
304
+ return {
305
+ x: clamp((e.clientX - r.left) / r.width, 0, 1),
306
+ y: clamp((e.clientY - r.top) / r.height, 0, 1)
307
+ };
308
+ }
309
+ function onPointerMove(e) {
310
+ if (!drag) return;
311
+ const p = rel(e);
312
+ let b;
313
+ if (drag.mode === "new") {
314
+ b = {
315
+ x: Math.min(drag.start.x, p.x),
316
+ y: Math.min(drag.start.y, p.y),
317
+ w: Math.abs(p.x - drag.start.x),
318
+ h: Math.abs(p.y - drag.start.y)
319
+ };
320
+ } else if (drag.mode === "move") {
321
+ const dx = p.x - drag.start.x;
322
+ const dy = p.y - drag.start.y;
323
+ b = {
324
+ x: clamp(drag.orig.x + dx, 0, 1 - drag.orig.w),
325
+ y: clamp(drag.orig.y + dy, 0, 1 - drag.orig.h),
326
+ w: drag.orig.w,
327
+ h: drag.orig.h
328
+ };
329
+ } else {
330
+ let x1 = drag.orig.x;
331
+ let y1 = drag.orig.y;
332
+ let x2 = drag.orig.x + drag.orig.w;
333
+ let y2 = drag.orig.y + drag.orig.h;
334
+ if (drag.handle[0] === "n") y1 = p.y;
335
+ else y2 = p.y;
336
+ if (drag.handle[1] === "w") x1 = p.x;
337
+ else x2 = p.x;
338
+ b = { x: Math.min(x1, x2), y: Math.min(y1, y2), w: Math.abs(x2 - x1), h: Math.abs(y2 - y1) };
339
+ }
340
+ setLive(b);
341
+ }
342
+ function onPointerUp() {
343
+ if (drag && live && live.w >= MIN_W && live.h >= MIN_H) {
344
+ if (drag.mode === "new") {
345
+ const f = {
346
+ id: newId(),
347
+ label: value.length === 0 ? "Signature" : `Signature ${value.length + 1}`,
348
+ page,
349
+ ...live
350
+ };
351
+ onChange([...value, f]);
352
+ setSelectedId(f.id);
353
+ } else {
354
+ onChange(value.map((x) => x.id === drag.id ? { ...x, ...live } : x));
355
+ }
356
+ }
357
+ setDrag(null);
358
+ setLive(null);
359
+ }
360
+ function removeField(id) {
361
+ onChange(value.filter((f) => f.id !== id));
362
+ if (selectedId === id) setSelectedId(null);
363
+ }
364
+ function rename(id, label) {
365
+ onChange(value.map((f) => f.id === id ? { ...f, label } : f));
366
+ }
367
+ const handle = (id, geom, c) => {
368
+ const cx = c[1] === "w" ? geom.x : geom.x + geom.w;
369
+ const cy = c[0] === "n" ? geom.y : geom.y + geom.h;
370
+ const cursor = c === "nw" || c === "se" ? "nwse-resize" : "nesw-resize";
371
+ return /* @__PURE__ */ jsx(
372
+ "div",
373
+ {
374
+ onPointerDown: (e) => {
375
+ e.stopPropagation();
376
+ setDrag({ mode: "resize", id, handle: c, orig: geom });
377
+ },
378
+ style: {
379
+ position: "absolute",
380
+ left: `${cx * 100}%`,
381
+ top: `${cy * 100}%`,
382
+ width: 13,
383
+ height: 13,
384
+ marginLeft: -7,
385
+ marginTop: -7,
386
+ background: "#fff",
387
+ border: `2px solid ${primaryColor}`,
388
+ borderRadius: 2,
389
+ cursor,
390
+ touchAction: "none"
391
+ }
392
+ },
393
+ c
394
+ );
395
+ };
396
+ if (failed) {
397
+ return /* @__PURE__ */ jsx("div", { style: { color: "#b91c1c", fontSize: 14 }, children: "Could not render this PDF for placement. Please check the file is a valid, unencrypted PDF." });
398
+ }
399
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: 16, alignItems: "flex-start" }, children: [
400
+ /* @__PURE__ */ jsxs("div", { style: { flex: "1 1 340px", minWidth: 260 }, children: [
401
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }, children: [
402
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: "#6b7280" }, children: "Drag a box where a signature goes." }),
403
+ numPages > 1 ? /* @__PURE__ */ jsxs("label", { style: { marginLeft: "auto", fontSize: 13, color: "#374151" }, children: [
404
+ "Page",
405
+ " ",
406
+ /* @__PURE__ */ jsx("select", { value: page, onChange: (e) => setPage(Number(e.target.value)), children: Array.from({ length: numPages }, (_, i) => /* @__PURE__ */ jsx("option", { value: i + 1, children: i + 1 }, i)) })
407
+ ] }) : null
408
+ ] }),
409
+ /* @__PURE__ */ jsxs(
410
+ "div",
411
+ {
412
+ ref: stageRef,
413
+ onPointerDown: (e) => setDrag({ mode: "new", start: rel(e) }),
414
+ onPointerMove,
415
+ onPointerUp,
416
+ onPointerLeave: onPointerUp,
417
+ style: {
418
+ position: "relative",
419
+ cursor: "crosshair",
420
+ userSelect: "none",
421
+ touchAction: "none",
422
+ border: "1px solid #e5e7eb",
423
+ borderRadius: 6,
424
+ overflow: "hidden"
425
+ },
426
+ children: [
427
+ /* @__PURE__ */ jsx("canvas", { ref: canvasRef }),
428
+ value.filter((f) => f.page === page).map((f) => {
429
+ const dragging = drag && drag.mode !== "new" && drag.id === f.id;
430
+ const geom = dragging && live ? live : f;
431
+ const isSel = f.id === selectedId;
432
+ return /* @__PURE__ */ jsxs("div", { children: [
433
+ /* @__PURE__ */ jsx(
434
+ "div",
435
+ {
436
+ onPointerDown: (e) => {
437
+ e.stopPropagation();
438
+ setSelectedId(f.id);
439
+ setDrag({ mode: "move", id: f.id, start: rel(e), orig: geom });
440
+ },
441
+ style: {
442
+ position: "absolute",
443
+ left: `${geom.x * 100}%`,
444
+ top: `${geom.y * 100}%`,
445
+ width: `${geom.w * 100}%`,
446
+ height: `${geom.h * 100}%`,
447
+ border: `2px ${isSel ? "solid" : "dashed"} ${primaryColor}`,
448
+ background: `${primaryColor}${isSel ? "22" : "14"}`,
449
+ borderRadius: 3,
450
+ cursor: "move",
451
+ display: "flex",
452
+ alignItems: "center",
453
+ justifyContent: "center",
454
+ overflow: "hidden",
455
+ touchAction: "none"
456
+ },
457
+ children: /* @__PURE__ */ jsxs(
458
+ "span",
459
+ {
460
+ style: {
461
+ fontSize: 12,
462
+ fontWeight: 600,
463
+ color: primaryColor,
464
+ opacity: 0.85,
465
+ whiteSpace: "nowrap",
466
+ padding: "0 4px"
467
+ },
468
+ children: [
469
+ "\u270D ",
470
+ f.label || "Signature"
471
+ ]
472
+ }
473
+ )
474
+ }
475
+ ),
476
+ isSel ? /* @__PURE__ */ jsxs(Fragment, { children: [
477
+ ["nw", "ne", "sw", "se"].map((c) => handle(f.id, geom, c)),
478
+ /* @__PURE__ */ jsx(
479
+ "button",
480
+ {
481
+ type: "button",
482
+ "aria-label": `Remove ${f.label}`,
483
+ onPointerDown: (e) => e.stopPropagation(),
484
+ onClick: (e) => {
485
+ e.stopPropagation();
486
+ removeField(f.id);
487
+ },
488
+ style: {
489
+ position: "absolute",
490
+ left: `${(geom.x + geom.w) * 100}%`,
491
+ top: `${geom.y * 100}%`,
492
+ transform: "translate(-50%, -50%)",
493
+ marginTop: -18,
494
+ width: 22,
495
+ height: 22,
496
+ borderRadius: "50%",
497
+ background: primaryColor,
498
+ color: "#fff",
499
+ border: "2px solid #fff",
500
+ boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
501
+ fontSize: 14,
502
+ lineHeight: "16px",
503
+ cursor: "pointer",
504
+ padding: 0,
505
+ touchAction: "none"
506
+ },
507
+ children: "\xD7"
508
+ }
509
+ )
510
+ ] }) : null
511
+ ] }, f.id);
512
+ }),
513
+ drag?.mode === "new" && live ? /* @__PURE__ */ jsx(
514
+ "div",
515
+ {
516
+ style: {
517
+ position: "absolute",
518
+ left: `${live.x * 100}%`,
519
+ top: `${live.y * 100}%`,
520
+ width: `${live.w * 100}%`,
521
+ height: `${live.h * 100}%`,
522
+ border: `2px dashed ${primaryColor}`,
523
+ background: `${primaryColor}22`,
524
+ borderRadius: 3,
525
+ pointerEvents: "none"
526
+ }
527
+ }
528
+ ) : null
529
+ ]
530
+ }
531
+ )
532
+ ] }),
533
+ /* @__PURE__ */ jsxs("div", { style: { flex: "1 1 200px", minWidth: 180, maxWidth: 300 }, children: [
534
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: 13, fontWeight: 600, color: "#374151", margin: "0 0 8px" }, children: [
535
+ "Signature fields (",
536
+ value.length,
537
+ ")"
538
+ ] }),
539
+ value.length === 0 ? /* @__PURE__ */ jsx("p", { style: { fontSize: 13, color: "#6b7280" }, children: "Draw a box on the page to add a field. Add as many as you need." }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: value.map((f) => /* @__PURE__ */ jsxs(
540
+ "div",
541
+ {
542
+ onClick: () => {
543
+ setSelectedId(f.id);
544
+ setPage(f.page);
545
+ },
546
+ style: {
547
+ display: "flex",
548
+ alignItems: "center",
549
+ gap: 6,
550
+ padding: "6px 8px",
551
+ borderRadius: 8,
552
+ border: `1px solid ${f.id === selectedId ? primaryColor : "#e5e7eb"}`,
553
+ background: f.id === selectedId ? `${primaryColor}0f` : "#fff",
554
+ cursor: "pointer"
555
+ },
556
+ children: [
557
+ /* @__PURE__ */ jsx(
558
+ "input",
559
+ {
560
+ value: f.label,
561
+ onClick: (e) => e.stopPropagation(),
562
+ onChange: (e) => rename(f.id, e.target.value),
563
+ placeholder: "Field name",
564
+ style: {
565
+ flex: 1,
566
+ minWidth: 0,
567
+ border: "none",
568
+ outline: "none",
569
+ background: "transparent",
570
+ fontSize: 13
571
+ }
572
+ }
573
+ ),
574
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: "#9ca3af" }, children: [
575
+ "p",
576
+ f.page
577
+ ] }),
578
+ /* @__PURE__ */ jsx(
579
+ "button",
580
+ {
581
+ type: "button",
582
+ "aria-label": `Remove ${f.label}`,
583
+ onClick: (e) => {
584
+ e.stopPropagation();
585
+ removeField(f.id);
586
+ },
587
+ style: {
588
+ border: "none",
589
+ background: "transparent",
590
+ color: "#9ca3af",
591
+ cursor: "pointer",
592
+ fontSize: 16,
593
+ lineHeight: 1,
594
+ padding: 0
595
+ },
596
+ children: "\xD7"
597
+ }
598
+ )
599
+ ]
600
+ },
601
+ f.id
602
+ )) })
603
+ ] })
604
+ ] });
605
+ }
237
606
  function SigningExperience(props) {
238
607
  const primary = props.branding?.primaryColor ?? "#4f46e5";
239
608
  const [signaturePng, setSignaturePng] = useState(null);
@@ -287,7 +656,7 @@ function SigningExperience(props) {
287
656
  PdfViewer,
288
657
  {
289
658
  url: props.sourceUrl,
290
- placement: props.placement,
659
+ placements: props.placements,
291
660
  workerSrc: props.workerSrc,
292
661
  primaryColor: primary
293
662
  }
@@ -337,6 +706,6 @@ function SigningExperience(props) {
337
706
  );
338
707
  }
339
708
 
340
- export { ConsentBlock, PdfViewer, SignaturePad, SigningExperience };
709
+ export { ConsentBlock, FieldDesigner, PdfViewer, SignaturePad, SigningExperience };
341
710
  //# sourceMappingURL=index.js.map
342
711
  //# sourceMappingURL=index.js.map