@smileid/web-components 11.0.0 → 11.0.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.
Files changed (141) hide show
  1. package/README.md +15 -15
  2. package/dist/README.md +15 -0
  3. package/dist/components/README.md +14 -0
  4. package/dist/components/document/src/README.md +111 -0
  5. package/dist/components/document/src/document-capture/README.md +90 -0
  6. package/dist/components/document/src/document-capture-instructions/README.md +56 -0
  7. package/dist/components/document/src/document-capture-review/README.md +79 -0
  8. package/dist/components/selfie/README.md +225 -0
  9. package/dist/components/smart-camera-web/src/README.md +207 -0
  10. package/dist/domain/camera/src/README.md +38 -0
  11. package/dist/domain/file-upload/README.md +35 -0
  12. package/dist/esm/{DocumentCaptureScreens-RECPb0wH.js → DocumentCaptureScreens-CRx5ymqY.js} +2 -2
  13. package/dist/esm/DocumentCaptureScreens-CRx5ymqY.js.map +1 -0
  14. package/dist/esm/EndUserConsent-D4fd1ovG.js.map +1 -1
  15. package/dist/esm/Navigation-CTjK6tLU.js.map +1 -1
  16. package/dist/esm/PoweredBySmileId-CxbaihMu.js.map +1 -1
  17. package/dist/esm/{SelfieCaptureScreens-CqBVGEJk.js → SelfieCaptureScreens-DuQjKt_K.js} +274 -257
  18. package/dist/esm/SelfieCaptureScreens-DuQjKt_K.js.map +1 -0
  19. package/dist/esm/SignaturePad-C7MtmT8m.js.map +1 -1
  20. package/dist/esm/TotpConsent-CQU5jQi4.js.map +1 -1
  21. package/dist/esm/combobox.js.map +1 -1
  22. package/dist/esm/document.js +1 -1
  23. package/dist/esm/main.js +2 -2
  24. package/dist/esm/{package-BDJnoIAU.js → package-C_cKNrUu.js} +2 -2
  25. package/dist/esm/package-C_cKNrUu.js.map +1 -0
  26. package/dist/esm/selfie.js +1 -1
  27. package/dist/esm/smart-camera-web.js +3 -3
  28. package/dist/esm/smart-camera-web.js.map +1 -1
  29. package/dist/esm/styles-BOEZtbuc.js.map +1 -1
  30. package/dist/package-lock.json +4948 -0
  31. package/dist/package.json +59 -0
  32. package/dist/smart-camera-web.js +23 -23
  33. package/dist/smart-camera-web.js.gz +0 -0
  34. package/dist/smart-camera-web.js.map +1 -1
  35. package/dist/src/components/combobox/src/index.js +2 -0
  36. package/dist/src/components/combobox/src/index.js.map +7 -0
  37. package/dist/src/components/document/src/index.js +2 -0
  38. package/dist/src/components/document/src/index.js.map +7 -0
  39. package/dist/src/components/end-user-consent/src/index.js +14 -0
  40. package/dist/src/components/end-user-consent/src/index.js.map +7 -0
  41. package/dist/src/components/selfie/src/index.js +2 -0
  42. package/dist/src/components/selfie/src/index.js.map +7 -0
  43. package/dist/src/components/signature-pad/src/index.js +10 -0
  44. package/dist/src/components/signature-pad/src/index.js.map +7 -0
  45. package/dist/src/components/smart-camera-web/src/SmartCameraWeb.js +2 -0
  46. package/dist/src/components/smart-camera-web/src/SmartCameraWeb.js.map +7 -0
  47. package/dist/src/components/totp-consent/src/index.js +14 -0
  48. package/dist/src/components/totp-consent/src/index.js.map +7 -0
  49. package/dist/src/index.js.map +7 -0
  50. package/dist/styles/README.md +3 -0
  51. package/dist/types/combobox.d.ts +19 -19
  52. package/dist/types/document.d.ts +19 -19
  53. package/dist/types/end-user-consent.d.ts +19 -19
  54. package/dist/types/main.d.ts +24 -20
  55. package/dist/types/navigation.d.ts +19 -19
  56. package/dist/types/selfie.d.ts +19 -19
  57. package/dist/types/signature-pad.d.ts +19 -19
  58. package/dist/types/smart-camera-web.d.ts +19 -19
  59. package/dist/types/totp-consent.d.ts +19 -19
  60. package/lib/components/README.md +14 -14
  61. package/lib/components/attribution/PoweredBySmileId.js +42 -42
  62. package/lib/components/camera-permission/CameraPermission.js +139 -139
  63. package/lib/components/camera-permission/CameraPermission.stories.js +27 -27
  64. package/lib/components/combobox/src/Combobox.js +589 -589
  65. package/lib/components/combobox/src/index.js +1 -1
  66. package/lib/components/document/src/DocumentCaptureScreens.js +410 -410
  67. package/lib/components/document/src/DocumentCaptureScreens.stories.js +57 -57
  68. package/lib/components/document/src/README.md +111 -111
  69. package/lib/components/document/src/document-capture/DocumentCapture.js +760 -760
  70. package/lib/components/document/src/document-capture/DocumentCapture.stories.js +78 -78
  71. package/lib/components/document/src/document-capture/README.md +90 -90
  72. package/lib/components/document/src/document-capture/index.js +3 -3
  73. package/lib/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +545 -545
  74. package/lib/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +24 -24
  75. package/lib/components/document/src/document-capture-instructions/README.md +56 -56
  76. package/lib/components/document/src/document-capture-instructions/index.js +3 -3
  77. package/lib/components/document/src/document-capture-review/DocumentCaptureReview.js +360 -360
  78. package/lib/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +24 -24
  79. package/lib/components/document/src/document-capture-review/README.md +79 -79
  80. package/lib/components/document/src/document-capture-review/index.js +3 -3
  81. package/lib/components/document/src/index.js +3 -3
  82. package/lib/components/end-user-consent/src/EndUserConsent.js +795 -795
  83. package/lib/components/end-user-consent/src/EndUserConsent.stories.js +29 -29
  84. package/lib/components/end-user-consent/src/index.js +4 -4
  85. package/lib/components/navigation/src/Navigation.js +171 -171
  86. package/lib/components/navigation/src/Navigation.stories.js +24 -24
  87. package/lib/components/navigation/src/index.js +3 -3
  88. package/lib/components/selfie/README.md +225 -225
  89. package/lib/components/selfie/src/SelfieCaptureScreens.js +420 -420
  90. package/lib/components/selfie/src/SelfieCaptureScreens.stories.js +29 -29
  91. package/lib/components/selfie/src/index.js +3 -3
  92. package/lib/components/selfie/src/selfie-capture/SelfieCapture.js +1099 -1099
  93. package/lib/components/selfie/src/selfie-capture/SelfieCapture.stories.js +36 -36
  94. package/lib/components/selfie/src/selfie-capture/index.js +3 -3
  95. package/lib/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +689 -689
  96. package/lib/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +23 -23
  97. package/lib/components/selfie/src/selfie-capture-instructions/index.js +3 -3
  98. package/lib/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +209 -209
  99. package/lib/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +24 -24
  100. package/lib/components/selfie/src/selfie-capture-review/index.js +3 -3
  101. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +281 -256
  102. package/lib/components/selfie/src/selfie-capture-wrapper/index.ts +1 -1
  103. package/lib/components/selfie/src/smartselfie-capture/OvalProgress.tsx +81 -81
  104. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +265 -265
  105. package/lib/components/selfie/src/smartselfie-capture/components/AlertDisplay.tsx +34 -34
  106. package/lib/components/selfie/src/smartselfie-capture/components/CameraPreview.tsx +97 -97
  107. package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +78 -78
  108. package/lib/components/selfie/src/smartselfie-capture/components/index.ts +3 -3
  109. package/lib/components/selfie/src/smartselfie-capture/constants.ts +23 -23
  110. package/lib/components/selfie/src/smartselfie-capture/hooks/index.ts +2 -2
  111. package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +238 -238
  112. package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +618 -618
  113. package/lib/components/selfie/src/smartselfie-capture/index.ts +1 -1
  114. package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +13 -13
  115. package/lib/components/selfie/src/smartselfie-capture/utils/canvas.ts +105 -105
  116. package/lib/components/selfie/src/smartselfie-capture/utils/faceDetection.ts +129 -129
  117. package/lib/components/selfie/src/smartselfie-capture/utils/imageCapture.ts +64 -64
  118. package/lib/components/selfie/src/smartselfie-capture/utils/index.ts +4 -4
  119. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +118 -77
  120. package/lib/components/signature-pad/package-lock.json +3009 -3009
  121. package/lib/components/signature-pad/package.json +30 -30
  122. package/lib/components/signature-pad/src/SignaturePad.js +484 -484
  123. package/lib/components/signature-pad/src/SignaturePad.stories.js +32 -32
  124. package/lib/components/signature-pad/src/index.js +3 -3
  125. package/lib/components/smart-camera-web/src/README.md +206 -206
  126. package/lib/components/smart-camera-web/src/SmartCameraWeb.js +305 -305
  127. package/lib/components/smart-camera-web/src/SmartCameraWeb.stories.js +57 -57
  128. package/lib/components/totp-consent/src/TotpConsent.js +949 -949
  129. package/lib/components/totp-consent/src/index.js +4 -4
  130. package/lib/domain/camera/src/README.md +38 -38
  131. package/lib/domain/camera/src/SmartCamera.js +109 -109
  132. package/lib/domain/constants/src/Constants.js +27 -27
  133. package/lib/domain/file-upload/README.md +35 -35
  134. package/lib/domain/file-upload/src/SmartFileUpload.js +65 -65
  135. package/lib/styles/README.md +3 -3
  136. package/lib/styles/src/styles.js +372 -372
  137. package/lib/styles/src/typography.js +52 -52
  138. package/package.json +111 -112
  139. package/dist/esm/DocumentCaptureScreens-RECPb0wH.js.map +0 -1
  140. package/dist/esm/SelfieCaptureScreens-CqBVGEJk.js.map +0 -1
  141. package/dist/esm/package-BDJnoIAU.js.map +0 -1
@@ -1,256 +1,281 @@
1
- import { useState, useEffect } from 'preact/hooks';
2
- import { IconLoader2 } from '@tabler/icons-preact';
3
- import register from 'preact-custom-element';
4
- import type { FunctionComponent } from 'preact';
5
-
6
- import { getBoolProp } from '@/utils/props';
7
- import SmartSelfieCapture from '../smartselfie-capture/SmartSelfieCapture';
8
- import '../selfie-capture/SelfieCapture';
9
- import { getMediapipeInstance } from '../smartselfie-capture/utils/mediapipeManager';
10
-
11
- interface Props {
12
- timeout?: number;
13
- interval?: number;
14
- duration?: number;
15
- 'theme-color'?: string;
16
- 'show-navigation'?: string | boolean;
17
- 'allow-agent-mode'?: string | boolean;
18
- 'show-agent-mode-for-tests'?: string | boolean;
19
- 'hide-attribution'?: string | boolean;
20
- 'disable-image-tests'?: string | boolean;
21
- key?: string;
22
- 'start-countdown'?: string | boolean;
23
- hidden?: string | boolean;
24
- }
25
-
26
- const SelfieCaptureWrapper: FunctionComponent<Props> = ({
27
- timeout = 20000,
28
- 'start-countdown': startCountdownProp = false,
29
- hidden: hiddenProp = false,
30
- ...props
31
- }) => {
32
- const isParentCypress = (() => {
33
- try {
34
- return (
35
- !!(window.parent as any).Cypress ||
36
- (window.parent.navigator.userAgent.includes('Electron') &&
37
- (window.parent as any).__Cypress)
38
- );
39
- } catch {
40
- return false;
41
- }
42
- })();
43
- const isCypress =
44
- isParentCypress ||
45
- !!(window as any).Cypress ||
46
- (window.navigator.userAgent.includes('Electron') &&
47
- (window as any).__Cypress);
48
-
49
- const hidden = getBoolProp(hiddenProp);
50
- const startCountdown = getBoolProp(startCountdownProp);
51
- const [mediapipeReady, setMediapipeReady] = useState(false);
52
- const [loadingProgress, setLoadingProgress] = useState(isCypress ? 100 : 0);
53
- const [initialSessionCompleted, setInitialSessionCompleted] = useState(false);
54
- const [mediapipeLoading, setMediapipeLoading] = useState(false);
55
- const [usingSelfieCapture, setUsingSelfieCapture] = useState(false);
56
-
57
- useEffect(() => {
58
- if (mediapipeReady || mediapipeLoading || isCypress) return;
59
-
60
- const loadMediapipe = async () => {
61
- setMediapipeLoading(true);
62
- try {
63
- await getMediapipeInstance();
64
- setMediapipeReady(true);
65
- } catch (error) {
66
- console.error('Failed to load Mediapipe:', error);
67
- }
68
- setMediapipeLoading(false);
69
- };
70
-
71
- loadMediapipe();
72
- }, [mediapipeReady, mediapipeLoading]);
73
-
74
- useEffect(() => {
75
- if (hidden || !startCountdown || mediapipeReady) return undefined;
76
-
77
- const timer = setInterval(() => {
78
- setLoadingProgress((prev: number) => Math.min(prev + 1, 100));
79
- }, timeout / 100);
80
-
81
- return () => {
82
- clearInterval(timer);
83
- };
84
- }, [hidden, startCountdown, timeout, mediapipeReady]);
85
-
86
- useEffect(() => {
87
- if (hidden || mediapipeReady || loadingProgress < 100) return undefined;
88
-
89
- const setupEventForwarding = () => {
90
- const selfieCapture = document.querySelector('selfie-capture');
91
- if (
92
- selfieCapture &&
93
- !selfieCapture.hasAttribute('data-backup-events-setup')
94
- ) {
95
- selfieCapture.setAttribute('data-backup-events-setup', 'true');
96
-
97
- const forwardEvent = (event: Event) => {
98
- const customEvent = event as CustomEvent;
99
- window.dispatchEvent(
100
- new CustomEvent(customEvent.type, {
101
- detail: customEvent.detail,
102
- bubbles: true,
103
- }),
104
- );
105
- };
106
-
107
- selfieCapture.addEventListener('selfie-capture.publish', forwardEvent);
108
- selfieCapture.addEventListener(
109
- 'selfie-capture.cancelled',
110
- forwardEvent,
111
- );
112
- selfieCapture.addEventListener('selfie-capture.close', forwardEvent);
113
-
114
- return () => {
115
- selfieCapture.removeEventListener(
116
- 'selfie-capture.publish',
117
- forwardEvent,
118
- );
119
- selfieCapture.removeEventListener(
120
- 'selfie-capture.cancelled',
121
- forwardEvent,
122
- );
123
- selfieCapture.removeEventListener(
124
- 'selfie-capture.close',
125
- forwardEvent,
126
- );
127
- };
128
- }
129
- return undefined;
130
- };
131
-
132
- const timeoutId = setTimeout(setupEventForwarding, 200);
133
- return () => {
134
- clearTimeout(timeoutId);
135
- };
136
- }, [hidden, mediapipeReady, loadingProgress]);
137
-
138
- useEffect(() => {
139
- if (hidden || mediapipeLoading) return;
140
-
141
- const smartCameraWeb = document.querySelector('smart-camera-web');
142
- smartCameraWeb?.dispatchEvent(
143
- new CustomEvent('metadata.active-liveness-version', {
144
- detail: {
145
- version: usingSelfieCapture ? '0.0.1' : '1.0.0',
146
- },
147
- }),
148
- );
149
- }, [usingSelfieCapture, hidden, mediapipeLoading]);
150
-
151
- if (hidden) {
152
- return null;
153
- }
154
-
155
- // on retakes, prefer SmartSelfieCapture if Mediapipe is ready
156
- if (initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
157
- return <SmartSelfieCapture {...props} />;
158
- }
159
-
160
- // use SmartSelfieCapture if mediapipe loads
161
- if (!initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
162
- return <SmartSelfieCapture {...props} />;
163
- }
164
-
165
- if (loadingProgress >= 100) {
166
- if (!usingSelfieCapture) {
167
- setUsingSelfieCapture(true);
168
- }
169
-
170
- const propsWithoutHidden = { ...props };
171
- delete (propsWithoutHidden as any).hidden;
172
-
173
- return (
174
- // @ts-ignore
175
- <selfie-capture
176
- {...propsWithoutHidden}
177
- ref={(el: HTMLElement) => {
178
- if (el && !el.hasAttribute('data-events-setup')) {
179
- el.setAttribute('data-events-setup', 'true');
180
-
181
- const forwardEvent = (event: Event) => {
182
- const customEvent = event as CustomEvent;
183
-
184
- if (
185
- customEvent.type === 'selfie-capture.publish' ||
186
- customEvent.type === 'selfie-capture.cancelled' ||
187
- customEvent.type === 'selfie-capture.close'
188
- ) {
189
- setInitialSessionCompleted(true);
190
- }
191
-
192
- window.dispatchEvent(
193
- new CustomEvent(customEvent.type, {
194
- detail: customEvent.detail,
195
- bubbles: true,
196
- }),
197
- );
198
- };
199
-
200
- el.addEventListener('selfie-capture.publish', forwardEvent);
201
- el.addEventListener('selfie-capture.cancelled', forwardEvent);
202
- el.addEventListener('selfie-capture.close', forwardEvent);
203
- }
204
- }}
205
- />
206
- );
207
- }
208
-
209
- return (
210
- <div style={{ textAlign: 'center', marginTop: '20%' }}>
211
- <div
212
- style={{
213
- marginBottom: '16px',
214
- display: 'flex',
215
- justifyContent: 'center',
216
- }}
217
- >
218
- <IconLoader2
219
- size={48}
220
- style={{ animation: 'spin 1s linear infinite' }}
221
- />
222
- </div>
223
- <p>Loading... {loadingProgress}%</p>
224
- <style>{`
225
- @keyframes spin {
226
- from { transform: rotate(0deg); }
227
- to { transform: rotate(360deg); }
228
- }
229
- `}</style>
230
- </div>
231
- );
232
- };
233
-
234
- if (!customElements.get('selfie-capture-wrapper')) {
235
- register(
236
- SelfieCaptureWrapper,
237
- 'selfie-capture-wrapper',
238
- [
239
- 'timeout',
240
- 'interval',
241
- 'duration',
242
- 'theme-color',
243
- 'show-navigation',
244
- 'allow-agent-mode',
245
- 'show-agent-mode-for-tests',
246
- 'hide-attribution',
247
- 'disable-image-tests',
248
- 'key',
249
- 'start-countdown',
250
- 'hidden',
251
- ],
252
- { shadow: true },
253
- );
254
- }
255
-
256
- export default SelfieCaptureWrapper;
1
+ import { useState, useEffect } from 'preact/hooks';
2
+ import { IconLoader2 } from '@tabler/icons-preact';
3
+ import register from 'preact-custom-element';
4
+ import type { FunctionComponent } from 'preact';
5
+
6
+ import { getBoolProp } from '@/utils/props';
7
+ import SmartSelfieCapture from '../smartselfie-capture/SmartSelfieCapture';
8
+ // Legacy web component fallback (used when Mediapipe isn't available)
9
+ import '../selfie-capture/SelfieCapture';
10
+ // Mediapipe loader/manager used by SmartSelfieCapture
11
+ import { getMediapipeInstance } from '../smartselfie-capture/utils/mediapipeManager';
12
+
13
+ interface Props {
14
+ timeout?: number;
15
+ interval?: number;
16
+ duration?: number;
17
+ 'theme-color'?: string;
18
+ 'show-navigation'?: string | boolean;
19
+ 'allow-agent-mode'?: string | boolean;
20
+ 'show-agent-mode-for-tests'?: string | boolean;
21
+ 'hide-attribution'?: string | boolean;
22
+ 'disable-image-tests'?: string | boolean;
23
+ key?: string;
24
+ 'start-countdown'?: string | boolean;
25
+ hidden?: string | boolean;
26
+ }
27
+
28
+ // Wrapper component that decides whether to use the modern
29
+ // SmartSelfieCapture (Mediapipe-based) or fallback to the legacy `selfie-capture`
30
+ // web component after a timeout of 20 seconds.
31
+ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
32
+ timeout = 20000,
33
+ 'start-countdown': startCountdownProp = false,
34
+ hidden: hiddenProp = false,
35
+ ...props
36
+ }) => {
37
+ // Detect if tests are running under Cypress/Electron (affects loading behavior)
38
+ const isParentCypress = (() => {
39
+ try {
40
+ return (
41
+ !!(window.parent as any).Cypress ||
42
+ (window.parent.navigator.userAgent.includes('Electron') &&
43
+ (window.parent as any).__Cypress)
44
+ );
45
+ } catch {
46
+ return false;
47
+ }
48
+ })();
49
+ const isCypress =
50
+ isParentCypress ||
51
+ !!(window as any).Cypress ||
52
+ (window.navigator.userAgent.includes('Electron') &&
53
+ (window as any).__Cypress);
54
+
55
+ const hidden = getBoolProp(hiddenProp);
56
+ const startCountdown = getBoolProp(startCountdownProp);
57
+ // Component state:
58
+ // - mediapipeReady: whether the mediapipe instance has successfully loaded
59
+ // - loadingProgress: percentage used for the visible loading UI
60
+ // - initialSessionCompleted: set when the legacy component emits publish/cancel/close
61
+ // - mediapipeLoading: true while attempting to load mediapipe
62
+ // - usingSelfieCapture: whether we've mounted the legacy `selfie-capture` element
63
+ const [mediapipeReady, setMediapipeReady] = useState(false);
64
+ const [loadingProgress, setLoadingProgress] = useState(isCypress ? 100 : 0);
65
+ const [initialSessionCompleted, setInitialSessionCompleted] = useState(false);
66
+ const [mediapipeLoading, setMediapipeLoading] = useState(false);
67
+ const [usingSelfieCapture, setUsingSelfieCapture] = useState(false);
68
+
69
+ // Attempt to load Mediapipe (once). If Mediapipe is already ready, loading,
70
+ // or running under Cypress, skip the attempt. This side-effect flips
71
+ // mediapipeReady/mediapipeLoading flags which control which component is used.
72
+ useEffect(() => {
73
+ if (mediapipeReady || mediapipeLoading || isCypress) return;
74
+
75
+ const loadMediapipe = async () => {
76
+ setMediapipeLoading(true);
77
+ try {
78
+ await getMediapipeInstance();
79
+ setMediapipeReady(true);
80
+ } catch (error) {
81
+ // Loading failed; we'll fall back to the legacy selfie-capture component
82
+ // after the loadingProgress reaches 100%.
83
+ console.error('Failed to load Mediapipe:', error);
84
+ }
85
+ setMediapipeLoading(false);
86
+ };
87
+
88
+ loadMediapipe();
89
+ }, [mediapipeReady, mediapipeLoading]);
90
+
91
+ // When using the loading countdown (startCountdown), increment the
92
+ // visible loading progress. This is only used while mediapipe hasn't
93
+ // reported ready; once mediapipeReady becomes true we stop the timer.
94
+ useEffect(() => {
95
+ if (hidden || !startCountdown || mediapipeReady) return undefined;
96
+
97
+ const timer = setInterval(() => {
98
+ setLoadingProgress((prev: number) => Math.min(prev + 1, 100));
99
+ }, timeout / 100);
100
+
101
+ return () => {
102
+ clearInterval(timer);
103
+ };
104
+ }, [hidden, startCountdown, timeout, mediapipeReady]);
105
+
106
+ useEffect(() => {
107
+ if (hidden || mediapipeReady || loadingProgress < 100) return undefined;
108
+
109
+ const setupEventForwarding = () => {
110
+ const selfieCapture = document.querySelector('selfie-capture');
111
+ if (
112
+ selfieCapture &&
113
+ !selfieCapture.hasAttribute('data-backup-events-setup')
114
+ ) {
115
+ selfieCapture.setAttribute('data-backup-events-setup', 'true');
116
+
117
+ const forwardEvent = (event: Event) => {
118
+ const customEvent = event as CustomEvent;
119
+ window.dispatchEvent(
120
+ new CustomEvent(customEvent.type, {
121
+ detail: customEvent.detail,
122
+ bubbles: true,
123
+ }),
124
+ );
125
+ };
126
+
127
+ selfieCapture.addEventListener('selfie-capture.publish', forwardEvent);
128
+ selfieCapture.addEventListener(
129
+ 'selfie-capture.cancelled',
130
+ forwardEvent,
131
+ );
132
+ selfieCapture.addEventListener('selfie-capture.close', forwardEvent);
133
+
134
+ return () => {
135
+ selfieCapture.removeEventListener(
136
+ 'selfie-capture.publish',
137
+ forwardEvent,
138
+ );
139
+ selfieCapture.removeEventListener(
140
+ 'selfie-capture.cancelled',
141
+ forwardEvent,
142
+ );
143
+ selfieCapture.removeEventListener(
144
+ 'selfie-capture.close',
145
+ forwardEvent,
146
+ );
147
+ };
148
+ }
149
+ return undefined;
150
+ };
151
+
152
+ const timeoutId = setTimeout(setupEventForwarding, 200);
153
+ return () => {
154
+ clearTimeout(timeoutId);
155
+ };
156
+ }, [hidden, mediapipeReady, loadingProgress]);
157
+
158
+ // Announce to any `smart-camera-web` element which liveness version is active.
159
+ // The old capture users 0.0.1, the new one 1.0.0.
160
+ useEffect(() => {
161
+ if (hidden || mediapipeLoading) return;
162
+
163
+ const smartCameraWeb = document.querySelector('smart-camera-web');
164
+ smartCameraWeb?.dispatchEvent(
165
+ new CustomEvent('metadata.active-liveness-version', {
166
+ detail: {
167
+ version: usingSelfieCapture ? '0.0.1' : '1.0.0',
168
+ },
169
+ }),
170
+ );
171
+ }, [usingSelfieCapture, hidden, mediapipeLoading]);
172
+
173
+ if (hidden) {
174
+ return null;
175
+ }
176
+
177
+ // on retakes, prefer SmartSelfieCapture if Mediapipe is ready
178
+ if (initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
179
+ return <SmartSelfieCapture {...props} />;
180
+ }
181
+
182
+ // use SmartSelfieCapture if mediapipe loads
183
+ if (!initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
184
+ return <SmartSelfieCapture {...props} />;
185
+ }
186
+
187
+ if (loadingProgress >= 100) {
188
+ // When loading completes without Mediapipe becoming ready, mount the legacy
189
+ // `selfie-capture` web component. We also set `usingSelfieCapture` so other
190
+ // effects can react (e.g. metadata dispatch).
191
+ if (!usingSelfieCapture) {
192
+ setUsingSelfieCapture(true);
193
+ }
194
+
195
+ const propsWithoutHidden = { ...props };
196
+ delete (propsWithoutHidden as any).hidden;
197
+
198
+ return (
199
+ // @ts-ignore
200
+ <selfie-capture
201
+ {...propsWithoutHidden}
202
+ ref={(el: HTMLElement) => {
203
+ if (el && !el.hasAttribute('data-events-setup')) {
204
+ el.setAttribute('data-events-setup', 'true');
205
+
206
+ const forwardEvent = (event: Event) => {
207
+ const customEvent = event as CustomEvent;
208
+
209
+ if (
210
+ customEvent.type === 'selfie-capture.publish' ||
211
+ customEvent.type === 'selfie-capture.cancelled' ||
212
+ customEvent.type === 'selfie-capture.close'
213
+ ) {
214
+ setInitialSessionCompleted(true);
215
+ }
216
+
217
+ window.dispatchEvent(
218
+ new CustomEvent(customEvent.type, {
219
+ detail: customEvent.detail,
220
+ bubbles: true,
221
+ }),
222
+ );
223
+ };
224
+
225
+ el.addEventListener('selfie-capture.publish', forwardEvent);
226
+ el.addEventListener('selfie-capture.cancelled', forwardEvent);
227
+ el.addEventListener('selfie-capture.close', forwardEvent);
228
+ }
229
+ }}
230
+ />
231
+ );
232
+ }
233
+
234
+ return (
235
+ <div style={{ textAlign: 'center', marginTop: '20%' }}>
236
+ <div
237
+ style={{
238
+ marginBottom: '16px',
239
+ display: 'flex',
240
+ justifyContent: 'center',
241
+ }}
242
+ >
243
+ <IconLoader2
244
+ size={48}
245
+ style={{ animation: 'spin 1s linear infinite' }}
246
+ />
247
+ </div>
248
+ <p>Loading... {loadingProgress}%</p>
249
+ <style>{`
250
+ @keyframes spin {
251
+ from { transform: rotate(0deg); }
252
+ to { transform: rotate(360deg); }
253
+ }
254
+ `}</style>
255
+ </div>
256
+ );
257
+ };
258
+
259
+ if (!customElements.get('selfie-capture-wrapper')) {
260
+ register(
261
+ SelfieCaptureWrapper,
262
+ 'selfie-capture-wrapper',
263
+ [
264
+ 'timeout',
265
+ 'interval',
266
+ 'duration',
267
+ 'theme-color',
268
+ 'show-navigation',
269
+ 'allow-agent-mode',
270
+ 'show-agent-mode-for-tests',
271
+ 'hide-attribution',
272
+ 'disable-image-tests',
273
+ 'key',
274
+ 'start-countdown',
275
+ 'hidden',
276
+ ],
277
+ { shadow: true },
278
+ );
279
+ }
280
+
281
+ export default SelfieCaptureWrapper;
@@ -1 +1 @@
1
- export { default as SelfieCaptureWrapper } from './SelfieCaptureWrapper';
1
+ export { default as SelfieCaptureWrapper } from './SelfieCaptureWrapper';