@drvillo/react-browser-e-signing 0.2.0 → 0.3.1

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.js CHANGED
@@ -101,8 +101,11 @@ function PdfViewer({
101
101
  onDocumentLoadSuccess,
102
102
  onPageDimensions,
103
103
  renderOverlay,
104
+ renderToolbarContent,
104
105
  className,
105
- workerSrc
106
+ workerSrc,
107
+ pageMode = "scroll",
108
+ currentPageIndex = 0
106
109
  }) {
107
110
  useEffect(() => {
108
111
  if (typeof window === "undefined") return;
@@ -112,12 +115,16 @@ function PdfViewer({
112
115
  }, [workerSrc]);
113
116
  if (!pdfData)
114
117
  return /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-empty", className: cn(className), children: "Upload a PDF to begin" });
118
+ const maxPageIndex = Math.max(0, numPages - 1);
119
+ const resolvedCurrentPageIndex = Math.min(maxPageIndex, Math.max(0, currentPageIndex));
120
+ const pageIndices = pageMode === "single" ? [resolvedCurrentPageIndex] : Array.from({ length: numPages }, (_, pageIndex) => pageIndex);
115
121
  return /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer", className: cn(className), children: [
116
122
  /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-toolbar", children: [
117
123
  /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-page-count", children: [
118
124
  "Pages: ",
119
125
  numPages || "\u2014"
120
126
  ] }),
127
+ renderToolbarContent ? /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-toolbar-content", children: renderToolbarContent() }) : null,
121
128
  /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-viewer-zoom", children: [
122
129
  /* @__PURE__ */ jsx(
123
130
  "button",
@@ -150,7 +157,7 @@ function PdfViewer({
150
157
  onLoadSuccess: (loadedPdf) => onDocumentLoadSuccess(loadedPdf.numPages),
151
158
  loading: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-loading", children: "Loading PDF..." }),
152
159
  error: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-error", children: "Unable to render this PDF." }),
153
- children: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-pages", children: Array.from({ length: numPages }, (_, pageIndex) => /* @__PURE__ */ jsxs(
160
+ children: /* @__PURE__ */ jsx("div", { "data-slot": "pdf-viewer-pages", children: pageIndices.map((pageIndex) => /* @__PURE__ */ jsxs(
154
161
  "div",
155
162
  {
156
163
  "data-slot": "pdf-viewer-page",
@@ -179,6 +186,49 @@ function PdfViewer({
179
186
  )
180
187
  ] });
181
188
  }
189
+ function clampPageIndex(pageIndex, numPages) {
190
+ if (numPages <= 0) return 0;
191
+ if (pageIndex < 0) return 0;
192
+ if (pageIndex > numPages - 1) return numPages - 1;
193
+ return pageIndex;
194
+ }
195
+ function PdfPageNavigator({ currentPageIndex, numPages, onPageChange, className }) {
196
+ const resolvedPageIndex = clampPageIndex(currentPageIndex, numPages);
197
+ const isEmpty = numPages <= 0;
198
+ function handlePreviousPage() {
199
+ if (isEmpty) return;
200
+ onPageChange(clampPageIndex(resolvedPageIndex - 1, numPages));
201
+ }
202
+ function handleNextPage() {
203
+ if (isEmpty) return;
204
+ onPageChange(clampPageIndex(resolvedPageIndex + 1, numPages));
205
+ }
206
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "pdf-page-navigator", className: cn(className), children: [
207
+ /* @__PURE__ */ jsx(
208
+ "button",
209
+ {
210
+ type: "button",
211
+ "data-slot": "pdf-page-navigator-button",
212
+ disabled: isEmpty || resolvedPageIndex <= 0,
213
+ onClick: handlePreviousPage,
214
+ "aria-label": "Previous page",
215
+ children: "<"
216
+ }
217
+ ),
218
+ /* @__PURE__ */ jsx("span", { "data-slot": "pdf-page-navigator-label", children: isEmpty ? "0 / 0" : `${resolvedPageIndex + 1} / ${numPages}` }),
219
+ /* @__PURE__ */ jsx(
220
+ "button",
221
+ {
222
+ type: "button",
223
+ "data-slot": "pdf-page-navigator-button",
224
+ disabled: isEmpty || resolvedPageIndex >= numPages - 1,
225
+ onClick: handleNextPage,
226
+ "aria-label": "Next page",
227
+ children: ">"
228
+ }
229
+ )
230
+ ] });
231
+ }
182
232
  var MIN_WIDTH_PERCENT = 8;
183
233
  var MIN_HEIGHT_PERCENT = 3;
184
234
  function clampPercent(value) {
@@ -263,12 +313,14 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview, classNam
263
313
  event.currentTarget.releasePointerCapture(event.pointerId);
264
314
  }
265
315
  const previewText = getFieldPreviewText(field, preview);
316
+ const isLocked = field.locked === true;
266
317
  return /* @__PURE__ */ jsxs(
267
318
  "div",
268
319
  {
269
320
  ref: rootRef,
270
321
  "data-slot": "signature-field",
271
322
  "data-field-type": field.type,
323
+ "data-locked": isLocked ? true : void 0,
272
324
  className: cn(className),
273
325
  style: {
274
326
  position: "absolute",
@@ -276,11 +328,18 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview, classNam
276
328
  top: `${field.yPercent}%`,
277
329
  width: `${field.widthPercent}%`,
278
330
  height: `${field.heightPercent}%`,
279
- userSelect: "none"
331
+ userSelect: "none",
332
+ cursor: isLocked ? "default" : void 0,
333
+ ...isLocked && {
334
+ borderStyle: "dashed",
335
+ borderWidth: 1,
336
+ borderColor: "rgba(100, 116, 139, 0.55)",
337
+ boxSizing: "border-box"
338
+ }
280
339
  },
281
- onPointerDown: handleDragPointerDown,
282
- onPointerMove: handleDragPointerMove,
283
- onPointerUp: handleDragPointerUp,
340
+ onPointerDown: isLocked ? void 0 : handleDragPointerDown,
341
+ onPointerMove: isLocked ? void 0 : handleDragPointerMove,
342
+ onPointerUp: isLocked ? void 0 : handleDragPointerUp,
284
343
  children: [
285
344
  /* @__PURE__ */ jsxs(
286
345
  "div",
@@ -306,7 +365,39 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview, classNam
306
365
  }
307
366
  ) : /* @__PURE__ */ jsx("div", { "data-slot": "signature-field-preview-text", children: previewText || "\u2014" })
308
367
  ] }),
309
- /* @__PURE__ */ jsx(
368
+ isLocked ? /* @__PURE__ */ jsx(
369
+ "div",
370
+ {
371
+ "data-slot": "signature-field-lock",
372
+ "aria-label": "Locked field",
373
+ style: {
374
+ flexShrink: 0,
375
+ display: "flex",
376
+ alignItems: "flex-start",
377
+ justifyContent: "center",
378
+ padding: "2px",
379
+ color: "rgba(71, 85, 105, 0.9)"
380
+ },
381
+ children: /* @__PURE__ */ jsxs(
382
+ "svg",
383
+ {
384
+ width: "14",
385
+ height: "14",
386
+ viewBox: "0 0 24 24",
387
+ fill: "none",
388
+ stroke: "currentColor",
389
+ strokeWidth: "2",
390
+ strokeLinecap: "round",
391
+ strokeLinejoin: "round",
392
+ "aria-hidden": true,
393
+ children: [
394
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
395
+ /* @__PURE__ */ jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
396
+ ]
397
+ }
398
+ )
399
+ }
400
+ ) : /* @__PURE__ */ jsx(
310
401
  "button",
311
402
  {
312
403
  type: "button",
@@ -323,7 +414,7 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview, classNam
323
414
  ]
324
415
  }
325
416
  ),
326
- /* @__PURE__ */ jsx(
417
+ !isLocked ? /* @__PURE__ */ jsx(
327
418
  "div",
328
419
  {
329
420
  "data-slot": "signature-field-resize",
@@ -339,7 +430,7 @@ function SignatureField({ field, onUpdateField, onRemoveField, preview, classNam
339
430
  onPointerMove: handleResizePointerMove,
340
431
  onPointerUp: handleResizePointerUp
341
432
  }
342
- )
433
+ ) : null
343
434
  ]
344
435
  }
345
436
  );
@@ -690,6 +781,87 @@ function usePdfDocument(pdfInput) {
690
781
  errorMessage
691
782
  };
692
783
  }
784
+ var PAGE_SLOT_SELECTOR = '[data-slot="pdf-viewer-page"]';
785
+ function clampPageIndex2(pageIndex, numPages) {
786
+ if (numPages <= 0) return 0;
787
+ if (pageIndex < 0) return 0;
788
+ if (pageIndex > numPages - 1) return numPages - 1;
789
+ return pageIndex;
790
+ }
791
+ function usePdfPageVisibility({
792
+ containerRef,
793
+ numPages,
794
+ threshold = 0.5
795
+ }) {
796
+ const [currentPageIndex, setCurrentPageIndex] = useState(0);
797
+ const [visiblePageIndices, setVisiblePageIndices] = useState([]);
798
+ const resolvedThreshold = useMemo(() => {
799
+ if (Number.isNaN(threshold)) return 0.5;
800
+ if (threshold < 0) return 0;
801
+ if (threshold > 1) return 1;
802
+ return threshold;
803
+ }, [threshold]);
804
+ const scrollToPage = useCallback(
805
+ (pageIndex) => {
806
+ const container = containerRef.current;
807
+ if (!container || numPages <= 0) return;
808
+ const clampedIndex = clampPageIndex2(pageIndex, numPages);
809
+ const pages = container.querySelectorAll(PAGE_SLOT_SELECTOR);
810
+ const pageElement = pages.item(clampedIndex);
811
+ if (!pageElement) return;
812
+ pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
813
+ },
814
+ [containerRef, numPages]
815
+ );
816
+ useEffect(() => {
817
+ if (numPages <= 0) {
818
+ setCurrentPageIndex(0);
819
+ setVisiblePageIndices([]);
820
+ return;
821
+ }
822
+ const container = containerRef.current;
823
+ if (!container) return;
824
+ const pages = Array.from(container.querySelectorAll(PAGE_SLOT_SELECTOR));
825
+ if (!pages.length) return;
826
+ if (typeof IntersectionObserver !== "function") {
827
+ setCurrentPageIndex(0);
828
+ setVisiblePageIndices([0]);
829
+ return;
830
+ }
831
+ const ratioByIndex = /* @__PURE__ */ new Map();
832
+ for (let index = 0; index < pages.length; index += 1) ratioByIndex.set(index, 0);
833
+ const observer = new IntersectionObserver(
834
+ (entries) => {
835
+ for (const entry of entries) {
836
+ const index = pages.indexOf(entry.target);
837
+ if (index < 0) continue;
838
+ ratioByIndex.set(index, entry.isIntersecting ? entry.intersectionRatio : 0);
839
+ }
840
+ const nextVisible = Array.from(ratioByIndex.entries()).filter(([, ratio]) => ratio > 0).map(([index]) => index).sort((a, b) => a - b);
841
+ setVisiblePageIndices(nextVisible);
842
+ let maxRatio = -1;
843
+ let mostVisibleIndex = 0;
844
+ for (const [index, ratio] of ratioByIndex.entries()) {
845
+ if (ratio > maxRatio) {
846
+ maxRatio = ratio;
847
+ mostVisibleIndex = index;
848
+ }
849
+ }
850
+ setCurrentPageIndex(clampPageIndex2(mostVisibleIndex, numPages));
851
+ },
852
+ { threshold: [0, resolvedThreshold, 1] }
853
+ );
854
+ for (const pageElement of pages) observer.observe(pageElement);
855
+ return () => {
856
+ observer.disconnect();
857
+ };
858
+ }, [containerRef, numPages, resolvedThreshold]);
859
+ return {
860
+ currentPageIndex: clampPageIndex2(currentPageIndex, numPages),
861
+ visiblePageIndices,
862
+ scrollToPage
863
+ };
864
+ }
693
865
  function clampPercent2(value) {
694
866
  if (Number.isNaN(value)) return 0;
695
867
  if (value < 0) return 0;
@@ -705,7 +877,7 @@ function buildFieldId() {
705
877
  function useFieldPlacement(options = {}) {
706
878
  const defaultWidthPercent = options.defaultWidthPercent ?? 25;
707
879
  const defaultHeightPercent = options.defaultHeightPercent ?? 5;
708
- const [fields, setFields] = useState([]);
880
+ const [fields, setFields] = useState(options.initialFields ?? []);
709
881
  const addField = useCallback(
710
882
  ({ pageIndex, type, xPercent, yPercent }) => {
711
883
  const field = {
@@ -962,6 +1134,7 @@ var SLOTS = {
962
1134
  pdfViewer: "pdf-viewer",
963
1135
  pdfViewerEmpty: "pdf-viewer-empty",
964
1136
  pdfViewerToolbar: "pdf-viewer-toolbar",
1137
+ pdfViewerToolbarContent: "pdf-viewer-toolbar-content",
965
1138
  pdfViewerPageCount: "pdf-viewer-page-count",
966
1139
  pdfViewerZoom: "pdf-viewer-zoom",
967
1140
  pdfViewerZoomButton: "pdf-viewer-zoom-button",
@@ -970,6 +1143,9 @@ var SLOTS = {
970
1143
  pdfViewerPage: "pdf-viewer-page",
971
1144
  pdfViewerLoading: "pdf-viewer-loading",
972
1145
  pdfViewerError: "pdf-viewer-error",
1146
+ pdfPageNavigator: "pdf-page-navigator",
1147
+ pdfPageNavigatorButton: "pdf-page-navigator-button",
1148
+ pdfPageNavigatorLabel: "pdf-page-navigator-label",
973
1149
  fieldOverlay: "field-overlay",
974
1150
  signatureField: "signature-field",
975
1151
  signatureFieldContent: "signature-field-content",
@@ -979,6 +1155,7 @@ var SLOTS = {
979
1155
  signatureFieldPreviewText: "signature-field-preview-text",
980
1156
  signatureFieldRemove: "signature-field-remove",
981
1157
  signatureFieldResize: "signature-field-resize",
1158
+ signatureFieldLock: "signature-field-lock",
982
1159
  fieldPalette: "field-palette",
983
1160
  fieldPaletteButton: "field-palette-button",
984
1161
  signerPanel: "signer-panel",
@@ -1016,6 +1193,6 @@ var defaults = {
1016
1193
  DEFAULT_FIELD_HEIGHT_PERCENT: 5
1017
1194
  };
1018
1195
 
1019
- export { FieldOverlay, FieldPalette, PdfViewer, SIGNATURE_FONTS, SLOTS, SignatureField, SignaturePad, SignaturePreview, SignerDetailsPanel, SigningComplete, configure, defaults, loadSignatureFont, mapFromPoints, mapToPoints, modifyPdf, sha256, useFieldPlacement, usePdfDocument, useSignatureRenderer };
1196
+ export { FieldOverlay, FieldPalette, PdfPageNavigator, PdfViewer, SIGNATURE_FONTS, SLOTS, SignatureField, SignaturePad, SignaturePreview, SignerDetailsPanel, SigningComplete, configure, defaults, loadSignatureFont, mapFromPoints, mapToPoints, modifyPdf, sha256, useFieldPlacement, usePdfDocument, usePdfPageVisibility, useSignatureRenderer };
1020
1197
  //# sourceMappingURL=index.js.map
1021
1198
  //# sourceMappingURL=index.js.map