idmission-web-sdk 2.3.21 → 2.3.23

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.
@@ -211,7 +211,7 @@
211
211
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
212
212
  };
213
213
 
214
- var webSdkVersion = '2.3.21';
214
+ var webSdkVersion = '2.3.23';
215
215
 
216
216
  function getPlatform() {
217
217
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -9354,14 +9354,13 @@
9354
9354
  });
9355
9355
  }
9356
9356
 
9357
- function useFrameLoop(fn, _a) {
9358
- var _b = _a.throttleMs,
9359
- throttleMs = _b === void 0 ? 0 : _b,
9360
- _c = _a.autoStart,
9361
- autoStart = _c === void 0 ? false : _c;
9362
- var _d = React.useState(false),
9363
- running = _d[0],
9364
- setRunning = _d[1];
9357
+ function useFrameLoop(fn, options) {
9358
+ if (options === void 0) {
9359
+ options = {};
9360
+ }
9361
+ var _a = React.useState(false),
9362
+ running = _a[0],
9363
+ setRunning = _a[1];
9365
9364
  var startedAtRef = React.useRef(null);
9366
9365
  var loopId = React.useRef(0);
9367
9366
  var frameId = React.useRef(0);
@@ -9369,36 +9368,36 @@
9369
9368
  if (!running) return;
9370
9369
  var timer;
9371
9370
  var currentLoopId = loopId.current;
9372
- function renderPrediction() {
9371
+ function hotLoop() {
9373
9372
  return __awaiter(this, void 0, void 0, function () {
9374
9373
  var start, timeRunning, took, amountToThrottle;
9375
- var _a, _b;
9376
- return __generator(this, function (_c) {
9377
- switch (_c.label) {
9374
+ var _a, _b, _c;
9375
+ return __generator(this, function (_d) {
9376
+ switch (_d.label) {
9378
9377
  case 0:
9379
9378
  if (currentLoopId !== loopId.current) return [2 /*return*/];
9380
9379
  start = new Date().getTime();
9381
9380
  timeRunning = start - ((_b = (_a = startedAtRef.current) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0);
9382
9381
  return [4 /*yield*/, fn(frameId.current, timeRunning)];
9383
9382
  case 1:
9384
- _c.sent();
9383
+ _d.sent();
9385
9384
  took = new Date().getTime() - start;
9386
- amountToThrottle = Math.max((throttleMs !== null && throttleMs !== void 0 ? throttleMs : 0) - took, 0);
9385
+ amountToThrottle = Math.max(((_c = options.throttleMs) !== null && _c !== void 0 ? _c : 0) - took, 0);
9387
9386
  timer = setTimeout(function () {
9388
- frameId.current = requestAnimationFrame(renderPrediction);
9387
+ frameId.current = requestAnimationFrame(hotLoop);
9389
9388
  }, amountToThrottle);
9390
9389
  return [2 /*return*/];
9391
9390
  }
9392
9391
  });
9393
9392
  });
9394
9393
  }
9395
- renderPrediction().then();
9394
+ void hotLoop();
9396
9395
  return function () {
9397
9396
  loopId.current += 1;
9398
9397
  if (frameId.current) cancelAnimationFrame(frameId.current);
9399
9398
  if (timer) clearTimeout(timer);
9400
9399
  };
9401
- }, [fn, running, throttleMs]);
9400
+ }, [fn, running, options.throttleMs]);
9402
9401
  var start = React.useCallback(function () {
9403
9402
  startedAtRef.current = new Date();
9404
9403
  setRunning(true);
@@ -9409,11 +9408,9 @@
9409
9408
  startedAtRef.current = null;
9410
9409
  }, []);
9411
9410
  React.useEffect(function startAutomatically() {
9412
- if (autoStart) start();
9413
- return function () {
9414
- stop();
9415
- };
9416
- }, [autoStart, start, stop]);
9411
+ if (options.autoStart) start();
9412
+ return stop;
9413
+ }, [options.autoStart, start, stop]);
9417
9414
  return {
9418
9415
  start: start,
9419
9416
  stop: stop
@@ -23236,9 +23233,6 @@
23236
23233
  var audioRecorder = null;
23237
23234
  var videoChunks = [];
23238
23235
  var audioChunks = [];
23239
- function getVideoRecorder() {
23240
- return videoRecorder;
23241
- }
23242
23236
  function setVideoRecorder(recorder) {
23243
23237
  videoRecorder = recorder;
23244
23238
  }
@@ -23266,20 +23260,22 @@
23266
23260
  return _assign(_assign({}, initialState$2), {
23267
23261
  startRecordingVideo: function startRecordingVideo(camera, audioStream) {
23268
23262
  var _a, _b, _c;
23269
- var videoStream = get().mergeAVStreams ? new MediaStream(__spreadArray(__spreadArray([], (_b = (_a = camera === null || camera === void 0 ? void 0 : camera.stream) === null || _a === void 0 ? void 0 : _a.getTracks()) !== null && _b !== void 0 ? _b : [], true), (_c = audioStream === null || audioStream === void 0 ? void 0 : audioStream.getTracks()) !== null && _c !== void 0 ? _c : [], true)) : camera.stream;
23263
+ var _d = get(),
23264
+ mergeAVStreams = _d.mergeAVStreams,
23265
+ startRecordingAudio = _d.startRecordingAudio;
23266
+ var videoStream = mergeAVStreams ? new MediaStream(__spreadArray(__spreadArray([], (_b = (_a = camera === null || camera === void 0 ? void 0 : camera.stream) === null || _a === void 0 ? void 0 : _a.getTracks()) !== null && _b !== void 0 ? _b : [], true), (_c = audioStream === null || audioStream === void 0 ? void 0 : audioStream.getTracks()) !== null && _c !== void 0 ? _c : [], true)) : camera.stream;
23270
23267
  if (!videoStream) return;
23271
23268
  clearVideoChunks();
23272
- setVideoRecorder(null);
23269
+ videoRecorder = null;
23273
23270
  set({
23274
23271
  isRecordingVideo: true,
23275
23272
  videoRecordingStopped: false,
23276
23273
  videoRecordingIntentionallyStopped: false
23277
23274
  });
23278
- var videoRecorder = new MediaRecorder(videoStream, {
23275
+ videoRecorder = new MediaRecorder(videoStream, {
23279
23276
  videoBitsPerSecond: 270000,
23280
23277
  audioBitsPerSecond: 32000
23281
23278
  });
23282
- setVideoRecorder(videoRecorder);
23283
23279
  videoRecorder.ondataavailable = function (e) {
23284
23280
  videoChunks.push(e.data);
23285
23281
  };
@@ -23290,12 +23286,14 @@
23290
23286
  };
23291
23287
  videoRecorder.start(100);
23292
23288
  setTimeout(function () {
23293
- var videoRecorder = getVideoRecorder();
23294
23289
  if (!videoRecorder || videoRecorder.state === 'inactive') {
23295
23290
  log('media recorder is inactive!');
23296
23291
  // TODO: figure out what to do here
23297
23292
  }
23298
23293
  }, 100);
23294
+ if (audioStream && !mergeAVStreams) {
23295
+ startRecordingAudio(audioStream);
23296
+ }
23299
23297
  },
23300
23298
  stopRecordingVideo: function stopRecordingVideo() {
23301
23299
  set({
@@ -23413,16 +23411,7 @@
23413
23411
  };
23414
23412
 
23415
23413
  var signatureRecorder = null;
23416
- var getSignatureRecorder = function getSignatureRecorder() {
23417
- return signatureRecorder;
23418
- };
23419
- var setSignatureRecorder = function setSignatureRecorder(recorder) {
23420
- return signatureRecorder = recorder;
23421
- };
23422
23414
  var signatureChunks = [];
23423
- var clearSignatureChunks = function clearSignatureChunks() {
23424
- return signatureChunks = [];
23425
- };
23426
23415
  var videoSignatureInitialState = {
23427
23416
  startRecording: function startRecording() {
23428
23417
  return null;
@@ -23437,19 +23426,11 @@
23437
23426
  signaturePad: {
23438
23427
  current: null
23439
23428
  },
23440
- signatureData: null,
23441
- signatureDataUrl: null,
23442
- signatureVideoData: null,
23443
- signatureVideoUrl: null,
23444
23429
  outputCanvas: {
23445
23430
  current: null
23446
23431
  },
23447
- onAcceptClicked: function onAcceptClicked() {
23448
- return __awaiter(void 0, void 0, void 0, function () {
23449
- return __generator(this, function (_a) {
23450
- return [2 /*return*/];
23451
- });
23452
- });
23432
+ onSignatureVideoCaptured: function onSignatureVideoCaptured() {
23433
+ return null;
23453
23434
  }
23454
23435
  };
23455
23436
  var useVideoSignatureStore = create$1()(devtools(function (set, get) {
@@ -23459,25 +23440,22 @@
23459
23440
  if (captureAudio === void 0) {
23460
23441
  captureAudio = false;
23461
23442
  }
23443
+ // set our flag and clear whatever we have recorded so far.
23462
23444
  set({
23463
23445
  isRecording: true
23464
23446
  });
23465
- clearSignatureChunks();
23466
- useVideoRecorderStore.getState().clearRecordedData();
23467
- var _b = useVideoRecorderStore.getState(),
23468
- startRecordingVideo = _b.startRecordingVideo,
23469
- startRecordingAudio = _b.startRecordingAudio;
23470
- startRecordingVideo(camera, audioStream);
23471
- if (captureAudio) startRecordingAudio(audioStream);
23472
- var stream = get().outputCanvas.current.captureStream(24 /* fps */);
23473
- var tracks = [stream.getVideoTracks()[0]];
23447
+ signatureChunks = [];
23448
+ // start recording video and audio
23449
+ useVideoRecorderStore.getState().startRecordingVideo(camera, captureAudio ? audioStream : undefined);
23450
+ // start recording from the output canvas to capture the signature
23451
+ var videoStream = get().outputCanvas.current.captureStream(24); // fps
23452
+ var tracks = [videoStream.getVideoTracks()[0]];
23474
23453
  var audioTrack = (_a = audioStream === null || audioStream === void 0 ? void 0 : audioStream.getAudioTracks()) === null || _a === void 0 ? void 0 : _a[0];
23475
23454
  if (audioTrack) tracks.push(audioTrack);
23476
- var signatureRecorder = new MediaRecorder(new MediaStream(tracks), {
23455
+ signatureRecorder = new MediaRecorder(new MediaStream(tracks), {
23477
23456
  videoBitsPerSecond: 270000,
23478
23457
  audioBitsPerSecond: 32000
23479
23458
  });
23480
- setSignatureRecorder(signatureRecorder);
23481
23459
  signatureRecorder.ondataavailable = function (event) {
23482
23460
  signatureChunks.push(event.data);
23483
23461
  };
@@ -23490,43 +23468,41 @@
23490
23468
  if (!signatureRecorder) return;
23491
23469
  signatureRecorder.stop();
23492
23470
  signatureRecorder.onstop = function () {
23493
- log('VideoSignatureContext: onstop');
23494
23471
  var blob = new Blob(signatureChunks, {
23495
23472
  type: 'video/mp4'
23496
23473
  });
23497
- useVideoSignatureStore.setState({
23498
- signatureVideoData: blob,
23499
- signatureVideoUrl: URL.createObjectURL(blob)
23474
+ signatureChunks = [];
23475
+ signatureRecorder = null;
23476
+ var signaturePad = get().signaturePad.current;
23477
+ if (!signaturePad) throw new Error('Signature pad not found');
23478
+ var signatureData = buildSignatureData(signaturePad);
23479
+ exportSignatureImage(signaturePad).then(function (imageUrl) {
23480
+ if (imageUrl) signatureData.fileContent = dataUrlToBase64Sync(imageUrl);
23481
+ get().onSignatureVideoCaptured(blob, signatureData, imageUrl);
23500
23482
  });
23501
- clearSignatureChunks();
23502
- setSignatureRecorder(null);
23503
23483
  };
23504
23484
  useVideoRecorderStore.getState().stopRecording();
23505
23485
  },
23506
23486
  clearRecordedData: function clearRecordedData() {
23507
- var _a;
23508
- clearSignatureChunks();
23487
+ signatureChunks = [];
23509
23488
  useVideoRecorderStore.getState().stopRecordingVideo();
23510
23489
  useVideoRecorderStore.getState().clearRecordedData();
23511
- (_a = getSignatureRecorder()) === null || _a === void 0 ? void 0 : _a.stop();
23512
- setSignatureRecorder(null);
23490
+ signatureRecorder === null || signatureRecorder === void 0 ? void 0 : signatureRecorder.stop();
23491
+ signatureRecorder = null;
23513
23492
  set({
23514
- isRecording: false,
23515
- signatureVideoData: null,
23516
- signatureVideoUrl: null
23493
+ isRecording: false
23517
23494
  });
23518
23495
  }
23519
23496
  });
23520
23497
  }));
23521
23498
  function VideoSignatureContextProvider(_a) {
23499
+ var _this = this;
23522
23500
  var _b, _c;
23523
23501
  var children = _a.children,
23524
23502
  _d = _a.captureAudio,
23525
23503
  captureAudio = _d === void 0 ? false : _d;
23526
- var _e = useCameraStore(),
23527
- camera = _e.camera,
23528
- videoRef = _e.videoRef;
23529
- var isRecordingVideo = useVideoRecorder(captureAudio).isRecordingVideo;
23504
+ var videoRef = useCameraStore().videoRef;
23505
+ useVideoRecorder(captureAudio);
23530
23506
  var outputCanvas = React.useRef(null);
23531
23507
  React.useEffect(function () {
23532
23508
  return useVideoSignatureStore.setState({
@@ -23538,36 +23514,35 @@
23538
23514
  useVideoSignatureStore.getState().clearRecordedData();
23539
23515
  }, []);
23540
23516
  var isRecording = useVideoSignatureStore().isRecording;
23541
- var animationFrame = React.useRef(0);
23542
- React.useEffect(function () {
23543
- if (!videoRef.current || !outputCanvas.current || !camera || !isRecording || !isRecordingVideo) return;
23544
- var ctx = outputCanvas.current.getContext('2d');
23545
- if (!ctx) return;
23546
- var signaturePad = useVideoSignatureStore.getState().signaturePad;
23547
- animationFrame.current = requestAnimationFrame(function runFrame() {
23548
- if (!signaturePad.current || !videoRef.current || !outputCanvas.current) {
23549
- cancelAnimationFrame(animationFrame.current);
23550
- return;
23551
- }
23552
- var _a = [videoRef.current.videoWidth, videoRef.current.videoHeight],
23553
- w = _a[0],
23554
- h = _a[1];
23555
- var isPortrait = w < h;
23556
- outputCanvas.current.width = w;
23557
- outputCanvas.current.height = h;
23558
- var rect = [w * (isPortrait ? 0.02 : 0.15), h * (isPortrait ? 0.15 : 0.25), w * (isPortrait ? 0.96 : 0.7), h * (isPortrait ? 0.7 : 0.5)];
23559
- ctx.drawImage(videoRef.current, 0, 0, w, h);
23560
- ctx.beginPath();
23561
- ctx.fillStyle = 'rgba(255,255,255,0.5)';
23562
- ctx.roundRect.apply(ctx, __spreadArray(__spreadArray([], rect, false), [16], false));
23563
- ctx.fill();
23564
- ctx.drawImage.apply(ctx, __spreadArray([signaturePad.current.getCanvas()], rect, false));
23565
- animationFrame.current = requestAnimationFrame(runFrame);
23517
+ useFrameLoop(React.useCallback(function () {
23518
+ return __awaiter(_this, void 0, void 0, function () {
23519
+ var signaturePad, ctx, _a, w, h, isPortrait, rect;
23520
+ return __generator(this, function (_b) {
23521
+ signaturePad = useVideoSignatureStore.getState().signaturePad;
23522
+ if (!outputCanvas.current || !signaturePad.current || !videoRef.current) return [2 /*return*/];
23523
+ ctx = outputCanvas.current.getContext('2d');
23524
+ if (!ctx) return [2 /*return*/];
23525
+ _a = [videoRef.current.videoWidth, videoRef.current.videoHeight], w = _a[0], h = _a[1];
23526
+ isPortrait = w < h;
23527
+ outputCanvas.current.width = w;
23528
+ outputCanvas.current.height = h;
23529
+ rect = [w * (isPortrait ? 0.02 : 0.15), h * (isPortrait ? 0.15 : 0.25), w * (isPortrait ? 0.96 : 0.7), h * (isPortrait ? 0.7 : 0.5)];
23530
+ // draw the current video frame
23531
+ ctx.drawImage(videoRef.current, 0, 0, w, h);
23532
+ // draw a semi-transparent white rectangle over the video to simulate a signature pad
23533
+ ctx.beginPath();
23534
+ ctx.fillStyle = 'rgba(255,255,255,0.5)';
23535
+ ctx.roundRect.apply(ctx, __spreadArray(__spreadArray([], rect, false), [16], false));
23536
+ ctx.fill();
23537
+ // draw whatever the user has drawn on the signature pad
23538
+ ctx.drawImage.apply(ctx, __spreadArray([signaturePad.current.getCanvas()], rect, false));
23539
+ return [2 /*return*/];
23540
+ });
23566
23541
  });
23567
- return function () {
23568
- return cancelAnimationFrame(animationFrame.current);
23569
- };
23570
- }, [camera, isRecording, isRecordingVideo, videoRef]);
23542
+ }, [videoRef]), {
23543
+ autoStart: isRecording,
23544
+ throttleMs: 1000 / 24
23545
+ });
23571
23546
  return /*#__PURE__*/React.createElement(React.Fragment, null, children, /*#__PURE__*/React.createElement(InvisibleCanvas, {
23572
23547
  ref: outputCanvas,
23573
23548
  width: (_b = videoRef.current) === null || _b === void 0 ? void 0 : _b.videoWidth,
@@ -23576,7 +23551,6 @@
23576
23551
  }
23577
23552
 
23578
23553
  function VideoSignatureGuides(_a) {
23579
- var _this = this;
23580
23554
  var _b = _a.requestedAction,
23581
23555
  requestedAction = _b === void 0 ? 'VERIFY_LIVENESS' : _b,
23582
23556
  _c = _a.faceGuideStatus,
@@ -23632,32 +23606,7 @@
23632
23606
  if (signaturePadEmpty) setEmptyContentDismissed(false);
23633
23607
  }, [signaturePadEmpty]);
23634
23608
  var onAcceptClicked = React.useCallback(function () {
23635
- return __awaiter(_this, void 0, void 0, function () {
23636
- var signatureData, imageUrl;
23637
- return __generator(this, function (_a) {
23638
- switch (_a.label) {
23639
- case 0:
23640
- log('VideoSignatureContext: onAcceptClicked');
23641
- if (!signaturePad.current) return [2 /*return*/];
23642
- log('VideoSignatureContext: building signature data...');
23643
- signatureData = buildSignatureData(signaturePad.current);
23644
- log('VideoSignatureContext: exporting signature image...', signatureData);
23645
- return [4 /*yield*/, exportSignatureImage(signaturePad.current)];
23646
- case 1:
23647
- imageUrl = _a.sent();
23648
- if (imageUrl) signatureData.fileContent = dataUrlToBase64Sync(imageUrl);
23649
- log('VideoSignatureContext: setting signature data url...', imageUrl);
23650
- useVideoSignatureStore.setState({
23651
- signatureData: signatureData,
23652
- signatureDataUrl: imageUrl
23653
- });
23654
- log('VideoSignatureContext: stopping signature recorder...');
23655
- // getSignatureRecorder()?.stop()
23656
- useVideoSignatureStore.getState().stopRecording();
23657
- return [2 /*return*/];
23658
- }
23659
- });
23660
- });
23609
+ useVideoSignatureStore.getState().stopRecording();
23661
23610
  }, []);
23662
23611
  return /*#__PURE__*/React.createElement(Container$3, {
23663
23612
  className: classNames.container
@@ -23751,7 +23700,7 @@
23751
23700
  var DEFAULT_MIN_SIGNATURE_PAD_POINTS = 10;
23752
23701
  var DEFAULT_HEAD_TRACKING_BOUNDARY_PERCENTAGE = 0.01;
23753
23702
  var VideoSignatureCapture = function VideoSignatureCapture(_a) {
23754
- var onVideoCaptured = _a.onVideoCaptured,
23703
+ var onSignatureVideoCaptured = _a.onSignatureVideoCaptured,
23755
23704
  onFaceNotDetected = _a.onFaceNotDetected,
23756
23705
  onExit = _a.onExit,
23757
23706
  _b = _a.restartVideoOnSignaturePadCleared,
@@ -23784,17 +23733,19 @@
23784
23733
  videoWidth = _k.videoWidth,
23785
23734
  videoHeight = _k.videoHeight;
23786
23735
  var _l = useSelfieGuidanceModelsContext(),
23787
- onPredictionMade = _l.onPredictionMade,
23736
+ onHeadTrackingPredictionMade = _l.onPredictionMade,
23788
23737
  startHeadTracking = _l.start,
23789
23738
  stopHeadTracking = _l.stop;
23790
23739
  var _m = useVideoSignatureStore(),
23791
- signatureData = _m.signatureData,
23792
- signatureDataUrl = _m.signatureDataUrl,
23793
- signatureVideoData = _m.signatureVideoData,
23794
23740
  startRecording = _m.startRecording,
23795
23741
  stopRecording = _m.stopRecording,
23796
23742
  clearRecordedData = _m.clearRecordedData,
23797
23743
  isRecording = _m.isRecording;
23744
+ React.useEffect(function () {
23745
+ useVideoSignatureStore.setState({
23746
+ onSignatureVideoCaptured: onSignatureVideoCaptured
23747
+ });
23748
+ }, [onSignatureVideoCaptured]);
23798
23749
  React.useEffect(function () {
23799
23750
  if (!camera) return;
23800
23751
  startRecording(camera, audioStream, captureAudio);
@@ -23809,11 +23760,6 @@
23809
23760
  var verbiage = useTranslations(rawVerbiage, {
23810
23761
  guidanceMessageText: 'Please sign the box below'
23811
23762
  });
23812
- React.useEffect(function () {
23813
- if (signatureVideoData && signatureData && signatureDataUrl) {
23814
- onVideoCaptured === null || onVideoCaptured === void 0 ? void 0 : onVideoCaptured(signatureVideoData, signatureData, signatureDataUrl);
23815
- }
23816
- }, [onVideoCaptured, signatureData, signatureDataUrl, signatureVideoData]);
23817
23763
  var _o = React.useState(true),
23818
23764
  headTrackingSatisfied = _o[0],
23819
23765
  setHeadTrackingSatisfied = _o[1];
@@ -23823,7 +23769,7 @@
23823
23769
  var _q = React.useState(0),
23824
23770
  numFramesWithoutFaces = _q[0],
23825
23771
  setNumFramesWithoutFaces = _q[1];
23826
- onPredictionMade(f(React.useCallback(function (_a) {
23772
+ onHeadTrackingPredictionMade(f(React.useCallback(function (_a) {
23827
23773
  var face = _a.face;
23828
23774
  if (!camera) return;
23829
23775
  var nearBoundary = (face === null || face === void 0 ? void 0 : face.box.xMin) < videoWidth * headTrackingBoundaryPercentage || (face === null || face === void 0 ? void 0 : face.box.xMax) > videoWidth * (1 - headTrackingBoundaryPercentage) || (face === null || face === void 0 ? void 0 : face.box.yMin) < videoHeight * headTrackingBoundaryPercentage || (face === null || face === void 0 ? void 0 : face.box.yMax) > videoHeight * (1 - headTrackingBoundaryPercentage);
@@ -24045,6 +23991,7 @@
24045
23991
  var onSignatureCaptureFacesNotDetected = React.useCallback(function () {
24046
23992
  setShowLoadingOverlay(false);
24047
23993
  setCaptureState('CHECKING_LIVENESS');
23994
+ useVideoSignatureStore.getState().clearRecordedData();
24048
23995
  }, []);
24049
23996
  var _u = React.useState(0),
24050
23997
  attempt = _u[0],
@@ -24125,7 +24072,7 @@
24125
24072
  }));
24126
24073
  case 'CAPTURING_SIGNATURE':
24127
24074
  return /*#__PURE__*/React.createElement(VideoSignatureCapture, {
24128
- onVideoCaptured: onSignatureCaptureCompleted,
24075
+ onSignatureVideoCaptured: onSignatureCaptureCompleted,
24129
24076
  onFaceNotDetected: onSignatureCaptureFacesNotDetected,
24130
24077
  onExit: onExitSignatureCapture,
24131
24078
  minSignaturePadPoints: minSignaturePadPoints,