@smileid/web-components 2.0.1 → 10.0.0

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 (125) hide show
  1. package/dist/DocumentCaptureScreens-Dwl7UqVH.js +1534 -0
  2. package/dist/DocumentCaptureScreens-Dwl7UqVH.js.map +1 -0
  3. package/dist/EndUserConsent-C5hZdJzH.js +715 -0
  4. package/dist/EndUserConsent-C5hZdJzH.js.map +1 -0
  5. package/dist/Navigation-juBE4qOw.js +136 -0
  6. package/dist/Navigation-juBE4qOw.js.map +1 -0
  7. package/dist/PoweredBySmileId-CxbaihMu.js +33 -0
  8. package/dist/PoweredBySmileId-CxbaihMu.js.map +1 -0
  9. package/dist/SelfieCaptureScreens-CQc251hz.js +7618 -0
  10. package/dist/SelfieCaptureScreens-CQc251hz.js.map +1 -0
  11. package/dist/SignaturePad-C7MtmT8m.js +324 -0
  12. package/dist/SignaturePad-C7MtmT8m.js.map +1 -0
  13. package/dist/TotpConsent-CQU5jQi4.js +730 -0
  14. package/dist/TotpConsent-CQU5jQi4.js.map +1 -0
  15. package/dist/combobox.js +300 -0
  16. package/dist/combobox.js.map +1 -0
  17. package/dist/document.js +5 -0
  18. package/dist/document.js.map +1 -0
  19. package/dist/end-user-consent.js +5 -0
  20. package/dist/end-user-consent.js.map +1 -0
  21. package/dist/main.js +22 -0
  22. package/dist/main.js.map +1 -0
  23. package/dist/navigation.js +5 -0
  24. package/dist/navigation.js.map +1 -0
  25. package/dist/package-Oi2Yil3b.js +105 -0
  26. package/dist/package-Oi2Yil3b.js.map +1 -0
  27. package/dist/selfie.js +5 -0
  28. package/dist/selfie.js.map +1 -0
  29. package/dist/signature-pad.js +5 -0
  30. package/dist/signature-pad.js.map +1 -0
  31. package/dist/smart-camera-web.js +303 -0
  32. package/dist/smart-camera-web.js.map +1 -0
  33. package/dist/styles-BUWNxWeQ.js +406 -0
  34. package/dist/styles-BUWNxWeQ.js.map +1 -0
  35. package/dist/totp-consent.js +5 -0
  36. package/dist/totp-consent.js.map +1 -0
  37. package/dist/types/combobox.d.ts +21 -0
  38. package/dist/types/document.d.ts +21 -0
  39. package/dist/types/end-user-consent.d.ts +21 -0
  40. package/dist/types/main.d.ts +331 -0
  41. package/dist/types/navigation.d.ts +21 -0
  42. package/dist/types/selfie.d.ts +21 -0
  43. package/dist/types/signature-pad.d.ts +21 -0
  44. package/dist/types/smart-camera-web.d.ts +21 -0
  45. package/dist/types/totp-consent.d.ts +21 -0
  46. package/{src → lib}/components/README.md +14 -14
  47. package/{src → lib}/components/attribution/PoweredBySmileId.js +42 -42
  48. package/{src → lib}/components/camera-permission/CameraPermission.js +140 -140
  49. package/{src → lib}/components/camera-permission/CameraPermission.stories.js +27 -27
  50. package/{src → lib}/components/combobox/src/Combobox.js +589 -589
  51. package/{src → lib}/components/combobox/src/index.js +1 -1
  52. package/{src → lib}/components/document/src/DocumentCaptureScreens.js +409 -409
  53. package/{src → lib}/components/document/src/DocumentCaptureScreens.stories.js +57 -57
  54. package/{src → lib}/components/document/src/README.md +111 -111
  55. package/{src → lib}/components/document/src/document-capture/DocumentCapture.js +760 -760
  56. package/{src → lib}/components/document/src/document-capture/DocumentCapture.stories.js +78 -78
  57. package/{src → lib}/components/document/src/document-capture/README.md +90 -90
  58. package/{src → lib}/components/document/src/document-capture/index.js +3 -3
  59. package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +499 -499
  60. package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +24 -24
  61. package/{src → lib}/components/document/src/document-capture-instructions/README.md +56 -56
  62. package/{src → lib}/components/document/src/document-capture-instructions/index.js +3 -3
  63. package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.js +362 -362
  64. package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +24 -24
  65. package/{src → lib}/components/document/src/document-capture-review/README.md +79 -79
  66. package/{src → lib}/components/document/src/document-capture-review/index.js +3 -3
  67. package/{src → lib}/components/document/src/index.js +3 -3
  68. package/{src → lib}/components/end-user-consent/src/EndUserConsent.js +795 -795
  69. package/{src → lib}/components/end-user-consent/src/EndUserConsent.stories.js +29 -29
  70. package/{src → lib}/components/end-user-consent/src/index.js +4 -4
  71. package/{src → lib}/components/navigation/src/Navigation.js +171 -171
  72. package/{src → lib}/components/navigation/src/Navigation.stories.js +24 -24
  73. package/{src → lib}/components/navigation/src/index.js +3 -3
  74. package/{src → lib}/components/selfie/README.md +225 -225
  75. package/{src → lib}/components/selfie/src/SelfieCaptureScreens.js +433 -282
  76. package/{src → lib}/components/selfie/src/SelfieCaptureScreens.stories.js +29 -29
  77. package/{src → lib}/components/selfie/src/index.js +3 -5
  78. package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.js +1041 -1010
  79. package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.stories.js +36 -36
  80. package/{src → lib}/components/selfie/src/selfie-capture/index.js +3 -3
  81. package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +657 -648
  82. package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +23 -23
  83. package/{src → lib}/components/selfie/src/selfie-capture-instructions/index.js +3 -3
  84. package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +340 -347
  85. package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +24 -24
  86. package/{src → lib}/components/selfie/src/selfie-capture-review/index.js +3 -3
  87. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +227 -0
  88. package/lib/components/selfie/src/selfie-capture-wrapper/index.ts +1 -0
  89. package/lib/components/selfie/src/smartselfie-capture/OvalProgress.tsx +81 -0
  90. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +224 -0
  91. package/lib/components/selfie/src/smartselfie-capture/components/AlertDisplay.tsx +34 -0
  92. package/lib/components/selfie/src/smartselfie-capture/components/CameraPreview.tsx +97 -0
  93. package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +74 -0
  94. package/lib/components/selfie/src/smartselfie-capture/components/index.ts +3 -0
  95. package/lib/components/selfie/src/smartselfie-capture/constants.ts +23 -0
  96. package/lib/components/selfie/src/smartselfie-capture/hooks/index.ts +2 -0
  97. package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +94 -0
  98. package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +558 -0
  99. package/lib/components/selfie/src/smartselfie-capture/index.ts +1 -0
  100. package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +12 -0
  101. package/lib/components/selfie/src/smartselfie-capture/utils/canvas.ts +105 -0
  102. package/lib/components/selfie/src/smartselfie-capture/utils/faceDetection.ts +129 -0
  103. package/lib/components/selfie/src/smartselfie-capture/utils/imageCapture.ts +64 -0
  104. package/lib/components/selfie/src/smartselfie-capture/utils/index.ts +4 -0
  105. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +60 -0
  106. package/{src → lib}/components/signature-pad/package-lock.json +3009 -3009
  107. package/{src → lib}/components/signature-pad/package.json +30 -30
  108. package/{src → lib}/components/signature-pad/src/SignaturePad.js +484 -484
  109. package/{src → lib}/components/signature-pad/src/SignaturePad.stories.js +32 -32
  110. package/{src → lib}/components/signature-pad/src/index.js +3 -3
  111. package/{src → lib}/components/smart-camera-web/src/README.md +206 -207
  112. package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.js +299 -299
  113. package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.stories.js +57 -57
  114. package/{src → lib}/components/totp-consent/src/TotpConsent.js +949 -949
  115. package/{src → lib}/components/totp-consent/src/index.js +4 -4
  116. package/{src → lib}/domain/camera/src/README.md +38 -38
  117. package/{src → lib}/domain/camera/src/SmartCamera.js +109 -109
  118. package/{src → lib}/domain/constants/src/Constants.js +27 -27
  119. package/{src → lib}/domain/file-upload/README.md +35 -35
  120. package/{src → lib}/domain/file-upload/src/SmartFileUpload.js +65 -65
  121. package/{src → lib}/styles/README.md +3 -3
  122. package/{src → lib}/styles/src/styles.js +359 -359
  123. package/{src → lib}/styles/src/typography.js +52 -52
  124. package/package.json +109 -58
  125. package/src/index.js +0 -5
@@ -1,282 +1,433 @@
1
- import './selfie-capture';
2
- import './selfie-capture-instructions';
3
- import './selfie-capture-review';
4
- import SmartCamera from '../../../domain/camera/src/SmartCamera';
5
- import styles from '../../../styles/src/styles';
6
- import packageJson from '../../../../package.json';
7
-
8
- const COMPONENTS_VERSION = packageJson.version;
9
-
10
- const smartCameraWeb = document.querySelector('smart-camera-web');
11
-
12
- async function getPermissions(captureScreen, facingMode = 'user') {
13
- try {
14
- const stream = await SmartCamera.getMedia({
15
- audio: false,
16
- video: { facingMode },
17
- });
18
- const devices = await navigator.mediaDevices.enumerateDevices();
19
- const videoDevice = devices.find(
20
- (device) =>
21
- device.kind === 'videoinput' &&
22
- stream.getVideoTracks()[0].getSettings().deviceId === device.deviceId,
23
- );
24
- smartCameraWeb?.dispatchEvent(
25
- new CustomEvent('metadata.camera-name', {
26
- detail: { cameraName: videoDevice?.label },
27
- }),
28
- );
29
- captureScreen.removeAttribute('data-camera-error');
30
- captureScreen.setAttribute('data-camera-ready', true);
31
- } catch (error) {
32
- captureScreen.removeAttribute('data-camera-ready');
33
- captureScreen.setAttribute(
34
- 'data-camera-error',
35
- SmartCamera.handleCameraError(error),
36
- );
37
- }
38
- }
39
-
40
- class SelfieCaptureScreens extends HTMLElement {
41
- constructor() {
42
- super();
43
- this.activeScreen = null;
44
- smartCameraWeb?.dispatchEvent(new CustomEvent('metadata.initialize'));
45
- }
46
-
47
- connectedCallback() {
48
- this.innerHTML = `
49
- ${styles(this.themeColor)}
50
- <div>
51
- <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>
53
- <selfie-capture-review theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
54
- </div>
55
- `;
56
-
57
- this._data = {
58
- images: [],
59
- meta: {
60
- libraryVersion: COMPONENTS_VERSION,
61
- },
62
- };
63
-
64
- this.selfieInstruction = this.querySelector('selfie-capture-instructions');
65
- this.selfieCapture = this.querySelector('selfie-capture');
66
- this.selfieReview = this.querySelector('selfie-capture-review');
67
-
68
- if (this.hideInstructions && !this.hasAttribute('hidden')) {
69
- getPermissions(this.selfieCapture, this.getAgentMode());
70
- }
71
-
72
- // If the initial screen is selfie-capture, we need to get permissions
73
- if (this.getAttribute('initial-screen') === 'selfie-capture') {
74
- getPermissions(this.selfieCapture, this.getAgentMode()).then(() =>
75
- this.setActiveScreen(this.selfieCapture),
76
- );
77
- } else if (this.hideInstructions) {
78
- this.setActiveScreen(this.selfieCapture);
79
- } else {
80
- this.setActiveScreen(this.selfieInstruction);
81
- }
82
-
83
- this.setUpEventListeners();
84
- }
85
-
86
- getAgentMode() {
87
- return this.inAgentMode ? 'environment' : 'user';
88
- }
89
-
90
- disconnectedCallback() {
91
- SmartCamera.stopMedia();
92
- if (this.activeScreen) {
93
- this.activeScreen.removeAttribute('hidden');
94
- }
95
- this.activeScreen = null;
96
- this.innerHTML = '';
97
- }
98
-
99
- setUpEventListeners() {
100
- this.selfieInstruction.addEventListener(
101
- 'selfie-capture-instructions.capture',
102
- async () => {
103
- await getPermissions(this.selfieCapture, this.getAgentMode()).then(() =>
104
- this.setActiveScreen(this.selfieCapture),
105
- );
106
- smartCameraWeb?.dispatchEvent(
107
- new CustomEvent('metadata.selfie-capture-start'),
108
- );
109
- smartCameraWeb?.dispatchEvent(
110
- new CustomEvent('metadata.selfie-origin', {
111
- detail: {
112
- imageOrigin: {
113
- environment: 'back_camera',
114
- user: 'front_camera',
115
- }[this.getAgentMode()],
116
- },
117
- }),
118
- );
119
- },
120
- );
121
- this.selfieInstruction.addEventListener(
122
- 'selfie-capture-instructions.cancelled',
123
- () => {
124
- this.handleBackEvents();
125
- },
126
- );
127
-
128
- this.selfieCapture.addEventListener('selfie-capture.cancelled', () => {
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
- });
148
-
149
- this.selfieReview.addEventListener(
150
- 'selfie-capture-review.rejected',
151
- async () => {
152
- smartCameraWeb?.dispatchEvent(
153
- new CustomEvent('metadata.selfie-capture-retry'),
154
- );
155
- this.selfieReview.removeAttribute('data-image');
156
- this._data.images = [];
157
- if (this.hideInstructions) {
158
- this.setActiveScreen(this.selfieCapture);
159
- await getPermissions(this.selfieCapture, this.getAgentMode());
160
- } else {
161
- this.setActiveScreen(this.selfieInstruction);
162
- }
163
- },
164
- );
165
-
166
- this.selfieReview.addEventListener(
167
- 'selfie-capture-review.accepted',
168
- async () => {
169
- this._publishSelectedImages();
170
- },
171
- );
172
-
173
- [this.selfieInstruction, this.selfieCapture, this.selfieReview].forEach(
174
- (screen) => {
175
- screen.addEventListener(
176
- `${screen.nodeName.toLowerCase()}.close`,
177
- () => {
178
- this.handleCloseEvent();
179
- },
180
- );
181
- },
182
- );
183
- }
184
-
185
- _publishSelectedImages() {
186
- this.dispatchEvent(
187
- new CustomEvent('selfie-capture-screens.publish', { detail: this._data }),
188
- );
189
- }
190
-
191
- get hideInstructions() {
192
- return this.hasAttribute('hide-instructions');
193
- }
194
-
195
- get hideAttribution() {
196
- return this.hasAttribute('hide-attribution') ? 'hide-attribution' : '';
197
- }
198
-
199
- get hideBackOfId() {
200
- return this.hasAttribute('hide-back-of-id');
201
- }
202
-
203
- get showNavigation() {
204
- return this.hasAttribute('show-navigation') ? 'show-navigation' : '';
205
- }
206
-
207
- get inAgentMode() {
208
- return this.getAttribute('allow-agent-mode') === 'true';
209
- }
210
-
211
- get allowAgentMode() {
212
- return this.inAgentMode ? "allow-agent-mode='true'" : '';
213
- }
214
-
215
- get allowAgentModeTests() {
216
- return this.hasAttribute('show-agent-mode-for-tests')
217
- ? 'show-agent-mode-for-tests'
218
- : '';
219
- }
220
-
221
- get hideBack() {
222
- return this.hasAttribute('hide-back-to-host') ||
223
- this.hasAttribute('hide-back')
224
- ? 'hide-back'
225
- : '';
226
- }
227
-
228
- get disableImageTests() {
229
- return this.hasAttribute('disable-image-tests')
230
- ? 'disable-image-tests'
231
- : '';
232
- }
233
-
234
- get themeColor() {
235
- return this.getAttribute('theme-color') || '#001096';
236
- }
237
-
238
- setActiveScreen(screen) {
239
- this.activeScreen?.setAttribute('hidden', '');
240
- screen.removeAttribute('hidden');
241
- this.activeScreen = screen;
242
- }
243
-
244
- handleBackEvents() {
245
- this.dispatchEvent(new CustomEvent('selfie-capture-screens.cancelled'));
246
- }
247
-
248
- handleCloseEvent() {
249
- this.dispatchEvent(new CustomEvent('selfie-capture-screens.close'));
250
- }
251
-
252
- static get observedAttributes() {
253
- return [
254
- 'title',
255
- 'hidden',
256
- 'show-navigation',
257
- 'hide-back-to-host',
258
- 'initial-screen',
259
- ];
260
- }
261
-
262
- attributeChangedCallback(name) {
263
- switch (name) {
264
- case 'title':
265
- case 'hidden':
266
- case 'initial-screen':
267
- this.connectedCallback();
268
- break;
269
- default:
270
- break;
271
- }
272
- }
273
- }
274
-
275
- if (
276
- 'customElements' in window &&
277
- !customElements.get('selfie-capture-screens')
278
- ) {
279
- customElements.define('selfie-capture-screens', SelfieCaptureScreens);
280
- }
281
-
282
- export default SelfieCaptureScreens;
1
+ import './selfie-capture-instructions';
2
+ import './selfie-capture-review';
3
+ import './selfie-capture-wrapper/index.ts';
4
+ import SmartCamera from '../../../domain/camera/src/SmartCamera';
5
+ import styles from '../../../styles/src/styles';
6
+ import packageJson from '../../../../package.json';
7
+
8
+ const COMPONENTS_VERSION = packageJson.version;
9
+
10
+ const smartCameraWeb = document.querySelector('smart-camera-web');
11
+
12
+ async function getPermissions(captureScreen, facingMode = 'user') {
13
+ try {
14
+ const stream = await SmartCamera.getMedia({
15
+ audio: false,
16
+ video: { facingMode },
17
+ });
18
+ const devices = await navigator.mediaDevices.enumerateDevices();
19
+ const videoDevice = devices.find(
20
+ (device) =>
21
+ device.kind === 'videoinput' &&
22
+ stream.getVideoTracks()[0].getSettings().deviceId === device.deviceId,
23
+ );
24
+ smartCameraWeb?.dispatchEvent(
25
+ new CustomEvent('metadata.camera-name', {
26
+ detail: { cameraName: videoDevice?.label },
27
+ }),
28
+ );
29
+ captureScreen.removeAttribute('data-camera-error');
30
+ captureScreen.setAttribute('data-camera-ready', true);
31
+ } catch (error) {
32
+ captureScreen.removeAttribute('data-camera-ready');
33
+ captureScreen.setAttribute(
34
+ 'data-camera-error',
35
+ SmartCamera.handleCameraError(error),
36
+ );
37
+ }
38
+ }
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
+
105
+ class SelfieCaptureScreens extends HTMLElement {
106
+ constructor() {
107
+ super();
108
+ this.activeScreen = null;
109
+ this._remountKey = 0; // Counter for forcing wrapper remounts
110
+ smartCameraWeb?.dispatchEvent(new CustomEvent('metadata.initialize'));
111
+ }
112
+
113
+ connectedCallback() {
114
+ this.innerHTML = `
115
+ ${styles(this.themeColor)}
116
+ <div>
117
+ <selfie-capture-instructions theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} ${this.hideBack} hidden></selfie-capture-instructions>
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>
119
+ <selfie-capture-review theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
120
+ </div>
121
+ `;
122
+
123
+ this._data = {
124
+ images: [],
125
+ meta: {
126
+ libraryVersion: COMPONENTS_VERSION,
127
+ },
128
+ };
129
+ this.selfieInstruction = this.querySelector('selfie-capture-instructions');
130
+ this.selfieCapture = this.querySelector('selfie-capture-wrapper');
131
+ this.selfieReview = this.querySelector('selfie-capture-review');
132
+
133
+ if (this.hideInstructions && !this.hasAttribute('hidden')) {
134
+ getPermissions(this.selfieCapture, this.getAgentMode());
135
+ }
136
+
137
+ // If the initial screen is selfie-capture, we need to get permissions
138
+ if (this.getAttribute('initial-screen') === 'selfie-capture') {
139
+ getPermissions(this.selfieCapture, this.getAgentMode()).then(() =>
140
+ this.setActiveScreen(this.selfieCapture),
141
+ );
142
+ } else if (this.hideInstructions) {
143
+ this.setActiveScreen(this.selfieCapture);
144
+ } else {
145
+ this.setActiveScreen(this.selfieInstruction);
146
+ }
147
+
148
+ this.setUpEventListeners();
149
+ }
150
+
151
+ getAgentMode() {
152
+ return this.inAgentMode ? 'environment' : 'user';
153
+ }
154
+
155
+ disconnectedCallback() {
156
+ SmartCamera.stopMedia();
157
+ if (this.activeScreen) {
158
+ this.activeScreen.removeAttribute('hidden');
159
+ }
160
+ this.activeScreen = null;
161
+ this.innerHTML = '';
162
+ }
163
+
164
+ setUpEventListeners() {
165
+ this.selfieInstruction.addEventListener(
166
+ 'selfie-capture-instructions.capture',
167
+ async () => {
168
+ await getPermissions(this.selfieCapture, this.getAgentMode()).then(() =>
169
+ this.setActiveScreen(this.selfieCapture),
170
+ );
171
+ smartCameraWeb?.dispatchEvent(
172
+ new CustomEvent('metadata.selfie-capture-start'),
173
+ );
174
+ smartCameraWeb?.dispatchEvent(
175
+ new CustomEvent('metadata.selfie-origin', {
176
+ detail: {
177
+ imageOrigin: {
178
+ environment: 'back_camera',
179
+ user: 'front_camera',
180
+ }[this.getAgentMode()],
181
+ },
182
+ }),
183
+ );
184
+ },
185
+ );
186
+ this.selfieInstruction.addEventListener(
187
+ 'selfie-capture-instructions.cancelled',
188
+ () => {
189
+ this.handleBackEvents();
190
+ },
191
+ );
192
+ // Setup selfie-wrapper event listeners
193
+ this.setupSelfieWrapperEventListeners();
194
+
195
+ this.selfieReview.addEventListener(
196
+ 'selfie-capture-review.rejected',
197
+ async () => {
198
+ smartCameraWeb?.dispatchEvent(
199
+ new CustomEvent('metadata.selfie-capture-retry'),
200
+ );
201
+ this.selfieReview.removeAttribute('data-image');
202
+ this._data.images = [];
203
+
204
+ // Force remount by incrementing key
205
+ this.forceWrapperRemount();
206
+
207
+ if (this.hideInstructions) {
208
+ this.setActiveScreen(this.selfieCapture);
209
+ await getPermissions(this.selfieCapture, this.getAgentMode());
210
+ } else {
211
+ this.setActiveScreen(this.selfieInstruction);
212
+ }
213
+ },
214
+ );
215
+
216
+ this.selfieReview.addEventListener(
217
+ 'selfie-capture-review.accepted',
218
+ async () => {
219
+ this._publishSelectedImages();
220
+ },
221
+ );
222
+
223
+ [this.selfieInstruction, this.selfieCapture, this.selfieReview].forEach(
224
+ (screen) => {
225
+ screen.addEventListener(
226
+ `${screen.nodeName.toLowerCase()}.close`,
227
+ () => {
228
+ this.handleCloseEvent();
229
+ },
230
+ );
231
+ },
232
+ );
233
+ }
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
+
342
+ _publishSelectedImages() {
343
+ this.dispatchEvent(
344
+ new CustomEvent('selfie-capture-screens.publish', { detail: this._data }),
345
+ );
346
+ }
347
+
348
+ get hideInstructions() {
349
+ return this.hasAttribute('hide-instructions');
350
+ }
351
+
352
+ get hideAttribution() {
353
+ return this.hasAttribute('hide-attribution') ? 'hide-attribution=""' : '';
354
+ }
355
+
356
+ get hideBackOfId() {
357
+ return this.hasAttribute('hide-back-of-id');
358
+ }
359
+
360
+ get showNavigation() {
361
+ return this.hasAttribute('show-navigation') ? 'show-navigation=""' : '';
362
+ }
363
+
364
+ get inAgentMode() {
365
+ return this.getAttribute('allow-agent-mode') === 'true';
366
+ }
367
+
368
+ get allowAgentMode() {
369
+ return this.inAgentMode ? 'allow-agent-mode="true"' : '';
370
+ }
371
+
372
+ get allowAgentModeTests() {
373
+ return this.hasAttribute('show-agent-mode-for-tests')
374
+ ? 'show-agent-mode-for-tests=""'
375
+ : '';
376
+ }
377
+
378
+ get hideBack() {
379
+ return this.hasAttribute('hide-back-to-host') ||
380
+ this.hasAttribute('hide-back')
381
+ ? 'hide-back=""'
382
+ : '';
383
+ }
384
+
385
+ get disableImageTests() {
386
+ return this.hasAttribute('disable-image-tests')
387
+ ? 'disable-image-tests=""'
388
+ : '';
389
+ }
390
+
391
+ get themeColor() {
392
+ return this.getAttribute('theme-color') || '#001096';
393
+ }
394
+
395
+ handleBackEvents() {
396
+ this.dispatchEvent(new CustomEvent('selfie-capture-screens.cancelled'));
397
+ }
398
+
399
+ handleCloseEvent() {
400
+ this.dispatchEvent(new CustomEvent('selfie-capture-screens.close'));
401
+ }
402
+
403
+ static get observedAttributes() {
404
+ return [
405
+ 'title',
406
+ 'hidden',
407
+ 'show-navigation',
408
+ 'hide-back-to-host',
409
+ 'initial-screen',
410
+ ];
411
+ }
412
+
413
+ attributeChangedCallback(name) {
414
+ switch (name) {
415
+ case 'title':
416
+ case 'hidden':
417
+ case 'initial-screen':
418
+ this.connectedCallback();
419
+ break;
420
+ default:
421
+ break;
422
+ }
423
+ }
424
+ }
425
+
426
+ if (
427
+ 'customElements' in window &&
428
+ !customElements.get('selfie-capture-screens')
429
+ ) {
430
+ customElements.define('selfie-capture-screens', SelfieCaptureScreens);
431
+ }
432
+
433
+ export default SelfieCaptureScreens;