@smileid/web-components 2.0.2 → 10.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.
- package/dist/esm/DocumentCaptureScreens-ChpBVvNE.js +1532 -0
- package/dist/esm/DocumentCaptureScreens-ChpBVvNE.js.map +1 -0
- package/dist/esm/EndUserConsent-CMHp-34-.js +715 -0
- package/dist/esm/EndUserConsent-CMHp-34-.js.map +1 -0
- package/dist/esm/Navigation-juBE4qOw.js +136 -0
- package/dist/esm/Navigation-juBE4qOw.js.map +1 -0
- package/dist/esm/PoweredBySmileId-CxbaihMu.js +33 -0
- package/dist/esm/PoweredBySmileId-CxbaihMu.js.map +1 -0
- package/dist/esm/SelfieCaptureScreens-DMo-z-32.js +7618 -0
- package/dist/esm/SelfieCaptureScreens-DMo-z-32.js.map +1 -0
- package/dist/esm/SignaturePad-C7MtmT8m.js +324 -0
- package/dist/esm/SignaturePad-C7MtmT8m.js.map +1 -0
- package/dist/esm/TotpConsent-CQU5jQi4.js +730 -0
- package/dist/esm/TotpConsent-CQU5jQi4.js.map +1 -0
- package/dist/esm/combobox.js +300 -0
- package/dist/esm/combobox.js.map +1 -0
- package/dist/esm/document.js +5 -0
- package/dist/esm/document.js.map +1 -0
- package/dist/esm/end-user-consent.js +5 -0
- package/dist/esm/end-user-consent.js.map +1 -0
- package/dist/esm/main.js +22 -0
- package/dist/esm/main.js.map +1 -0
- package/dist/esm/navigation.js +5 -0
- package/dist/esm/navigation.js.map +1 -0
- package/dist/esm/package-D_4zJ9ck.js +105 -0
- package/dist/esm/package-D_4zJ9ck.js.map +1 -0
- package/dist/esm/selfie.js +5 -0
- package/dist/esm/selfie.js.map +1 -0
- package/dist/esm/signature-pad.js +5 -0
- package/dist/esm/signature-pad.js.map +1 -0
- package/dist/esm/smart-camera-web.js +302 -0
- package/dist/esm/smart-camera-web.js.map +1 -0
- package/dist/esm/styles-D2i3GFLK.js +405 -0
- package/dist/esm/styles-D2i3GFLK.js.map +1 -0
- package/dist/esm/totp-consent.js +5 -0
- package/dist/esm/totp-consent.js.map +1 -0
- package/dist/smart-camera-web.js +4130 -0
- package/dist/smart-camera-web.js.map +1 -0
- package/dist/types/combobox.d.ts +21 -0
- package/dist/types/document.d.ts +21 -0
- package/dist/types/end-user-consent.d.ts +21 -0
- package/dist/types/main.d.ts +331 -0
- package/dist/types/navigation.d.ts +21 -0
- package/dist/types/selfie.d.ts +21 -0
- package/dist/types/signature-pad.d.ts +21 -0
- package/dist/types/smart-camera-web.d.ts +21 -0
- package/dist/types/totp-consent.d.ts +21 -0
- package/{src → lib}/components/camera-permission/CameraPermission.js +0 -1
- package/{src → lib}/components/document/src/document-capture/DocumentCapture.js +0 -1
- package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.js +0 -1
- package/{src → lib}/components/selfie/src/SelfieCaptureScreens.js +188 -37
- package/{src → lib}/components/selfie/src/index.js +0 -2
- package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.js +3 -4
- package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +0 -1
- package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +0 -8
- package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +226 -0
- package/lib/components/selfie/src/selfie-capture-wrapper/index.ts +1 -0
- package/lib/components/selfie/src/smartselfie-capture/OvalProgress.tsx +81 -0
- package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +223 -0
- package/lib/components/selfie/src/smartselfie-capture/components/AlertDisplay.tsx +34 -0
- package/lib/components/selfie/src/smartselfie-capture/components/CameraPreview.tsx +97 -0
- package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +74 -0
- package/lib/components/selfie/src/smartselfie-capture/components/index.ts +3 -0
- package/lib/components/selfie/src/smartselfie-capture/constants.ts +23 -0
- package/lib/components/selfie/src/smartselfie-capture/hooks/index.ts +2 -0
- package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +94 -0
- package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +558 -0
- package/lib/components/selfie/src/smartselfie-capture/index.ts +1 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +12 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/canvas.ts +105 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/faceDetection.ts +129 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/imageCapture.ts +65 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/index.ts +4 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +60 -0
- package/{src → lib}/components/signature-pad/package.json +1 -1
- package/{src → lib}/components/smart-camera-web/src/README.md +0 -1
- package/{src → lib}/styles/src/styles.js +0 -1
- package/package.json +76 -24
- package/src/index.js +0 -5
- /package/{src → lib}/components/README.md +0 -0
- /package/{src → lib}/components/attribution/PoweredBySmileId.js +0 -0
- /package/{src → lib}/components/camera-permission/CameraPermission.stories.js +0 -0
- /package/{src → lib}/components/combobox/src/Combobox.js +0 -0
- /package/{src → lib}/components/combobox/src/index.js +0 -0
- /package/{src → lib}/components/document/src/DocumentCaptureScreens.js +0 -0
- /package/{src → lib}/components/document/src/DocumentCaptureScreens.stories.js +0 -0
- /package/{src → lib}/components/document/src/README.md +0 -0
- /package/{src → lib}/components/document/src/document-capture/DocumentCapture.stories.js +0 -0
- /package/{src → lib}/components/document/src/document-capture/README.md +0 -0
- /package/{src → lib}/components/document/src/document-capture/index.js +0 -0
- /package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +0 -0
- /package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +0 -0
- /package/{src → lib}/components/document/src/document-capture-instructions/README.md +0 -0
- /package/{src → lib}/components/document/src/document-capture-instructions/index.js +0 -0
- /package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +0 -0
- /package/{src → lib}/components/document/src/document-capture-review/README.md +0 -0
- /package/{src → lib}/components/document/src/document-capture-review/index.js +0 -0
- /package/{src → lib}/components/document/src/index.js +0 -0
- /package/{src → lib}/components/end-user-consent/src/EndUserConsent.js +0 -0
- /package/{src → lib}/components/end-user-consent/src/EndUserConsent.stories.js +0 -0
- /package/{src → lib}/components/end-user-consent/src/index.js +0 -0
- /package/{src → lib}/components/navigation/src/Navigation.js +0 -0
- /package/{src → lib}/components/navigation/src/Navigation.stories.js +0 -0
- /package/{src → lib}/components/navigation/src/index.js +0 -0
- /package/{src → lib}/components/selfie/README.md +0 -0
- /package/{src → lib}/components/selfie/src/SelfieCaptureScreens.stories.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.stories.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture/index.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture-instructions/index.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +0 -0
- /package/{src → lib}/components/selfie/src/selfie-capture-review/index.js +0 -0
- /package/{src → lib}/components/signature-pad/package-lock.json +0 -0
- /package/{src → lib}/components/signature-pad/src/SignaturePad.js +0 -0
- /package/{src → lib}/components/signature-pad/src/SignaturePad.stories.js +0 -0
- /package/{src → lib}/components/signature-pad/src/index.js +0 -0
- /package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.js +0 -0
- /package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.stories.js +0 -0
- /package/{src → lib}/components/totp-consent/src/TotpConsent.js +0 -0
- /package/{src → lib}/components/totp-consent/src/index.js +0 -0
- /package/{src → lib}/domain/camera/src/README.md +0 -0
- /package/{src → lib}/domain/camera/src/SmartCamera.js +0 -0
- /package/{src → lib}/domain/constants/src/Constants.js +0 -0
- /package/{src → lib}/domain/file-upload/README.md +0 -0
- /package/{src → lib}/domain/file-upload/src/SmartFileUpload.js +0 -0
- /package/{src → lib}/styles/README.md +0 -0
- /package/{src → lib}/styles/src/typography.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import './selfie-capture';
|
|
2
1
|
import './selfie-capture-instructions';
|
|
3
2
|
import './selfie-capture-review';
|
|
3
|
+
import './selfie-capture-wrapper/index.ts';
|
|
4
4
|
import SmartCamera from '../../../domain/camera/src/SmartCamera';
|
|
5
5
|
import styles from '../../../styles/src/styles';
|
|
6
6
|
import packageJson from '../../../../package.json';
|
|
@@ -37,10 +37,76 @@ async function getPermissions(captureScreen, facingMode = 'user') {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
const cropImageFromDataUri = (
|
|
41
|
+
dataUri,
|
|
42
|
+
cropPercentX = 0,
|
|
43
|
+
cropPercentY = 0,
|
|
44
|
+
quality = 0.9,
|
|
45
|
+
) =>
|
|
46
|
+
new Promise((resolve, reject) => {
|
|
47
|
+
if (!dataUri || typeof dataUri !== 'string') {
|
|
48
|
+
reject(new Error('Invalid data URI provided'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
cropPercentX < 0 ||
|
|
54
|
+
cropPercentX >= 99 ||
|
|
55
|
+
cropPercentY < 0 ||
|
|
56
|
+
cropPercentY >= 99
|
|
57
|
+
) {
|
|
58
|
+
reject(new Error('Crop percentages must be between 0 and 99'));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const img = new Image();
|
|
63
|
+
|
|
64
|
+
img.onload = () => {
|
|
65
|
+
try {
|
|
66
|
+
const canvas = document.createElement('canvas');
|
|
67
|
+
const ctx = canvas.getContext('2d');
|
|
68
|
+
|
|
69
|
+
const originalWidth = img.width;
|
|
70
|
+
const originalHeight = img.height;
|
|
71
|
+
const cropAmountX = (originalWidth * cropPercentX) / 100;
|
|
72
|
+
const cropAmountY = (originalHeight * cropPercentY) / 100;
|
|
73
|
+
|
|
74
|
+
const newWidth = originalWidth - cropAmountX * 2;
|
|
75
|
+
const newHeight = originalHeight - cropAmountY * 2;
|
|
76
|
+
canvas.width = newWidth;
|
|
77
|
+
canvas.height = newHeight;
|
|
78
|
+
|
|
79
|
+
ctx.drawImage(
|
|
80
|
+
img,
|
|
81
|
+
cropAmountX,
|
|
82
|
+
cropAmountY,
|
|
83
|
+
newWidth,
|
|
84
|
+
newHeight,
|
|
85
|
+
0,
|
|
86
|
+
0,
|
|
87
|
+
newWidth,
|
|
88
|
+
newHeight,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const croppedDataUri = canvas.toDataURL('image/jpeg', quality);
|
|
92
|
+
resolve(croppedDataUri);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
reject(new Error(`Failed to process image: ${error.message}`));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
img.onerror = () => {
|
|
99
|
+
reject(new Error('Failed to load image from data URI'));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
img.src = dataUri;
|
|
103
|
+
});
|
|
104
|
+
|
|
40
105
|
class SelfieCaptureScreens extends HTMLElement {
|
|
41
106
|
constructor() {
|
|
42
107
|
super();
|
|
43
108
|
this.activeScreen = null;
|
|
109
|
+
this._remountKey = 0; // Counter for forcing wrapper remounts
|
|
44
110
|
smartCameraWeb?.dispatchEvent(new CustomEvent('metadata.initialize'));
|
|
45
111
|
}
|
|
46
112
|
|
|
@@ -49,7 +115,7 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
49
115
|
${styles(this.themeColor)}
|
|
50
116
|
<div>
|
|
51
117
|
<selfie-capture-instructions theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} ${this.hideBack} hidden></selfie-capture-instructions>
|
|
52
|
-
<selfie-capture theme-color='${this.themeColor}' ${this.showNavigation} ${this.allowAgentMode} ${this.allowAgentModeTests} ${this.hideAttribution} ${this.disableImageTests} hidden></selfie-capture>
|
|
118
|
+
<selfie-capture-wrapper theme-color='${this.themeColor}' ${this.showNavigation} ${this.allowAgentMode} ${this.allowAgentModeTests} ${this.hideAttribution} ${this.disableImageTests} key="${this._remountKey}" start-countdown="false" hidden></selfie-capture-wrapper>
|
|
53
119
|
<selfie-capture-review theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
|
|
54
120
|
</div>
|
|
55
121
|
`;
|
|
@@ -60,9 +126,8 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
60
126
|
libraryVersion: COMPONENTS_VERSION,
|
|
61
127
|
},
|
|
62
128
|
};
|
|
63
|
-
|
|
64
129
|
this.selfieInstruction = this.querySelector('selfie-capture-instructions');
|
|
65
|
-
this.selfieCapture = this.querySelector('selfie-capture');
|
|
130
|
+
this.selfieCapture = this.querySelector('selfie-capture-wrapper');
|
|
66
131
|
this.selfieReview = this.querySelector('selfie-capture-review');
|
|
67
132
|
|
|
68
133
|
if (this.hideInstructions && !this.hasAttribute('hidden')) {
|
|
@@ -124,27 +189,8 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
124
189
|
this.handleBackEvents();
|
|
125
190
|
},
|
|
126
191
|
);
|
|
127
|
-
|
|
128
|
-
this.
|
|
129
|
-
this.selfieCapture.reset();
|
|
130
|
-
SmartCamera.stopMedia();
|
|
131
|
-
if (this.hideInstructions) {
|
|
132
|
-
this.handleBackEvents();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
this.setActiveScreen(this.selfieInstruction);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
this.selfieCapture.addEventListener('selfie-capture.publish', (event) => {
|
|
140
|
-
smartCameraWeb?.dispatchEvent(
|
|
141
|
-
new CustomEvent('metadata.selfie-capture-end'),
|
|
142
|
-
);
|
|
143
|
-
this.selfieReview.setAttribute('data-image', event.detail.referenceImage);
|
|
144
|
-
this._data.images = event.detail.images;
|
|
145
|
-
SmartCamera.stopMedia();
|
|
146
|
-
this.setActiveScreen(this.selfieReview);
|
|
147
|
-
});
|
|
192
|
+
// Setup selfie-wrapper event listeners
|
|
193
|
+
this.setupSelfieWrapperEventListeners();
|
|
148
194
|
|
|
149
195
|
this.selfieReview.addEventListener(
|
|
150
196
|
'selfie-capture-review.rejected',
|
|
@@ -154,6 +200,10 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
154
200
|
);
|
|
155
201
|
this.selfieReview.removeAttribute('data-image');
|
|
156
202
|
this._data.images = [];
|
|
203
|
+
|
|
204
|
+
// Force remount by incrementing key
|
|
205
|
+
this.forceWrapperRemount();
|
|
206
|
+
|
|
157
207
|
if (this.hideInstructions) {
|
|
158
208
|
this.setActiveScreen(this.selfieCapture);
|
|
159
209
|
await getPermissions(this.selfieCapture, this.getAgentMode());
|
|
@@ -182,6 +232,113 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
182
232
|
);
|
|
183
233
|
}
|
|
184
234
|
|
|
235
|
+
// Force remount of selfie-capture-wrapper component for clean state
|
|
236
|
+
forceWrapperRemount() {
|
|
237
|
+
this._remountKey++;
|
|
238
|
+
const container = this.querySelector('div');
|
|
239
|
+
const oldSelfieCapture = this.selfieCapture;
|
|
240
|
+
|
|
241
|
+
// Create new selfie-capture-wrapper element with same attributes
|
|
242
|
+
const newSelfieCapture = document.createElement('selfie-capture-wrapper');
|
|
243
|
+
newSelfieCapture.setAttribute('theme-color', this.themeColor);
|
|
244
|
+
newSelfieCapture.setAttribute('key', this._remountKey.toString());
|
|
245
|
+
newSelfieCapture.setAttribute('start-countdown', 'false');
|
|
246
|
+
|
|
247
|
+
// Copy all the correct attributes based on the getter logic
|
|
248
|
+
const showNav = this.hasAttribute('show-navigation');
|
|
249
|
+
const allowAgent = this.getAttribute('allow-agent-mode') === 'true';
|
|
250
|
+
const allowAgentTests = this.hasAttribute('show-agent-mode-for-tests');
|
|
251
|
+
const hideAttr = this.hasAttribute('hide-attribution');
|
|
252
|
+
const disableTests = this.hasAttribute('disable-image-tests');
|
|
253
|
+
|
|
254
|
+
if (showNav) newSelfieCapture.setAttribute('show-navigation', '');
|
|
255
|
+
if (allowAgent) newSelfieCapture.setAttribute('allow-agent-mode', 'true');
|
|
256
|
+
if (allowAgentTests)
|
|
257
|
+
newSelfieCapture.setAttribute('show-agent-mode-for-tests', '');
|
|
258
|
+
if (hideAttr) newSelfieCapture.setAttribute('hide-attribution', '');
|
|
259
|
+
if (disableTests) newSelfieCapture.setAttribute('disable-image-tests', '');
|
|
260
|
+
newSelfieCapture.setAttribute('hidden', '');
|
|
261
|
+
|
|
262
|
+
// Replace old element with new one
|
|
263
|
+
container.replaceChild(newSelfieCapture, oldSelfieCapture);
|
|
264
|
+
|
|
265
|
+
// Update reference
|
|
266
|
+
this.selfieCapture = newSelfieCapture;
|
|
267
|
+
|
|
268
|
+
// Re-add event listeners for the new element
|
|
269
|
+
this.setupSelfieWrapperEventListeners();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Override setActiveScreen to enable countdown when selfie-capture is active
|
|
273
|
+
setActiveScreen(screen) {
|
|
274
|
+
this.activeScreen?.setAttribute('hidden', '');
|
|
275
|
+
screen.removeAttribute('hidden');
|
|
276
|
+
this.activeScreen = screen;
|
|
277
|
+
|
|
278
|
+
// If activating selfie-capture-wrapper, enable the countdown and ensure permissions
|
|
279
|
+
if (screen === this.selfieCapture) {
|
|
280
|
+
screen.setAttribute('start-countdown', 'true');
|
|
281
|
+
getPermissions(this.selfieCapture, this.getAgentMode());
|
|
282
|
+
} else if (this.selfieCapture) {
|
|
283
|
+
// Disable countdown when not on capture screen
|
|
284
|
+
this.selfieCapture.setAttribute('start-countdown', 'false');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
setupSelfieWrapperEventListeners() {
|
|
289
|
+
window.addEventListener('selfie-capture.cancelled', () => {
|
|
290
|
+
SmartCamera.stopMedia();
|
|
291
|
+
|
|
292
|
+
// Force remount of selfie-capture-wrapper for clean state on next visit
|
|
293
|
+
this.forceWrapperRemount();
|
|
294
|
+
|
|
295
|
+
if (this.hideInstructions) {
|
|
296
|
+
this.handleBackEvents();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
this.setActiveScreen(this.selfieInstruction);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Add specific close event handler for selfie-capture-wrapper
|
|
304
|
+
window.addEventListener('selfie-capture.close', () => {
|
|
305
|
+
SmartCamera.stopMedia();
|
|
306
|
+
|
|
307
|
+
// Force remount of selfie-capture-wrapper for clean state on next visit
|
|
308
|
+
this.forceWrapperRemount();
|
|
309
|
+
|
|
310
|
+
this.handleCloseEvent();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
window.addEventListener('selfie-capture.publish', async (event) => {
|
|
314
|
+
smartCameraWeb?.dispatchEvent(
|
|
315
|
+
new CustomEvent('metadata.selfie-capture-end'),
|
|
316
|
+
);
|
|
317
|
+
this.selfieReview.setAttribute(
|
|
318
|
+
'data-image',
|
|
319
|
+
await cropImageFromDataUri(event.detail.referenceImage, 20, 20),
|
|
320
|
+
);
|
|
321
|
+
this._data.images = event.detail.images;
|
|
322
|
+
SmartCamera.stopMedia();
|
|
323
|
+
this.setActiveScreen(this.selfieReview);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Also listen for the publish event on the parent SelfieCaptureScreens element
|
|
327
|
+
// in case smartselfie-capture dispatches it there
|
|
328
|
+
this.addEventListener('selfie-capture.publish', async (event) => {
|
|
329
|
+
smartCameraWeb?.dispatchEvent(
|
|
330
|
+
new CustomEvent('metadata.selfie-capture-end'),
|
|
331
|
+
);
|
|
332
|
+
this.selfieReview.setAttribute(
|
|
333
|
+
'data-image',
|
|
334
|
+
await cropImageFromDataUri(event.detail.referenceImage, 20, 20),
|
|
335
|
+
);
|
|
336
|
+
this._data.images = event.detail.images;
|
|
337
|
+
SmartCamera.stopMedia();
|
|
338
|
+
this.setActiveScreen(this.selfieReview);
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
185
342
|
_publishSelectedImages() {
|
|
186
343
|
this.dispatchEvent(
|
|
187
344
|
new CustomEvent('selfie-capture-screens.publish', { detail: this._data }),
|
|
@@ -193,7 +350,7 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
193
350
|
}
|
|
194
351
|
|
|
195
352
|
get hideAttribution() {
|
|
196
|
-
return this.hasAttribute('hide-attribution') ? 'hide-attribution' : '';
|
|
353
|
+
return this.hasAttribute('hide-attribution') ? 'hide-attribution=""' : '';
|
|
197
354
|
}
|
|
198
355
|
|
|
199
356
|
get hideBackOfId() {
|
|
@@ -201,7 +358,7 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
201
358
|
}
|
|
202
359
|
|
|
203
360
|
get showNavigation() {
|
|
204
|
-
return this.hasAttribute('show-navigation') ? 'show-navigation' : '';
|
|
361
|
+
return this.hasAttribute('show-navigation') ? 'show-navigation=""' : '';
|
|
205
362
|
}
|
|
206
363
|
|
|
207
364
|
get inAgentMode() {
|
|
@@ -209,25 +366,25 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
209
366
|
}
|
|
210
367
|
|
|
211
368
|
get allowAgentMode() {
|
|
212
|
-
return this.inAgentMode ?
|
|
369
|
+
return this.inAgentMode ? 'allow-agent-mode="true"' : '';
|
|
213
370
|
}
|
|
214
371
|
|
|
215
372
|
get allowAgentModeTests() {
|
|
216
373
|
return this.hasAttribute('show-agent-mode-for-tests')
|
|
217
|
-
? 'show-agent-mode-for-tests'
|
|
374
|
+
? 'show-agent-mode-for-tests=""'
|
|
218
375
|
: '';
|
|
219
376
|
}
|
|
220
377
|
|
|
221
378
|
get hideBack() {
|
|
222
379
|
return this.hasAttribute('hide-back-to-host') ||
|
|
223
380
|
this.hasAttribute('hide-back')
|
|
224
|
-
? 'hide-back'
|
|
381
|
+
? 'hide-back=""'
|
|
225
382
|
: '';
|
|
226
383
|
}
|
|
227
384
|
|
|
228
385
|
get disableImageTests() {
|
|
229
386
|
return this.hasAttribute('disable-image-tests')
|
|
230
|
-
? 'disable-image-tests'
|
|
387
|
+
? 'disable-image-tests=""'
|
|
231
388
|
: '';
|
|
232
389
|
}
|
|
233
390
|
|
|
@@ -235,12 +392,6 @@ class SelfieCaptureScreens extends HTMLElement {
|
|
|
235
392
|
return this.getAttribute('theme-color') || '#001096';
|
|
236
393
|
}
|
|
237
394
|
|
|
238
|
-
setActiveScreen(screen) {
|
|
239
|
-
this.activeScreen?.setAttribute('hidden', '');
|
|
240
|
-
screen.removeAttribute('hidden');
|
|
241
|
-
this.activeScreen = screen;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
395
|
handleBackEvents() {
|
|
245
396
|
this.dispatchEvent(new CustomEvent('selfie-capture-screens.cancelled'));
|
|
246
397
|
}
|
|
@@ -358,7 +358,7 @@ function templateString() {
|
|
|
358
358
|
left: 50%;
|
|
359
359
|
min-width: auto;
|
|
360
360
|
position: absolute;
|
|
361
|
-
top:
|
|
361
|
+
top: 50%;
|
|
362
362
|
transform: translateX(-50%) translateY(50%);
|
|
363
363
|
}
|
|
364
364
|
|
|
@@ -381,7 +381,7 @@ function templateString() {
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
.video-container video {
|
|
384
|
-
|
|
384
|
+
height: 150%;
|
|
385
385
|
transform: scaleX(-1) translateX(50%) translateY(-50%);
|
|
386
386
|
}
|
|
387
387
|
|
|
@@ -468,7 +468,6 @@ function templateString() {
|
|
|
468
468
|
#selfie-capture-screen,
|
|
469
469
|
#back-of-id-entry-screen {
|
|
470
470
|
block-size: 45rem;
|
|
471
|
-
padding-block: 2rem;
|
|
472
471
|
display: flex;
|
|
473
472
|
flex-direction: column;
|
|
474
473
|
max-block-size: 100%;
|
|
@@ -520,7 +519,7 @@ function templateString() {
|
|
|
520
519
|
<div class='video-container'>
|
|
521
520
|
<div class='video'>
|
|
522
521
|
</div>
|
|
523
|
-
<svg id="image-outline" width="215" height="245" viewBox="0 0 215 245" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
522
|
+
<svg id="image-outline" width="215" height="245" viewBox="0 0 215 245" fill="none" xmlns="http://www.w3.org/2000/svg" style="position: relative;">
|
|
524
523
|
<path d="M210.981 122.838C210.981 188.699 164.248 241.268 107.55 241.268C50.853 241.268 4.12018 188.699 4.12018 122.838C4.12018 56.9763 50.853 4.40771 107.55 4.40771C164.248 4.40771 210.981 56.9763 210.981 122.838Z" stroke="${this.themeColor}" stroke-width="7.13965"/>
|
|
525
524
|
</svg>
|
|
526
525
|
<div id="smile-cta-box">
|
|
@@ -94,7 +94,6 @@ function templateString() {
|
|
|
94
94
|
}
|
|
95
95
|
#selfie-capture-review-screen {
|
|
96
96
|
block-size: 45rem;
|
|
97
|
-
padding-block: 2rem;
|
|
98
97
|
display: flex;
|
|
99
98
|
flex-direction: column;
|
|
100
99
|
max-block-size: 100%;
|
|
@@ -126,13 +125,6 @@ function templateString() {
|
|
|
126
125
|
z-index: 1;
|
|
127
126
|
block-size: 100%;
|
|
128
127
|
}
|
|
129
|
-
|
|
130
|
-
.selfie-container,
|
|
131
|
-
.selfie-review-container.landscape {
|
|
132
|
-
height: auto;
|
|
133
|
-
clip-path: inset(15% 20% 20% 20% round 10px);
|
|
134
|
-
overflow: hidden;
|
|
135
|
-
}
|
|
136
128
|
|
|
137
129
|
.selfie-container img {
|
|
138
130
|
background-color: black;
|
|
@@ -0,0 +1,226 @@
|
|
|
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 hidden = getBoolProp(hiddenProp);
|
|
33
|
+
const startCountdown = getBoolProp(startCountdownProp);
|
|
34
|
+
const [mediapipeReady, setMediapipeReady] = useState(false);
|
|
35
|
+
const [loadingProgress, setLoadingProgress] = useState(0);
|
|
36
|
+
const [initialSessionCompleted, setInitialSessionCompleted] = useState(false);
|
|
37
|
+
const [mediapipeLoading, setMediapipeLoading] = useState(false);
|
|
38
|
+
const [usingSelfieCapture, setUsingSelfieCapture] = useState(false);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (mediapipeReady || mediapipeLoading) return;
|
|
42
|
+
|
|
43
|
+
const loadMediapipe = async () => {
|
|
44
|
+
setMediapipeLoading(true);
|
|
45
|
+
try {
|
|
46
|
+
await getMediapipeInstance();
|
|
47
|
+
setMediapipeReady(true);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Failed to load Mediapipe:', error);
|
|
50
|
+
}
|
|
51
|
+
setMediapipeLoading(false);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
loadMediapipe();
|
|
55
|
+
}, [mediapipeReady, mediapipeLoading]);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (hidden || !startCountdown || mediapipeReady) return undefined;
|
|
59
|
+
|
|
60
|
+
const timer = setInterval(() => {
|
|
61
|
+
setLoadingProgress((prev: number) => Math.min(prev + 1, 100));
|
|
62
|
+
}, timeout / 100);
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
clearInterval(timer);
|
|
66
|
+
};
|
|
67
|
+
}, [hidden, startCountdown, timeout, mediapipeReady]);
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (hidden || mediapipeReady || loadingProgress < 100) return undefined;
|
|
71
|
+
|
|
72
|
+
const setupEventForwarding = () => {
|
|
73
|
+
const selfieCapture = document.querySelector('selfie-capture');
|
|
74
|
+
if (
|
|
75
|
+
selfieCapture &&
|
|
76
|
+
!selfieCapture.hasAttribute('data-backup-events-setup')
|
|
77
|
+
) {
|
|
78
|
+
selfieCapture.setAttribute('data-backup-events-setup', 'true');
|
|
79
|
+
|
|
80
|
+
const forwardEvent = (event: Event) => {
|
|
81
|
+
const customEvent = event as CustomEvent;
|
|
82
|
+
window.dispatchEvent(
|
|
83
|
+
new CustomEvent(customEvent.type, {
|
|
84
|
+
detail: customEvent.detail,
|
|
85
|
+
bubbles: true,
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
selfieCapture.addEventListener('selfie-capture.publish', forwardEvent);
|
|
91
|
+
selfieCapture.addEventListener(
|
|
92
|
+
'selfie-capture.cancelled',
|
|
93
|
+
forwardEvent,
|
|
94
|
+
);
|
|
95
|
+
selfieCapture.addEventListener('selfie-capture.close', forwardEvent);
|
|
96
|
+
|
|
97
|
+
return () => {
|
|
98
|
+
selfieCapture.removeEventListener(
|
|
99
|
+
'selfie-capture.publish',
|
|
100
|
+
forwardEvent,
|
|
101
|
+
);
|
|
102
|
+
selfieCapture.removeEventListener(
|
|
103
|
+
'selfie-capture.cancelled',
|
|
104
|
+
forwardEvent,
|
|
105
|
+
);
|
|
106
|
+
selfieCapture.removeEventListener(
|
|
107
|
+
'selfie-capture.close',
|
|
108
|
+
forwardEvent,
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const timeoutId = setTimeout(setupEventForwarding, 200);
|
|
116
|
+
return () => {
|
|
117
|
+
clearTimeout(timeoutId);
|
|
118
|
+
};
|
|
119
|
+
}, [hidden, mediapipeReady, loadingProgress]);
|
|
120
|
+
|
|
121
|
+
if (hidden) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// on retakes, prefer SmartSelfieCapture if Mediapipe is ready
|
|
126
|
+
if (initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
|
|
127
|
+
return <SmartSelfieCapture {...props} />;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// use SmartSelfieCapture if mediapipe loads
|
|
131
|
+
if (!initialSessionCompleted && mediapipeReady && !usingSelfieCapture) {
|
|
132
|
+
return <SmartSelfieCapture {...props} />;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (loadingProgress >= 100) {
|
|
136
|
+
if (!usingSelfieCapture) {
|
|
137
|
+
setUsingSelfieCapture(true);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const propsWithoutHidden = { ...props };
|
|
141
|
+
delete (propsWithoutHidden as any).hidden;
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
// @ts-ignore
|
|
145
|
+
<selfie-capture
|
|
146
|
+
{...propsWithoutHidden}
|
|
147
|
+
ref={(el: HTMLElement) => {
|
|
148
|
+
if (el && !el.hasAttribute('data-events-setup')) {
|
|
149
|
+
el.setAttribute('data-events-setup', 'true');
|
|
150
|
+
|
|
151
|
+
const forwardEvent = (event: Event) => {
|
|
152
|
+
const customEvent = event as CustomEvent;
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
customEvent.type === 'selfie-capture.publish' ||
|
|
156
|
+
customEvent.type === 'selfie-capture.cancelled' ||
|
|
157
|
+
customEvent.type === 'selfie-capture.close'
|
|
158
|
+
) {
|
|
159
|
+
setInitialSessionCompleted(true);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
window.dispatchEvent(
|
|
163
|
+
new CustomEvent(customEvent.type, {
|
|
164
|
+
detail: customEvent.detail,
|
|
165
|
+
bubbles: true,
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
el.addEventListener('selfie-capture.publish', forwardEvent);
|
|
171
|
+
el.addEventListener('selfie-capture.cancelled', forwardEvent);
|
|
172
|
+
el.addEventListener('selfie-capture.close', forwardEvent);
|
|
173
|
+
}
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<div style={{ textAlign: 'center', marginTop: '20%' }}>
|
|
181
|
+
<div
|
|
182
|
+
style={{
|
|
183
|
+
marginBottom: '16px',
|
|
184
|
+
display: 'flex',
|
|
185
|
+
justifyContent: 'center',
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
<IconLoader2
|
|
189
|
+
size={48}
|
|
190
|
+
style={{ animation: 'spin 1s linear infinite' }}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
<p>Loading... {loadingProgress}%</p>
|
|
194
|
+
<style>{`
|
|
195
|
+
@keyframes spin {
|
|
196
|
+
from { transform: rotate(0deg); }
|
|
197
|
+
to { transform: rotate(360deg); }
|
|
198
|
+
}
|
|
199
|
+
`}</style>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
if (!customElements.get('selfie-capture-wrapper')) {
|
|
205
|
+
register(
|
|
206
|
+
SelfieCaptureWrapper,
|
|
207
|
+
'selfie-capture-wrapper',
|
|
208
|
+
[
|
|
209
|
+
'timeout',
|
|
210
|
+
'interval',
|
|
211
|
+
'duration',
|
|
212
|
+
'theme-color',
|
|
213
|
+
'show-navigation',
|
|
214
|
+
'allow-agent-mode',
|
|
215
|
+
'show-agent-mode-for-tests',
|
|
216
|
+
'hide-attribution',
|
|
217
|
+
'disable-image-tests',
|
|
218
|
+
'key',
|
|
219
|
+
'start-countdown',
|
|
220
|
+
'hidden',
|
|
221
|
+
],
|
|
222
|
+
{ shadow: true },
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export default SelfieCaptureWrapper;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SelfieCaptureWrapper } from './SelfieCaptureWrapper';
|