@smileid/web-components 11.4.4 → 11.5.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 (84) hide show
  1. package/dist/esm/{DocumentCaptureScreens-bLFW-yEM.js → DocumentCaptureScreens-ucJDu5nH.js} +555 -2470
  2. package/dist/esm/DocumentCaptureScreens-ucJDu5nH.js.map +1 -0
  3. package/dist/esm/{EndUserConsent-D26UoVk5.js → EndUserConsent-CsiwoThZ.js} +3 -3
  4. package/dist/esm/{EndUserConsent-D26UoVk5.js.map → EndUserConsent-CsiwoThZ.js.map} +1 -1
  5. package/dist/esm/{Navigation-nvehze1F.js → Navigation-Xg565kcu.js} +28 -22
  6. package/dist/esm/Navigation-Xg565kcu.js.map +1 -0
  7. package/dist/esm/SelfieCaptureScreens-D3KuMzZA.js +11471 -0
  8. package/dist/esm/SelfieCaptureScreens-D3KuMzZA.js.map +1 -0
  9. package/dist/esm/{TotpConsent-owUOdKzP.js → TotpConsent-CRtmtudl.js} +2 -2
  10. package/dist/esm/{TotpConsent-owUOdKzP.js.map → TotpConsent-CRtmtudl.js.map} +1 -1
  11. package/dist/esm/combobox.js +1 -1
  12. package/dist/esm/document.js +1 -1
  13. package/dist/esm/end-user-consent.js +1 -1
  14. package/dist/esm/index-CUwa6MPI.js +1363 -0
  15. package/dist/esm/{index-5Nn2kzHI.js.map → index-CUwa6MPI.js.map} +1 -1
  16. package/dist/esm/localisation.js +1 -1
  17. package/dist/esm/main.js +6 -6
  18. package/dist/esm/navigation.js +1 -1
  19. package/dist/esm/package-BmVbDNny.js +2535 -0
  20. package/dist/esm/package-BmVbDNny.js.map +1 -0
  21. package/dist/esm/selfie.js +1 -1
  22. package/dist/esm/smart-camera-web.js +67 -40
  23. package/dist/esm/smart-camera-web.js.map +1 -1
  24. package/dist/esm/totp-consent.js +1 -1
  25. package/dist/smart-camera-web.js +877 -122
  26. package/dist/smart-camera-web.js.map +1 -1
  27. package/dist/types/main.d.ts +13 -0
  28. package/lib/components/navigation/src/Navigation.js +27 -8
  29. package/lib/components/selfie/src/SelfieCaptureScreens.js +139 -8
  30. package/lib/components/selfie/src/enhanced-smartselfie-capture/EnhancedSmartSelfieCapture.tsx +684 -0
  31. package/lib/components/selfie/src/enhanced-smartselfie-capture/EnhancedSmartSelfieConsent.tsx +71 -0
  32. package/lib/components/selfie/src/enhanced-smartselfie-capture/EnhancedSmartSelfieSubmission.tsx +181 -0
  33. package/lib/components/selfie/src/enhanced-smartselfie-capture/OvalProgress.tsx +87 -0
  34. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/Icon.svg +8 -0
  35. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/accessories.svg +77 -0
  36. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/active_liveness_animation.lottie +0 -0
  37. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/device.svg +12 -0
  38. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/device_orientation.lottie +0 -0
  39. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/good.svg +52 -0
  40. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/id-card.svg +9 -0
  41. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/illustrations.tsx +852 -0
  42. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/instructions-img.svg +3 -0
  43. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/multiple-faces.svg +69 -0
  44. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/person.svg +6 -0
  45. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/phone.svg +8 -0
  46. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/poor-lighting.svg +53 -0
  47. package/lib/components/selfie/src/enhanced-smartselfie-capture/assets/too_dark_animation.lottie +0 -0
  48. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/ActiveLivenessOverlay.tsx +226 -0
  49. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/AlertDisplay.tsx +38 -0
  50. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/BackNavigation.tsx +45 -0
  51. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/CameraPreview.tsx +96 -0
  52. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/CaptureControls.tsx +97 -0
  53. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/CaptureGuidelines.tsx +374 -0
  54. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/ConsentView.tsx +460 -0
  55. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/SubmissionView.tsx +426 -0
  56. package/lib/components/selfie/src/enhanced-smartselfie-capture/components/index.ts +3 -0
  57. package/lib/components/selfie/src/enhanced-smartselfie-capture/constants.ts +23 -0
  58. package/lib/components/selfie/src/enhanced-smartselfie-capture/hooks/index.ts +2 -0
  59. package/lib/components/selfie/src/enhanced-smartselfie-capture/hooks/useCamera.ts +238 -0
  60. package/lib/components/selfie/src/enhanced-smartselfie-capture/hooks/useFaceCapture.ts +1075 -0
  61. package/lib/components/selfie/src/enhanced-smartselfie-capture/index.ts +1 -0
  62. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/alertMessages.ts +20 -0
  63. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/canvas.ts +108 -0
  64. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/faceDetection.ts +545 -0
  65. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/imageCapture.ts +66 -0
  66. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/imageQuality.ts +151 -0
  67. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/index.ts +5 -0
  68. package/lib/components/selfie/src/enhanced-smartselfie-capture/utils/mediapipeManager.ts +215 -0
  69. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +163 -17
  70. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +2 -2
  71. package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +15 -7
  72. package/lib/components/selfie/src/smartselfie-capture/utils/canvas.ts +4 -6
  73. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +145 -9
  74. package/lib/components/signature-pad/package.json +1 -1
  75. package/lib/components/smart-camera-web/src/SmartCameraWeb.js +70 -11
  76. package/lib/domain/localisation/index.js +2 -2
  77. package/package.json +3 -3
  78. package/dist/esm/DocumentCaptureScreens-bLFW-yEM.js.map +0 -1
  79. package/dist/esm/Navigation-nvehze1F.js.map +0 -1
  80. package/dist/esm/SelfieCaptureScreens-BXIs6_tl.js +0 -7522
  81. package/dist/esm/SelfieCaptureScreens-BXIs6_tl.js.map +0 -1
  82. package/dist/esm/index-5Nn2kzHI.js +0 -1360
  83. package/dist/esm/package-DmH-I6GW.js +0 -565
  84. package/dist/esm/package-DmH-I6GW.js.map +0 -1
@@ -194,6 +194,7 @@ export declare class Navigation extends HTMLElement {
194
194
  handleBack(): void;
195
195
  handleClose(): void;
196
196
  get showBackButton(): boolean;
197
+ get showCloseButton(): boolean;
197
198
  get themeColor(): string;
198
199
  get hasThemeColor(): string | undefined;
199
200
  }
@@ -242,8 +243,10 @@ export declare class SelfieCaptureScreens extends HTMLElement {
242
243
  }[] | null | undefined;
243
244
  setUpEventListeners(): void;
244
245
  forceWrapperRemount(): Promise<any>;
246
+ restartSelfieCapture(): void;
245
247
  setActiveScreen(screen: any): void;
246
248
  setupSelfieWrapperEventListeners(): void;
249
+ _selfieWrapperPublishHandler: ((event: any) => Promise<void>) | undefined;
247
250
  _publishSelectedImages(): void;
248
251
  get hideInstructions(): boolean;
249
252
  get hideAttribution(): "" | "hide-attribution=\"\"";
@@ -255,6 +258,10 @@ export declare class SelfieCaptureScreens extends HTMLElement {
255
258
  get hideBack(): "" | "hide-back=\"\"";
256
259
  get disableImageTests(): "" | "disable-image-tests=\"\"";
257
260
  get allowLegacySelfieFallback(): string;
261
+ get useStrictMode(): "" | "use-strict-mode=\"true\"";
262
+ get showBackOnGuidelines(): "" | "show-back-on-guidelines=\"true\"";
263
+ /** Boolean form of `use-strict-mode` for runtime checks. */
264
+ get isStrictMode(): boolean;
258
265
  get themeColor(): string;
259
266
  handleBackEvents(): void;
260
267
  handleCloseEvent(): void;
@@ -333,6 +340,7 @@ export declare class SmartCameraWeb extends HTMLElement {
333
340
  get hideBackOfId(): "" | "hide-back-of-id";
334
341
  get newInstructions(): "" | "new-instructions";
335
342
  get showNavigation(): "" | "show-navigation";
343
+ get showBackOnGuidelines(): "" | "show-back-on-guidelines";
336
344
  get hideBackToHost(): "" | "hide-back";
337
345
  get allowAgentMode(): string;
338
346
  get allowAgentModeTests(): "" | "show-agent-mode-for-tests";
@@ -340,7 +348,12 @@ export declare class SmartCameraWeb extends HTMLElement {
340
348
  get documentCaptureModes(): string;
341
349
  get disableImageTests(): "" | "disable-image-tests";
342
350
  get allowLegacySelfieFallback(): string;
351
+ get useStrictMode(): "" | "use-strict-mode=\"true\"";
343
352
  get hideAttribution(): "" | "hide-attribution";
353
+ get hideConsent(): "" | "hide-consent";
354
+ get partnerName(): string;
355
+ get partnerLogo(): string;
356
+ get policyUrl(): string;
344
357
  get hasThemeColor(): boolean;
345
358
  get themeColor(): string | null;
346
359
  get applyComponentThemeColor(): string;
@@ -12,12 +12,19 @@ class Navigation extends HTMLElement {
12
12
  const iconColor = this.hasThemeColor ? this.themeColor : '#FFFFFF';
13
13
  const focusColor = '#FFFFFF';
14
14
 
15
+ let justifyContent = 'flex-end';
16
+ if (this.showBackButton && this.showCloseButton) {
17
+ justifyContent = 'space-between';
18
+ } else if (this.showBackButton) {
19
+ justifyContent = 'flex-start';
20
+ }
21
+
15
22
  const style = document.createElement('style');
16
23
  style.textContent = `
17
24
  :host {
18
25
  display: flex;
19
26
  max-inline-size: 100%;
20
- justify-content: ${this.showBackButton ? 'space-between' : 'flex-end'};
27
+ justify-content: ${justifyContent};
21
28
  direction: ${direction};
22
29
  padding: var(--smileid-navigation-padding, ${hostPadding});
23
30
  gap: 1rem;
@@ -135,23 +142,31 @@ button svg {
135
142
 
136
143
  shadow.appendChild(style);
137
144
  if (this.showBackButton) shadow.appendChild(backButton);
138
- shadow.appendChild(closeButton);
145
+ if (this.showCloseButton) shadow.appendChild(closeButton);
139
146
 
140
147
  // Set language direction attribute on host for CSS selectors
141
148
  this.setAttribute('dir', direction);
142
149
 
143
150
  // Back Button Controls
144
- this.backButton = backButton;
145
- this.backButton.addEventListener('click', () => this.handleBack());
151
+ if (this.showBackButton) {
152
+ this.backButton = backButton;
153
+ this.backButton.addEventListener('click', () => this.handleBack());
154
+ }
146
155
 
147
156
  // Close Button Controls
148
- this.closeButton = closeButton;
149
- this.closeButton.addEventListener('click', () => this.handleClose());
157
+ if (this.showCloseButton) {
158
+ this.closeButton = closeButton;
159
+ this.closeButton.addEventListener('click', () => this.handleClose());
160
+ }
150
161
  }
151
162
 
152
163
  disconnectedCallback() {
153
- this.backButton.removeEventListener('click', () => this.handleBack());
154
- this.closeButton.removeEventListener('click', () => this.handleClose());
164
+ if (this.backButton) {
165
+ this.backButton.removeEventListener('click', () => this.handleBack());
166
+ }
167
+ if (this.closeButton) {
168
+ this.closeButton.removeEventListener('click', () => this.handleClose());
169
+ }
155
170
  }
156
171
 
157
172
  handleBack() {
@@ -166,6 +181,10 @@ button svg {
166
181
  return !this.hasAttribute('hide-back');
167
182
  }
168
183
 
184
+ get showCloseButton() {
185
+ return !this.hasAttribute('hide-close');
186
+ }
187
+
169
188
  get themeColor() {
170
189
  return this.getAttribute('theme-color') || '#001096';
171
190
  }
@@ -1,6 +1,7 @@
1
1
  import './selfie-capture-instructions';
2
2
  import './selfie-capture-review';
3
3
  import './selfie-capture-wrapper/index.ts';
4
+ import { getMediapipeInstance } from './smartselfie-capture/utils/mediapipeManager.ts';
4
5
  import SmartCamera from '../../../domain/camera/src/SmartCamera';
5
6
  import styles from '../../../styles/src/styles';
6
7
  import packageJson from '../../../../package.json';
@@ -10,6 +11,15 @@ const COMPONENTS_VERSION = packageJson.version;
10
11
 
11
12
  const smartCameraWeb = document.querySelector('smart-camera-web');
12
13
 
14
+ /**
15
+ * Minimum-correct HTML attribute escape. `&` must be replaced first so the
16
+ * subsequent `"` -> `&quot;` substitution isn't double-encoded. Used by every
17
+ * getter that interpolates a partner-supplied value into the `innerHTML`
18
+ * template in `connectedCallback` — without this, a value containing `"`
19
+ * (or `&`) would break out of the attribute and inject markup.
20
+ */
21
+ const escAttr = (s) => String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
22
+
13
23
  const cropImageFromDataUri = (dataUri, cropPercentX = 0, cropPercentY = 0) =>
14
24
  new Promise((resolve, reject) => {
15
25
  if (!dataUri || typeof dataUri !== 'string') {
@@ -82,9 +92,9 @@ class SelfieCaptureScreens extends HTMLElement {
82
92
  this.innerHTML = `
83
93
  ${styles(this.themeColor)}
84
94
  <div style="height: 100%;">
85
- <selfie-capture-instructions theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} ${this.hideBack} hidden></selfie-capture-instructions>
86
- <selfie-capture-wrapper theme-color='${this.themeColor}' ${this.showNavigation} ${this.allowAgentMode} ${this.allowAgentModeTests} ${this.hideAttribution} ${this.disableImageTests} ${this.allowLegacySelfieFallback} key="${this._remountKey}" start-countdown="false" hidden></selfie-capture-wrapper>
87
- <selfie-capture-review theme-color='${this.themeColor}' ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
95
+ <selfie-capture-instructions theme-color="${escAttr(this.themeColor)}" ${this.showNavigation} ${this.hideAttribution} ${this.hideBack} hidden></selfie-capture-instructions>
96
+ <selfie-capture-wrapper theme-color="${escAttr(this.themeColor)}" ${this.showNavigation} ${this.allowAgentMode} ${this.allowAgentModeTests} ${this.hideAttribution} ${this.disableImageTests} ${this.allowLegacySelfieFallback} ${this.useStrictMode} ${this.showBackOnGuidelines} key="${this._remountKey}" start-countdown="false" hidden></selfie-capture-wrapper>
97
+ <selfie-capture-review theme-color="${escAttr(this.themeColor)}" ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
88
98
  </div>
89
99
  `;
90
100
 
@@ -100,7 +110,11 @@ class SelfieCaptureScreens extends HTMLElement {
100
110
 
101
111
  if (
102
112
  this.getAttribute('initial-screen') === 'selfie-capture' ||
103
- this.hideInstructions
113
+ this.hideInstructions ||
114
+ // In strict mode the modern `enhanced-smartselfie-capture` element
115
+ // renders its own guidelines screen, so we skip the legacy
116
+ // `selfie-capture-instructions` element entirely.
117
+ this.isStrictMode
104
118
  ) {
105
119
  this.setActiveScreen(this.selfieCapture);
106
120
  } else {
@@ -108,6 +122,37 @@ class SelfieCaptureScreens extends HTMLElement {
108
122
  }
109
123
 
110
124
  this.setUpEventListeners();
125
+
126
+ // Pre-warm MediaPipe as soon as the selfie flow starts so the heavy WASM +
127
+ // model download (and on-device init) happens while the user reads the
128
+ // instructions — not behind a blocking spinner on the capture screen. This
129
+ // is fire-and-forget and idempotent: getMediapipeInstance() caches a single
130
+ // in-flight promise / instance, so the wrapper (and any remount) reuses the
131
+ // same load instead of starting a new one. Errors are handled by the
132
+ // wrapper's own retry/fallback path, so swallow them here.
133
+ //
134
+ // Skipped under Cypress to match `SelfieCaptureWrapper`'s existing test
135
+ // seam (`skipMediapipeForTests`). Specs rely on the wrapper short-circuiting
136
+ // to the legacy `selfie-capture` fallback; pre-warming here would race with
137
+ // that seam and (intermittently) flip the wrapper into the SmartSelfie path
138
+ // by populating `window.__smileIdentityMediapipe` before the wrapper mounts.
139
+ //
140
+ // The parent check covers the embed Cypress context where this element runs
141
+ // inside an iframe and window.Cypress is only set on the parent frame.
142
+ const isCypress =
143
+ !!window.Cypress ||
144
+ (() => {
145
+ try {
146
+ return !!window.parent.Cypress;
147
+ } catch {
148
+ return false;
149
+ }
150
+ })() ||
151
+ (window.navigator.userAgent.includes('Electron') && window.__Cypress);
152
+ const forceMediapipeLoad = !!window.__SMILE_ID_TEST_FORCE_MEDIAPIPE_LOAD__;
153
+ if (!isCypress || forceMediapipeLoad) {
154
+ getMediapipeInstance().catch(() => {});
155
+ }
111
156
  }
112
157
 
113
158
  getAgentMode() {
@@ -230,6 +275,45 @@ class SelfieCaptureScreens extends HTMLElement {
230
275
  });
231
276
  }
232
277
 
278
+ // Return to a clean selfie capture screen. Used when navigating back from the
279
+ // document flow. Previously this was driven by toggling the `initial-screen`
280
+ // attribute on this element, which re-fired a full `connectedCallback()`
281
+ // rebuild every time (even when the value was unchanged). We now swap in a
282
+ // fresh `selfie-capture-wrapper` synchronously and navigate explicitly, so we
283
+ // land on a clean capture screen — not the stale review — without rebuilding
284
+ // the whole screen tree or depending on timers.
285
+ restartSelfieCapture() {
286
+ SmartCamera.stopMedia();
287
+
288
+ const container = this.querySelector('div');
289
+ const oldWrapper = this.selfieCapture;
290
+
291
+ if (oldWrapper && container) {
292
+ this._remountKey++;
293
+
294
+ const newWrapper = document.createElement('selfie-capture-wrapper');
295
+ Array.from(oldWrapper.attributes).forEach((attr) => {
296
+ newWrapper.setAttribute(attr.name, attr.value);
297
+ });
298
+ newWrapper.setAttribute('key', this._remountKey.toString());
299
+ newWrapper.setAttribute('start-countdown', 'false');
300
+ newWrapper.setAttribute('hidden', '');
301
+
302
+ const reviewElement = container.querySelector('selfie-capture-review');
303
+ oldWrapper.remove();
304
+ if (reviewElement) {
305
+ container.insertBefore(newWrapper, reviewElement);
306
+ } else {
307
+ container.appendChild(newWrapper);
308
+ }
309
+
310
+ this.selfieCapture = newWrapper;
311
+ this.setupSelfieWrapperEventListeners();
312
+ }
313
+
314
+ this.setActiveScreen(this.selfieCapture);
315
+ }
316
+
233
317
  // Override setActiveScreen to enable countdown when selfie-capture is active
234
318
  setActiveScreen(screen) {
235
319
  if (this.activeScreen === screen) {
@@ -256,6 +340,17 @@ class SelfieCaptureScreens extends HTMLElement {
256
340
  window.removeEventListener(event, handler);
257
341
  });
258
342
  }
343
+ // Also remove the previously-attached element-level publish handler so we
344
+ // don't accumulate duplicates across remounts (each call to
345
+ // setupSelfieWrapperEventListeners would otherwise add another listener,
346
+ // causing multiple transitions to review / multiple metadata events on
347
+ // navigating back from document capture).
348
+ if (this._selfieWrapperPublishHandler) {
349
+ this.removeEventListener(
350
+ 'selfie-capture.publish',
351
+ this._selfieWrapperPublishHandler,
352
+ );
353
+ }
259
354
 
260
355
  // Create new event handlers
261
356
  const cancelledHandler = async () => {
@@ -264,7 +359,7 @@ class SelfieCaptureScreens extends HTMLElement {
264
359
  // Force remount of selfie-capture-wrapper for clean state on next visit
265
360
  await this.forceWrapperRemount();
266
361
 
267
- if (this.hideInstructions) {
362
+ if (this.hideInstructions || this.isStrictMode) {
268
363
  this.handleBackEvents();
269
364
  return;
270
365
  }
@@ -285,6 +380,18 @@ class SelfieCaptureScreens extends HTMLElement {
285
380
  smartCameraWeb?.dispatchEvent(
286
381
  new CustomEvent('metadata.selfie-capture-end'),
287
382
  );
383
+ this._data.images = event.detail.images;
384
+ SmartCamera.stopMedia();
385
+
386
+ // In strict mode (Enhanced SmartSelfie), the ESS component already
387
+ // shows its own review screen and only re-dispatches `publish` after
388
+ // the user confirms. Skip the legacy `selfie-capture-review` step and
389
+ // publish straight up to the host page.
390
+ if (this.isStrictMode) {
391
+ this._publishSelectedImages();
392
+ return;
393
+ }
394
+
288
395
  this.selfieReview.setAttribute(
289
396
  'data-image',
290
397
  await cropImageFromDataUri(event.detail.referenceImage, 20, 20),
@@ -294,8 +401,6 @@ class SelfieCaptureScreens extends HTMLElement {
294
401
  'mirror-image',
295
402
  shouldMirror ? 'true' : 'false',
296
403
  );
297
- this._data.images = event.detail.images;
298
- SmartCamera.stopMedia();
299
404
  this.setActiveScreen(this.selfieReview);
300
405
  };
301
406
 
@@ -313,6 +418,7 @@ class SelfieCaptureScreens extends HTMLElement {
313
418
 
314
419
  // Also listen for the publish event on the parent SelfieCaptureScreens element
315
420
  // in case smartselfie-capture dispatches it there
421
+ this._selfieWrapperPublishHandler = publishHandler;
316
422
  this.addEventListener('selfie-capture.publish', publishHandler);
317
423
  }
318
424
 
@@ -367,10 +473,31 @@ class SelfieCaptureScreens extends HTMLElement {
367
473
 
368
474
  get allowLegacySelfieFallback() {
369
475
  return this.hasAttribute('allow-legacy-selfie-fallback')
370
- ? `allow-legacy-selfie-fallback='${this.getAttribute('allow-legacy-selfie-fallback')}'`
476
+ ? `allow-legacy-selfie-fallback="${escAttr(this.getAttribute('allow-legacy-selfie-fallback'))}"`
477
+ : '';
478
+ }
479
+
480
+ get useStrictMode() {
481
+ return this.hasAttribute('use-strict-mode') &&
482
+ this.getAttribute('use-strict-mode') !== 'false'
483
+ ? 'use-strict-mode="true"'
371
484
  : '';
372
485
  }
373
486
 
487
+ get showBackOnGuidelines() {
488
+ return this.hasAttribute('show-back-on-guidelines')
489
+ ? 'show-back-on-guidelines="true"'
490
+ : '';
491
+ }
492
+
493
+ /** Boolean form of `use-strict-mode` for runtime checks. */
494
+ get isStrictMode() {
495
+ return (
496
+ this.hasAttribute('use-strict-mode') &&
497
+ this.getAttribute('use-strict-mode') !== 'false'
498
+ );
499
+ }
500
+
374
501
  get themeColor() {
375
502
  return this.getAttribute('theme-color') || '#001096';
376
503
  }
@@ -394,6 +521,8 @@ class SelfieCaptureScreens extends HTMLElement {
394
521
  'allow-legacy-selfie-fallback',
395
522
  'show-agent-mode-for-tests',
396
523
  'disable-image-tests',
524
+ 'use-strict-mode',
525
+ 'show-back-on-guidelines',
397
526
  ];
398
527
  }
399
528
 
@@ -406,6 +535,8 @@ class SelfieCaptureScreens extends HTMLElement {
406
535
  case 'allow-legacy-selfie-fallback':
407
536
  case 'show-agent-mode-for-tests':
408
537
  case 'disable-image-tests':
538
+ case 'use-strict-mode':
539
+ case 'show-back-on-guidelines':
409
540
  this.connectedCallback();
410
541
  break;
411
542
  default: