@smileid/web-components 10.0.3 → 10.0.5

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.
Files changed (44) hide show
  1. package/dist/esm/{DocumentCaptureScreens-CkWKSrqy.js → DocumentCaptureScreens-BIJUlWLB.js} +98 -56
  2. package/dist/esm/DocumentCaptureScreens-BIJUlWLB.js.map +1 -0
  3. package/dist/esm/{EndUserConsent-CMHp-34-.js → EndUserConsent-D4fd1ovG.js} +2 -2
  4. package/dist/esm/{EndUserConsent-CMHp-34-.js.map → EndUserConsent-D4fd1ovG.js.map} +1 -1
  5. package/dist/esm/{Navigation-juBE4qOw.js → Navigation-CTjK6tLU.js} +6 -6
  6. package/dist/esm/{Navigation-juBE4qOw.js.map → Navigation-CTjK6tLU.js.map} +1 -1
  7. package/dist/esm/SelfieCaptureScreens-CnMaKUmP.js +11361 -0
  8. package/dist/esm/SelfieCaptureScreens-CnMaKUmP.js.map +1 -0
  9. package/dist/esm/document.js +1 -1
  10. package/dist/esm/end-user-consent.js +1 -1
  11. package/dist/esm/main.js +4 -4
  12. package/dist/esm/navigation.js +1 -1
  13. package/dist/esm/{package-CmYr0HUS.js → package-PZvRbm5J.js} +2 -2
  14. package/dist/esm/{package-CmYr0HUS.js.map → package-PZvRbm5J.js.map} +1 -1
  15. package/dist/esm/selfie.js +1 -1
  16. package/dist/esm/smart-camera-web.js +12 -6
  17. package/dist/esm/smart-camera-web.js.map +1 -1
  18. package/dist/esm/{styles-D2i3GFLK.js → styles-BOEZtbuc.js} +19 -5
  19. package/dist/esm/{styles-D2i3GFLK.js.map → styles-BOEZtbuc.js.map} +1 -1
  20. package/dist/smart-camera-web.js +278 -290
  21. package/dist/smart-camera-web.js.map +1 -1
  22. package/lib/components/document/src/DocumentCaptureScreens.js +1 -1
  23. package/lib/components/document/src/document-capture/DocumentCapture.js +2 -1
  24. package/lib/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +54 -8
  25. package/lib/components/document/src/document-capture-review/DocumentCaptureReview.js +2 -3
  26. package/lib/components/navigation/src/Navigation.js +5 -5
  27. package/lib/components/selfie/src/SelfieCaptureScreens.js +116 -118
  28. package/lib/components/selfie/src/selfie-capture/SelfieCapture.js +54 -10
  29. package/lib/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +91 -58
  30. package/lib/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +23 -154
  31. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +13 -0
  32. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +66 -6
  33. package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +2 -0
  34. package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +165 -21
  35. package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +82 -23
  36. package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +2 -1
  37. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +18 -1
  38. package/lib/components/signature-pad/package.json +1 -1
  39. package/lib/components/smart-camera-web/src/SmartCameraWeb.js +7 -1
  40. package/lib/styles/src/styles.js +18 -4
  41. package/package.json +3 -1
  42. package/dist/esm/DocumentCaptureScreens-CkWKSrqy.js.map +0 -1
  43. package/dist/esm/SelfieCaptureScreens-BF1keQ0h.js +0 -7619
  44. package/dist/esm/SelfieCaptureScreens-BF1keQ0h.js.map +0 -1
@@ -260,6 +260,9 @@ function templateString() {
260
260
  }
261
261
 
262
262
  #selfie-capture-instruction-screen {
263
+ box-sizing: border-box;
264
+ height: 100%;
265
+ padding: 1rem;
263
266
  display: flex;
264
267
  flex-direction: column;
265
268
  max-block-size: 100%;
@@ -270,17 +273,20 @@ function templateString() {
270
273
  margin-block: 0 !important;
271
274
  }
272
275
 
276
+ header h1 {
277
+ font-size: 1.25rem;
278
+ }
279
+
273
280
  .instructions {
274
- margin-block-start: 1.5rem;
275
281
  display: flex;
276
282
  align-items: center;
277
283
  text-align: initial;
278
- gap: 1rem;
284
+ gap: 0.5rem;
279
285
  }
280
286
 
281
287
  .instructions svg {
282
288
  flex-shrink: 0;
283
- margin-inline-end: 1rem;
289
+ margin-inline-end: 0.25rem;
284
290
  }
285
291
 
286
292
  .instructions p {
@@ -290,6 +296,8 @@ function templateString() {
290
296
  h1 {
291
297
  color: ${this.themeColor};
292
298
  text-align: center;
299
+ margin-top: 0;
300
+ margin-bottom: 1rem;
293
301
 
294
302
  /* h1 */
295
303
  font-size: 1.5rem;
@@ -298,41 +306,73 @@ function templateString() {
298
306
  line-height: 36px; /* 150% */
299
307
  }
300
308
 
309
+ .controls {
310
+ width: 100%;
311
+ margin-top: 1rem;
312
+ }
313
+
314
+ .content-root {
315
+ height: 100%;
316
+ display: flex;
317
+ align-items: center;
318
+ flex-direction: column;
319
+ }
320
+
321
+ .content-header, .content-body, .content-footer {
322
+ width: 100%;
323
+ }
324
+
325
+ .content-body {
326
+ height: 100%;
327
+ display: flex;
328
+ flex-direction: column;
329
+ align-items: center;
330
+ justify-content: space-between;
331
+ }
332
+
301
333
  .tip-header {
302
334
  color: ${this.themeColor};
303
335
  }
336
+
337
+ .tip-body {
338
+ text-align: justify;
339
+ }
304
340
  </style>
305
341
  ${styles(this.themeColor)}
306
- <div id="selfie-capture-instruction-screen" class="flow center">
307
- <smileid-navigation theme-color=${this.themeColor} ${this.hideBack ? 'hide-back' : ''} ${this.showNavigation ? '' : 'hidden'}></smileid-navigation>
308
- <header>
309
- <svg xmlns="http://www.w3.org/2000/svg" width="65" height="91" viewBox="0 0 65 91" fill="none">
310
- <g clip-path="url(#clip0_604_692)">
311
- <path d="M36.6833 60.4888C26.9272 54.8682 13.1977 54.3026 5.53473 59.2162C-2.12824 64.1298 -0.851078 72.9318 8.05358 78.9413L17.8806 85.1274L51.5126 69.6797L36.7188 60.4534H36.6478L36.6833 60.4888Z" fill="#3B3837"/>
312
- <path d="M27.5624 90.5007L17.9127 85.0923C17.9127 85.0923 17.9127 74.6288 18.1256 70.4929C18.232 68.2305 23.2342 37.441 44.1655 34.6484C48.1389 34.1182 56.8662 40.5871 56.8662 40.5871" fill="#91190F"/>
313
- <path d="M27.5624 90.5007L17.9127 85.0923C17.9127 85.0923 17.9127 74.6288 18.1256 70.4929C18.232 68.2305 23.2342 37.441 44.1655 34.6484C48.1389 34.1182 56.8662 40.5871 56.8662 40.5871" fill="#3B3837"/>
314
- <path d="M64.0705 51.9698C63.8931 41.0114 56.2301 36.5927 46.7224 42.0366C37.0727 47.5511 29.055 60.9486 28.3454 72.2958L27.5649 90.4655L63.7512 69.5739L64.1769 51.8991H64.106L64.0705 51.9698Z" fill="#7ECAF0"/>
315
- <path d="M44.2729 28.3906L30.0112 36.521L30.4015 19.73L44.6631 11.5643L44.2729 28.3906Z" fill="#F8CEEB"/>
316
- <path d="M53.959 33.8711L39.6974 42.0368L40.0876 25.2104L54.3493 17.0447L53.959 33.8711Z" fill="#7ECAF0"/>
317
- <path d="M44.6631 11.5643L54.3483 17.0434L40.0866 25.2092L39.6964 42.0356L30.0112 36.521L30.4015 19.73L44.6631 11.5643Z" fill="#3B3837"/>
318
- <path d="M53.0767 51.0497L59.9591 46.8785L59.9237 36.9099L64.4647 34.3294L64.5002 49.4236L53.0767 56.2461V51.0497Z" fill="#FF5805"/>
319
- <path d="M54.0676 54.5139L63.5044 48.8933L63.469 36.026L60.9146 37.4754V47.4439L54.0676 51.5798V54.5139Z" fill="#FF5805"/>
320
- <path d="M30.4053 52.2515L34.9463 49.6356V60.8414L44.0638 55.1855V60.4172L30.4407 68.7244L30.4053 52.2515Z" fill="#FF5805"/>
321
- <path d="M31.4317 66.9921L43.0681 59.8869V56.9529L33.9506 62.6088V51.3323L31.3962 52.817L31.4317 66.9921Z" fill="#FF5805"/>
322
- <path d="M30.4053 19.7312L42.5383 13.0148V18.1759L34.9463 22.3471V32.4924L30.4407 35.073L30.4053 19.7312Z" fill="#FF5805"/>
323
- <path d="M31.3962 33.377L33.9506 31.9276V21.7823L41.5426 17.6111V14.6771L31.3962 20.2976V28.7815V33.377Z" fill="#FF5805"/>
324
- <path d="M59.9223 8.27746L53.5365 11.9538V6.79277L64.4279 0.500549L64.4633 16.5846L59.9578 19.1651L59.9223 8.27746Z" fill="#FF5805"/>
325
- <path d="M60.9142 17.4682L63.504 16.0189L63.4685 2.19722L54.4929 7.35826L54.5284 10.2569L60.9142 6.58057V17.4682Z" fill="#FF5805"/>
326
- </g>
327
- <defs>
328
- <clipPath id="clip0_604_692">
329
- <rect width="64" height="90" fill="white" transform="translate(0.5 0.5)"/>
330
- </clipPath>
331
- </defs>
332
- </svg>
333
- <h1 class='text-2xl title-color font-bold'>Next, we'll take a quick selfie</h1>
334
- </header>
335
- <div class="flow instructions-wrapper">
342
+ <div id="selfie-capture-instruction-screen" class="center">
343
+ <div class="content-root">
344
+ <div class="content-header">
345
+ <smileid-navigation theme-color=${this.themeColor} ${this.hideBack ? 'hide-back' : ''} ${this.showNavigation ? '' : 'hidden'}></smileid-navigation>
346
+ </div>
347
+ <div class="content-body">
348
+ <header>
349
+ <svg xmlns="http://www.w3.org/2000/svg" width="65" height="91" viewBox="0 0 65 91" fill="none">
350
+ <g clip-path="url(#clip0_604_692)">
351
+ <path d="M36.6833 60.4888C26.9272 54.8682 13.1977 54.3026 5.53473 59.2162C-2.12824 64.1298 -0.851078 72.9318 8.05358 78.9413L17.8806 85.1274L51.5126 69.6797L36.7188 60.4534H36.6478L36.6833 60.4888Z" fill="#3B3837"/>
352
+ <path d="M27.5624 90.5007L17.9127 85.0923C17.9127 85.0923 17.9127 74.6288 18.1256 70.4929C18.232 68.2305 23.2342 37.441 44.1655 34.6484C48.1389 34.1182 56.8662 40.5871 56.8662 40.5871" fill="#91190F"/>
353
+ <path d="M27.5624 90.5007L17.9127 85.0923C17.9127 85.0923 17.9127 74.6288 18.1256 70.4929C18.232 68.2305 23.2342 37.441 44.1655 34.6484C48.1389 34.1182 56.8662 40.5871 56.8662 40.5871" fill="#3B3837"/>
354
+ <path d="M64.0705 51.9698C63.8931 41.0114 56.2301 36.5927 46.7224 42.0366C37.0727 47.5511 29.055 60.9486 28.3454 72.2958L27.5649 90.4655L63.7512 69.5739L64.1769 51.8991H64.106L64.0705 51.9698Z" fill="#7ECAF0"/>
355
+ <path d="M44.2729 28.3906L30.0112 36.521L30.4015 19.73L44.6631 11.5643L44.2729 28.3906Z" fill="#F8CEEB"/>
356
+ <path d="M53.959 33.8711L39.6974 42.0368L40.0876 25.2104L54.3493 17.0447L53.959 33.8711Z" fill="#7ECAF0"/>
357
+ <path d="M44.6631 11.5643L54.3483 17.0434L40.0866 25.2092L39.6964 42.0356L30.0112 36.521L30.4015 19.73L44.6631 11.5643Z" fill="#3B3837"/>
358
+ <path d="M53.0767 51.0497L59.9591 46.8785L59.9237 36.9099L64.4647 34.3294L64.5002 49.4236L53.0767 56.2461V51.0497Z" fill="#FF5805"/>
359
+ <path d="M54.0676 54.5139L63.5044 48.8933L63.469 36.026L60.9146 37.4754V47.4439L54.0676 51.5798V54.5139Z" fill="#FF5805"/>
360
+ <path d="M30.4053 52.2515L34.9463 49.6356V60.8414L44.0638 55.1855V60.4172L30.4407 68.7244L30.4053 52.2515Z" fill="#FF5805"/>
361
+ <path d="M31.4317 66.9921L43.0681 59.8869V56.9529L33.9506 62.6088V51.3323L31.3962 52.817L31.4317 66.9921Z" fill="#FF5805"/>
362
+ <path d="M30.4053 19.7312L42.5383 13.0148V18.1759L34.9463 22.3471V32.4924L30.4407 35.073L30.4053 19.7312Z" fill="#FF5805"/>
363
+ <path d="M31.3962 33.377L33.9506 31.9276V21.7823L41.5426 17.6111V14.6771L31.3962 20.2976V28.7815V33.377Z" fill="#FF5805"/>
364
+ <path d="M59.9223 8.27746L53.5365 11.9538V6.79277L64.4279 0.500549L64.4633 16.5846L59.9578 19.1651L59.9223 8.27746Z" fill="#FF5805"/>
365
+ <path d="M60.9142 17.4682L63.504 16.0189L63.4685 2.19722L54.4929 7.35826L54.5284 10.2569L60.9142 6.58057V17.4682Z" fill="#FF5805"/>
366
+ </g>
367
+ <defs>
368
+ <clipPath id="clip0_604_692">
369
+ <rect width="64" height="90" fill="white" transform="translate(0.5 0.5)"/>
370
+ </clipPath>
371
+ </defs>
372
+ </svg>
373
+ <h1 class='title-color font-bold'>Next, we'll take a quick selfie</h1>
374
+ </header>
375
+ <div class="instructions-wrapper">
336
376
  <div class="instructions">
337
377
  <svg
338
378
  xmlns="http://www.w3.org/2000/svg"
@@ -411,8 +451,7 @@ function templateString() {
411
451
  <div class="instruction">
412
452
  <p class="text-base title-color font-bold tip-header">Good Light</p>
413
453
  <p class="tip-body">
414
- Make sure you are in a well-lit environment where your face is
415
- clear and visible.
454
+ Make sure you are in a well-lit environment.
416
455
  </p>
417
456
  </div>
418
457
  </div>
@@ -499,9 +538,8 @@ function templateString() {
499
538
  </svg>
500
539
  <div class="instruction">
501
540
  <p class="text-base title-color font-bold tip-header">Clear Image</p>
502
- <p>
503
- Hold your phone steady so the selfie is clear and sharp. Don't
504
- take blurry images.
541
+ <p class="tip-body">
542
+ Hold your phone steady so the selfie is clear and sharp.
505
543
  </p>
506
544
  </div>
507
545
  </div>
@@ -532,38 +570,38 @@ function templateString() {
532
570
  </svg>
533
571
  <div class="instruction">
534
572
  <p class="text-base title-color font-bold tip-header">Remove Obstructions</p>
535
- <p>
536
- Remove anything that covers your face, such glasses, masks, hats
537
- and scarves.
573
+ <p class="tip-body">
574
+ Remove anything that covers your face, such as glasses, masks, and hats.
538
575
  </p>
539
576
  </div>
540
577
  </div>
541
578
  <div class="instructions">
542
579
  <svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 24 24" fill="none" stroke="${this.themeColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-mood-happy"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M9 9l.01 0" /><path d="M15 9l.01 0" /><path d="M8 13a4 4 0 1 0 8 0h-8" /></svg>
543
580
  <div class="instruction">
544
- <p class="text-base title-color font-bold tip-header">Big Smile</p>
545
- <p>
546
- When asked to smile, give a big smile, showing your teeth and keep your eyes open.
581
+ <p class="text-base title-color font-bold tip-header">Wide Smile</p>
582
+ <p class="tip-body">
583
+ When asked to smile, give a wide smile, showing your teeth.
547
584
  </p>
548
585
  </div>
549
586
  </div>
550
- <section class='flow' style='--flow-space: 2.5rem'>
551
- <button id='allow' data-variant='solid full-width' class='button theme-background'>
552
- Allow
553
- </button>
554
- <button id='cancel' data-variant='outline full-width' class="button" style='--flow-space: 1.5rem' ${this.hideBack || !this.showNavigation ? 'hidden' : ''}>
555
- Cancel
556
- </button>
557
- </section>
558
587
  </div>
588
+ <section class="controls">
589
+ <button id='allow' data-variant='solid full-width' class='button theme-background'>
590
+ Allow
591
+ </button>
592
+ </section>
559
593
  ${
560
594
  this.hideAttribution
561
595
  ? ''
562
596
  : `
563
- <powered-by-smile-id></powered-by-smile-id>
597
+ <div class="content-footer">
598
+ <powered-by-smile-id></powered-by-smile-id>
599
+ </div>
564
600
  `
565
601
  }
566
602
  </div>
603
+ </div>
604
+ </div>
567
605
  `;
568
606
  }
569
607
 
@@ -585,7 +623,6 @@ class SelfieCaptureInstructions extends HTMLElement {
585
623
 
586
624
  this.allowButton = this.shadowRoot.querySelector('#allow');
587
625
  this.navigation = this.shadowRoot.querySelector('smileid-navigation');
588
- this.cancelButton = this.shadowRoot.querySelector('#cancel');
589
626
 
590
627
  this.navigation.addEventListener('navigation.back', () => {
591
628
  this.handleBackEvents();
@@ -606,10 +643,6 @@ class SelfieCaptureInstructions extends HTMLElement {
606
643
  },
607
644
  false,
608
645
  );
609
-
610
- this.cancelButton.addEventListener('click', () => {
611
- this.handleBackEvents();
612
- });
613
646
  }
614
647
 
615
648
  get hideBack() {
@@ -7,110 +7,27 @@ function templateString() {
7
7
  .retake-photo.button[data-variant~="ghost"] {
8
8
  color: #FF5805;
9
9
  }
10
- .icon-btn {
11
- appearance: none;
12
- background: none;
13
- border: none;
14
- color: hsl(0deg 0% 94%);
15
- cursor: pointer;
16
- display: flex;
17
- align-items: center;
18
- justify-content: center;
19
- padding: 4px 8px;
20
- }
21
- .justify-right {
22
- justify-content: end !important;
23
- }
24
- .nav {
25
- display: flex;
26
- justify-content: space-between;
27
- }
28
- .back-wrapper {
29
- display: flex;
30
- align-items: center;
31
- }
32
- .back-button-text {
33
- font-size: 11px;
34
- line-height: 11px;
35
- color: rgb(21, 31, 114);
36
- }
37
- .section {
38
- border-radius: .5rem;
39
- margin-left: auto;
40
- margin-right: auto;
41
- max-width: 35ch;
42
- padding: 1rem;
43
- }
44
- .selfie-capture-review-image {
45
- overflow: hidden;
46
- aspect-ratio: 1/1;
47
- }
48
- #review-image {
49
- scale: 1.75;
50
- }
51
- @media (max-aspect-ratio: 1/1) {
52
- #review-image {
53
- transform: scaleX(-1) translateY(-10%);
54
- }
55
- }
56
- .tips,
57
- .powered-by {
58
- align-items: center;
59
- border-radius: 0.25rem;
60
- color: #4e6577;
61
- display: flex;
62
- justify-content: center;
63
- letter-spacing: 0.075em;
64
- }
65
- .powered-by {
66
- box-shadow: 0px 2.57415px 2.57415px rgba(0, 0, 0, 0.06);
67
- display: inline-flex;
68
- font-size: 0.5rem;
69
- }
70
- .tips {
71
- margin-left: auto;
72
- margin-right: auto;
73
- max-width: 17rem;
74
- }
75
- .tips > * + *,
76
- .powered-by > * + * {
77
- display: inline-block;
78
- margin-left: 0.5em;
79
- }
80
- .powered-by .company {
81
- color: #18406d;
82
- font-weight: 700;
83
- letter-spacing: 0.15rem;
84
- }
85
- .logo-mark {
86
- background-color: #004071;
87
- display: inline-block;
88
- padding: 0.25em 0.5em;
89
- }
90
- .logo-mark svg {
91
- height: auto;
92
- justify-self: center;
93
- width: 0.75em;
94
- }
10
+
95
11
  #selfie-capture-review-screen {
96
- block-size: 45rem;
97
12
  display: flex;
98
13
  flex-direction: column;
99
- max-block-size: 100%;
100
- max-inline-size: 40ch;
14
+ padding: 1rem;
101
15
  }
16
+
102
17
  #selfie-capture-review-screen .selfie-review-container.landscape {
103
18
  height: auto;
104
19
  }
20
+
105
21
  #selfie-capture-review-screen header p {
106
22
  margin-block: 0 !important;
107
23
  }
24
+
108
25
  .selfie-review-container.portrait {
109
26
  width: 100%;
110
27
  position: relative;
111
28
  height: calc(200px * 1.4);
112
29
  }
113
-
30
+
114
31
  .selfie-review-container.portrait img {
115
32
  width: calc(213px + 0.9rem);
116
33
  height: 100%;
@@ -126,80 +43,22 @@ function templateString() {
126
43
  block-size: 100%;
127
44
  }
128
45
 
129
- .selfie-container img {
130
- background-color: black;
131
- position: absolute;
132
- left: 50%;
133
- height: calc(100% - 6px);
134
- clip-path: ellipse(101px 118px);
135
- }
136
-
137
- .description {
138
- color: var(--neutral-off-black, #2D2B2A);
139
- text-align: center;
140
- /* p */
141
- font-family: DM Sans;
142
- font-size: 0.875rem;
143
- font-style: normal;
144
- font-weight: 400;
145
- line-height: 18px;
146
- }
147
- .padding-bottom-2 {
148
- padding-bottom: 2rem;
149
- }
150
- .instructions-wrapper {
151
- display: inline-flex;
152
- flex-direction: column;
153
- align-items: flex-start;
154
- gap: 2rem;
155
- margin-block-start: 2rem;
156
- margin-block-end: 4rem;
157
- }
158
- .instructions {
159
- display: flex;
160
- align-items: center;
161
- text-align: initial;
162
- }
163
- .instructions svg {
164
- flex-shrink: 0;
165
- margin-inline-end: 2rem;
166
- }
167
- .instructions p {
168
- margin-block: 0;
169
- }
170
- .instruction-body {
171
- font-size: 0.75rem;
172
- }
173
46
  h1 {
174
47
  color: var(--web-digital-blue, #001096);
175
48
  text-align: center;
176
49
  /* h1 */
177
- font-size: 1.5rem;
50
+ font-size: 1.25rem;
178
51
  font-style: normal;
179
52
  font-weight: 700;
180
53
  line-height: 36px; /* 150% */
181
- }
182
- .p2 {
183
- font-size: 1rem;
184
- font-style: normal;
185
- font-weight: 500;
186
- line-height: 1rem;
187
- }
188
- .instruction-header {
189
- color: var(--web-digital-blue, #001096);
190
- }
191
- .h2 {
192
- font-size: 1rem;
193
- font-style: normal;
194
- font-weight: 700;
195
- line-height: 1.5rem;
54
+ margin-top: 0;
196
55
  }
197
56
  </style>
198
57
  ${styles(this.themeColor)}
199
- <div id='selfie-capture-review-screen' class='flow center'>
58
+ <div id='selfie-capture-review-screen' class='center'>
200
59
  <smileid-navigation ${this.showNavigation ? 'show-navigation' : ''} hide-back></smileid-navigation>
201
- <h1 class="header-title text-2xl title-color font-bold">
202
- Is your whole face visible and clear in this photo?
60
+ <h1 class="header-title title-color font-bold">
61
+ Is your whole face clear?
203
62
  </h1>
204
63
  <div class='section | flow'>
205
64
  <div class='selfie-review-container ${this.isPortraitCaptureView ? 'portrait' : 'landscape'}'>
@@ -210,7 +69,7 @@ function templateString() {
210
69
  id='document-capture-review-image'
211
70
  src='${this.imageSrc}'
212
71
  width='396'
213
- style='transform: scaleX(-1);'
72
+ style='max-width: 90%;${this.shouldMirror ? ' transform: scaleX(-1);' : ''}'
214
73
  />`
215
74
  : ''
216
75
  }
@@ -253,7 +112,12 @@ class SelfieCaptureReview extends HTMLElement {
253
112
  }
254
113
 
255
114
  static get observedAttributes() {
256
- return ['hide-back-to-host', 'show-navigation', 'data-image'];
115
+ return [
116
+ 'hide-back-to-host',
117
+ 'show-navigation',
118
+ 'data-image',
119
+ 'mirror-image',
120
+ ];
257
121
  }
258
122
 
259
123
  get hideBack() {
@@ -276,6 +140,10 @@ class SelfieCaptureReview extends HTMLElement {
276
140
  return this.getAttribute('data-image');
277
141
  }
278
142
 
143
+ get shouldMirror() {
144
+ return this.getAttribute('mirror-image') !== 'false';
145
+ }
146
+
279
147
  get title() {
280
148
  return this.getAttribute('title') || 'Submit Front of ID';
281
149
  }
@@ -293,6 +161,7 @@ class SelfieCaptureReview extends HTMLElement {
293
161
  case 'data-image':
294
162
  case 'hide-back-to-host':
295
163
  case 'show-navigation':
164
+ case 'mirror-image':
296
165
  this.shadowRoot.innerHTML = this.render();
297
166
  this.setUpEventListeners();
298
167
  break;
@@ -118,6 +118,19 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
118
118
  };
119
119
  }, [hidden, mediapipeReady, loadingProgress]);
120
120
 
121
+ useEffect(() => {
122
+ if (hidden || mediapipeLoading) return;
123
+
124
+ const smartCameraWeb = document.querySelector('smart-camera-web');
125
+ smartCameraWeb?.dispatchEvent(
126
+ new CustomEvent('metadata.active-liveness-version', {
127
+ detail: {
128
+ version: usingSelfieCapture ? '0.0.1' : '1.0.0',
129
+ },
130
+ }),
131
+ );
132
+ }, [usingSelfieCapture, hidden, mediapipeLoading]);
133
+
121
134
  if (hidden) {
122
135
  return null;
123
136
  }
@@ -1,6 +1,8 @@
1
1
  import { useRef, useEffect } from 'preact/hooks';
2
+ import { useSignal } from '@preact/signals';
2
3
  import register from 'preact-custom-element';
3
4
  import type { FunctionComponent } from 'preact';
5
+ import { throttle } from 'lodash';
4
6
 
5
7
  import { getBoolProp } from '../../../../utils/props';
6
8
  import { useFaceCapture, useCamera } from './hooks';
@@ -45,7 +47,15 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
45
47
  const minFaceSize = 0.35;
46
48
  const maxFaceSize = 0.5;
47
49
 
48
- const camera = useCamera();
50
+ const initialFacingMode = allowAgentMode ? 'environment' : 'user';
51
+ const camera = useCamera(initialFacingMode);
52
+
53
+ const throttledMultipleFaces = useSignal(false);
54
+ const updateMultipleFacesUI = useRef(
55
+ throttle((value: boolean) => {
56
+ throttledMultipleFaces.value = value;
57
+ }, 100),
58
+ ).current;
49
59
 
50
60
  const faceCapture = useFaceCapture({
51
61
  videoRef: camera.videoRef,
@@ -57,11 +67,19 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
57
67
  minFaceSize,
58
68
  maxFaceSize,
59
69
  smileCooldown,
70
+ getFacingMode: () => camera.facingMode,
60
71
  });
61
72
 
62
73
  useEffect(() => {
63
74
  const initializeCamera = async () => {
64
- await camera.startCamera();
75
+ await camera.startCamera(initialFacingMode, (cameraName) => {
76
+ const smartCameraWeb = document.querySelector('smart-camera-web');
77
+ smartCameraWeb?.dispatchEvent(
78
+ new CustomEvent('metadata.camera-name', {
79
+ detail: { cameraName },
80
+ }),
81
+ );
82
+ });
65
83
  await camera.checkAgentSupport();
66
84
  await faceCapture.initializeFaceLandmarker();
67
85
 
@@ -71,15 +89,31 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
71
89
  }, 500);
72
90
  };
73
91
 
92
+ camera.registerCameraSwitchCallback(() => {
93
+ try {
94
+ faceCapture.resetFaceDetectionState();
95
+ faceCapture.setupCanvas();
96
+ faceCapture.stopDetectionLoop();
97
+ faceCapture.startDetectionLoop();
98
+ } catch (error) {
99
+ console.error('Error during camera switch callback:', error);
100
+ }
101
+ });
102
+
74
103
  initializeCamera();
75
104
 
76
105
  return () => {
77
106
  faceCapture.stopDetectionLoop();
78
107
  camera.stopCamera();
79
108
  faceCapture.cleanup();
109
+ updateMultipleFacesUI.cancel();
80
110
  };
81
111
  }, []);
82
112
 
113
+ useEffect(() => {
114
+ updateMultipleFacesUI(faceCapture.multipleFaces.value);
115
+ }, [faceCapture.multipleFaces.value]);
116
+
83
117
  useEffect(() => {
84
118
  const navigation = navigationRef.current;
85
119
 
@@ -106,6 +140,33 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
106
140
  return undefined;
107
141
  }, [showNavigation]);
108
142
 
143
+ useEffect(() => {
144
+ if (faceCapture.hasFinishedCapture.value) {
145
+ const smartCameraWeb = document.querySelector('smart-camera-web');
146
+ smartCameraWeb?.dispatchEvent(
147
+ new CustomEvent('metadata.selfie-capture-end'),
148
+ );
149
+ }
150
+ }, [faceCapture.hasFinishedCapture.value]);
151
+
152
+ const handleStartCapture = () => {
153
+ faceCapture.startCapture();
154
+ const smartCameraWeb = document.querySelector('smart-camera-web');
155
+ smartCameraWeb?.dispatchEvent(
156
+ new CustomEvent('metadata.selfie-capture-start'),
157
+ );
158
+ smartCameraWeb?.dispatchEvent(
159
+ new CustomEvent('metadata.selfie-origin', {
160
+ detail: {
161
+ imageOrigin: {
162
+ environment: 'back_camera',
163
+ user: 'front_camera',
164
+ }[camera.facingMode],
165
+ },
166
+ }),
167
+ );
168
+ };
169
+
109
170
  return (
110
171
  <div className="smartselfie-capture">
111
172
  {showNavigation && (
@@ -117,7 +178,7 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
117
178
  videoRef={camera.videoRef}
118
179
  canvasRef={canvasRef}
119
180
  facingMode={camera.facingMode}
120
- multipleFaces={faceCapture.multipleFaces.value}
181
+ multipleFaces={throttledMultipleFaces.value}
121
182
  progress={
122
183
  faceCapture.capturesTaken.value > 0
123
184
  ? faceCapture.capturesTaken.value / faceCapture.totalCaptures.value
@@ -140,7 +201,7 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
140
201
  showAgentModeForTests={showAgentModeForTests}
141
202
  facingMode={camera.facingMode}
142
203
  themeColor={themeColor}
143
- onStartCapture={faceCapture.startCapture}
204
+ onStartCapture={handleStartCapture}
144
205
  onSwitchCamera={camera.switchCamera}
145
206
  />
146
207
  )}
@@ -193,9 +254,8 @@ const SmartSelfieCapture: FunctionComponent<Props> = ({
193
254
  }
194
255
 
195
256
  .smartselfie-capture {
257
+ padding: 1rem;
196
258
  font-family: sans-serif;
197
- max-width: 356px;
198
- margin: 0 auto;
199
259
  }
200
260
  `}</style>
201
261
  </div>
@@ -53,6 +53,8 @@ export const CaptureControls: FunctionComponent<CaptureControlsProps> = ({
53
53
  flex-direction: column;
54
54
  gap: 1rem;
55
55
  justify-content: center;
56
+ max-width: 356px;
57
+ margin: 0 auto;
56
58
  }
57
59
 
58
60
  .agent-mode-btn {