@smileid/web-components 2.0.2 → 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/selfie/src/SelfieCaptureScreens.js +188 -37
  47. package/{src → lib}/components/selfie/src/index.js +0 -2
  48. package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.js +3 -3
  49. package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +0 -7
  50. package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +227 -0
  51. package/lib/components/selfie/src/selfie-capture-wrapper/index.ts +1 -0
  52. package/lib/components/selfie/src/smartselfie-capture/OvalProgress.tsx +81 -0
  53. package/lib/components/selfie/src/smartselfie-capture/SmartSelfieCapture.tsx +224 -0
  54. package/lib/components/selfie/src/smartselfie-capture/components/AlertDisplay.tsx +34 -0
  55. package/lib/components/selfie/src/smartselfie-capture/components/CameraPreview.tsx +97 -0
  56. package/lib/components/selfie/src/smartselfie-capture/components/CaptureControls.tsx +74 -0
  57. package/lib/components/selfie/src/smartselfie-capture/components/index.ts +3 -0
  58. package/lib/components/selfie/src/smartselfie-capture/constants.ts +23 -0
  59. package/lib/components/selfie/src/smartselfie-capture/hooks/index.ts +2 -0
  60. package/lib/components/selfie/src/smartselfie-capture/hooks/useCamera.ts +94 -0
  61. package/lib/components/selfie/src/smartselfie-capture/hooks/useFaceCapture.ts +558 -0
  62. package/lib/components/selfie/src/smartselfie-capture/index.ts +1 -0
  63. package/lib/components/selfie/src/smartselfie-capture/utils/alertMessages.ts +12 -0
  64. package/lib/components/selfie/src/smartselfie-capture/utils/canvas.ts +105 -0
  65. package/lib/components/selfie/src/smartselfie-capture/utils/faceDetection.ts +129 -0
  66. package/lib/components/selfie/src/smartselfie-capture/utils/imageCapture.ts +64 -0
  67. package/lib/components/selfie/src/smartselfie-capture/utils/index.ts +4 -0
  68. package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +60 -0
  69. package/{src → lib}/components/signature-pad/package.json +1 -1
  70. package/{src → lib}/components/smart-camera-web/src/README.md +0 -1
  71. package/package.json +75 -24
  72. package/src/index.js +0 -5
  73. /package/{src → lib}/components/README.md +0 -0
  74. /package/{src → lib}/components/attribution/PoweredBySmileId.js +0 -0
  75. /package/{src → lib}/components/camera-permission/CameraPermission.js +0 -0
  76. /package/{src → lib}/components/camera-permission/CameraPermission.stories.js +0 -0
  77. /package/{src → lib}/components/combobox/src/Combobox.js +0 -0
  78. /package/{src → lib}/components/combobox/src/index.js +0 -0
  79. /package/{src → lib}/components/document/src/DocumentCaptureScreens.js +0 -0
  80. /package/{src → lib}/components/document/src/DocumentCaptureScreens.stories.js +0 -0
  81. /package/{src → lib}/components/document/src/README.md +0 -0
  82. /package/{src → lib}/components/document/src/document-capture/DocumentCapture.js +0 -0
  83. /package/{src → lib}/components/document/src/document-capture/DocumentCapture.stories.js +0 -0
  84. /package/{src → lib}/components/document/src/document-capture/README.md +0 -0
  85. /package/{src → lib}/components/document/src/document-capture/index.js +0 -0
  86. /package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +0 -0
  87. /package/{src → lib}/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +0 -0
  88. /package/{src → lib}/components/document/src/document-capture-instructions/README.md +0 -0
  89. /package/{src → lib}/components/document/src/document-capture-instructions/index.js +0 -0
  90. /package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.js +0 -0
  91. /package/{src → lib}/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +0 -0
  92. /package/{src → lib}/components/document/src/document-capture-review/README.md +0 -0
  93. /package/{src → lib}/components/document/src/document-capture-review/index.js +0 -0
  94. /package/{src → lib}/components/document/src/index.js +0 -0
  95. /package/{src → lib}/components/end-user-consent/src/EndUserConsent.js +0 -0
  96. /package/{src → lib}/components/end-user-consent/src/EndUserConsent.stories.js +0 -0
  97. /package/{src → lib}/components/end-user-consent/src/index.js +0 -0
  98. /package/{src → lib}/components/navigation/src/Navigation.js +0 -0
  99. /package/{src → lib}/components/navigation/src/Navigation.stories.js +0 -0
  100. /package/{src → lib}/components/navigation/src/index.js +0 -0
  101. /package/{src → lib}/components/selfie/README.md +0 -0
  102. /package/{src → lib}/components/selfie/src/SelfieCaptureScreens.stories.js +0 -0
  103. /package/{src → lib}/components/selfie/src/selfie-capture/SelfieCapture.stories.js +0 -0
  104. /package/{src → lib}/components/selfie/src/selfie-capture/index.js +0 -0
  105. /package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +0 -0
  106. /package/{src → lib}/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +0 -0
  107. /package/{src → lib}/components/selfie/src/selfie-capture-instructions/index.js +0 -0
  108. /package/{src → lib}/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +0 -0
  109. /package/{src → lib}/components/selfie/src/selfie-capture-review/index.js +0 -0
  110. /package/{src → lib}/components/signature-pad/package-lock.json +0 -0
  111. /package/{src → lib}/components/signature-pad/src/SignaturePad.js +0 -0
  112. /package/{src → lib}/components/signature-pad/src/SignaturePad.stories.js +0 -0
  113. /package/{src → lib}/components/signature-pad/src/index.js +0 -0
  114. /package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.js +0 -0
  115. /package/{src → lib}/components/smart-camera-web/src/SmartCameraWeb.stories.js +0 -0
  116. /package/{src → lib}/components/totp-consent/src/TotpConsent.js +0 -0
  117. /package/{src → lib}/components/totp-consent/src/index.js +0 -0
  118. /package/{src → lib}/domain/camera/src/README.md +0 -0
  119. /package/{src → lib}/domain/camera/src/SmartCamera.js +0 -0
  120. /package/{src → lib}/domain/constants/src/Constants.js +0 -0
  121. /package/{src → lib}/domain/file-upload/README.md +0 -0
  122. /package/{src → lib}/domain/file-upload/src/SmartFileUpload.js +0 -0
  123. /package/{src → lib}/styles/README.md +0 -0
  124. /package/{src → lib}/styles/src/styles.js +0 -0
  125. /package/{src → lib}/styles/src/typography.js +0 -0
@@ -0,0 +1,224 @@
1
+ import { useRef, useEffect } from 'preact/hooks';
2
+ import register from 'preact-custom-element';
3
+ import type { FunctionComponent } from 'preact';
4
+
5
+ import { getBoolProp } from '../../../../utils/props';
6
+ import { useFaceCapture, useCamera } from './hooks';
7
+ import { CameraPreview } from './components/CameraPreview';
8
+ import { AlertDisplay } from './components/AlertDisplay';
9
+ import { CaptureControls } from './components/CaptureControls';
10
+
11
+ import '../../../navigation/src';
12
+ import '../../../attribution/PoweredBySmileId';
13
+
14
+ interface Props {
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
+ }
24
+
25
+ const SmartSelfieCapture: FunctionComponent<Props> = ({
26
+ interval = 350,
27
+ duration = 2800,
28
+ 'theme-color': themeColor = '#001096',
29
+ 'show-navigation': showNavigationProp = false,
30
+ 'allow-agent-mode': allowAgentModeProp = false,
31
+ 'show-agent-mode-for-tests': showAgentModeForTestsProp = false,
32
+ 'hide-attribution': hideAttributionProp = false,
33
+ }) => {
34
+ const canvasRef = useRef<HTMLCanvasElement>(null);
35
+ const navigationRef = useRef<HTMLElement | null>(null);
36
+
37
+ const showNavigation = getBoolProp(showNavigationProp);
38
+ const allowAgentMode = getBoolProp(allowAgentModeProp);
39
+ const showAgentModeForTests = getBoolProp(showAgentModeForTestsProp);
40
+ const hideAttribution = getBoolProp(hideAttributionProp);
41
+
42
+ const smileCooldown = 300;
43
+ const smileThreshold = 0.25;
44
+ const mouthOpenThreshold = 0.05;
45
+ const minFaceSize = 0.35;
46
+ const maxFaceSize = 0.5;
47
+
48
+ const camera = useCamera();
49
+
50
+ const faceCapture = useFaceCapture({
51
+ videoRef: camera.videoRef,
52
+ canvasRef,
53
+ interval,
54
+ duration,
55
+ smileThreshold,
56
+ mouthOpenThreshold,
57
+ minFaceSize,
58
+ maxFaceSize,
59
+ smileCooldown,
60
+ });
61
+
62
+ useEffect(() => {
63
+ const initializeCamera = async () => {
64
+ await camera.startCamera();
65
+ await camera.checkAgentSupport();
66
+ await faceCapture.initializeFaceLandmarker();
67
+
68
+ setTimeout(() => {
69
+ faceCapture.setupCanvas();
70
+ faceCapture.startDetectionLoop();
71
+ }, 500);
72
+ };
73
+
74
+ initializeCamera();
75
+
76
+ return () => {
77
+ faceCapture.stopDetectionLoop();
78
+ camera.stopCamera();
79
+ faceCapture.cleanup();
80
+ };
81
+ }, []);
82
+
83
+ useEffect(() => {
84
+ const navigation = navigationRef.current;
85
+
86
+ if (navigation && showNavigation) {
87
+ const handleNavigationBack = () => {
88
+ faceCapture.handleCancel();
89
+ };
90
+
91
+ const handleNavigationClose = () => {
92
+ faceCapture.handleClose();
93
+ };
94
+
95
+ navigation.addEventListener('navigation.back', handleNavigationBack);
96
+ navigation.addEventListener('navigation.close', handleNavigationClose);
97
+
98
+ return () => {
99
+ navigation.removeEventListener('navigation.back', handleNavigationBack);
100
+ navigation.removeEventListener(
101
+ 'navigation.close',
102
+ handleNavigationClose,
103
+ );
104
+ };
105
+ }
106
+ return undefined;
107
+ }, [showNavigation]);
108
+
109
+ return (
110
+ <div className="smartselfie-capture">
111
+ {showNavigation && (
112
+ // @ts-ignore
113
+ <smileid-navigation ref={navigationRef} theme-color={themeColor} />
114
+ )}
115
+
116
+ <CameraPreview
117
+ videoRef={camera.videoRef}
118
+ canvasRef={canvasRef}
119
+ facingMode={camera.facingMode}
120
+ multipleFaces={faceCapture.multipleFaces.value}
121
+ progress={
122
+ faceCapture.capturesTaken.value > 0
123
+ ? faceCapture.capturesTaken.value / faceCapture.totalCaptures.value
124
+ : 0
125
+ }
126
+ interval={interval}
127
+ themeColor={themeColor}
128
+ />
129
+
130
+ <AlertDisplay alertTitle={faceCapture.alertTitle.value} />
131
+
132
+ {!faceCapture.isCapturing.value &&
133
+ !faceCapture.hasFinishedCapture.value && (
134
+ <CaptureControls
135
+ isCapturing={faceCapture.isCapturing.value}
136
+ hasFinishedCapture={faceCapture.hasFinishedCapture.value}
137
+ isReadyToCapture={faceCapture.isReadyToCapture.value}
138
+ allowAgentMode={allowAgentMode}
139
+ agentSupported={camera.agentSupported}
140
+ showAgentModeForTests={showAgentModeForTests}
141
+ facingMode={camera.facingMode}
142
+ themeColor={themeColor}
143
+ onStartCapture={faceCapture.startCapture}
144
+ onSwitchCamera={camera.switchCamera}
145
+ />
146
+ )}
147
+
148
+ {/* @ts-ignore */}
149
+ {!hideAttribution && <powered-by-smile-id />}
150
+
151
+ <style>{`
152
+ * {
153
+ box-sizing: border-box;
154
+ }
155
+
156
+ button {
157
+ padding: 10px 20px;
158
+ background: ${themeColor || '#001096'};
159
+ color: white;
160
+ border: none;
161
+ border-radius: 4px;
162
+ cursor: pointer;
163
+ font-size: 16px;
164
+ }
165
+
166
+ button:disabled {
167
+ background: #ccc;
168
+ cursor: not-allowed;
169
+ }
170
+
171
+ button.btn-primary {
172
+ background-color: ${themeColor || '#001096'};
173
+ border-radius: 2.5rem;
174
+ color: white;
175
+ border: none;
176
+ height: 3.125rem;
177
+ display: inline-block;
178
+ padding: 0.75rem 1.5rem;
179
+ text-align: center;
180
+ font-size: 1.125rem;
181
+ font-weight: 600;
182
+ font-family: "DM Sans", sans-serif;
183
+ cursor: pointer;
184
+ }
185
+
186
+ button.btn-primary:hover {
187
+ background-color: #2d2b2a;
188
+ }
189
+
190
+ button.btn-primary:disabled {
191
+ background-color: #666;
192
+ cursor: not-allowed;
193
+ }
194
+
195
+ .smartselfie-capture {
196
+ font-family: sans-serif;
197
+ max-width: 356px;
198
+ margin: 0 auto;
199
+ padding-block: 2rem;
200
+ }
201
+ `}</style>
202
+ </div>
203
+ );
204
+ };
205
+
206
+ if (!customElements.get('smartselfie-capture')) {
207
+ register(
208
+ SmartSelfieCapture,
209
+ 'smartselfie-capture',
210
+ [
211
+ 'interval',
212
+ 'duration',
213
+ 'theme-color',
214
+ 'show-navigation',
215
+ 'allow-agent-mode',
216
+ 'show-agent-mode-for-tests',
217
+ 'hide-attribution',
218
+ 'disable-image-tests',
219
+ ],
220
+ { shadow: true },
221
+ );
222
+ }
223
+
224
+ export default SmartSelfieCapture;
@@ -0,0 +1,34 @@
1
+ import type { FunctionComponent } from 'preact';
2
+
3
+ interface AlertDisplayProps {
4
+ alertTitle: string;
5
+ }
6
+
7
+ export const AlertDisplay: FunctionComponent<AlertDisplayProps> = ({
8
+ alertTitle,
9
+ }) =>
10
+ alertTitle ? (
11
+ <>
12
+ <div className="alert-message">
13
+ <div className="alert-title">{alertTitle}</div>
14
+ </div>
15
+
16
+ <style>{`
17
+ .alert-message {
18
+ margin-top: 1.5rem;
19
+ color: #000;
20
+ color: #151F72;
21
+ padding: 0.5rem 1.5rem;
22
+ border-radius: 4px;
23
+ text-align: start;
24
+ width: 100%;
25
+ }
26
+
27
+ .alert-title {
28
+ font-size: 16px;
29
+ font-weight: bold;
30
+ text-align: center;
31
+ }
32
+ `}</style>
33
+ </>
34
+ ) : null;
@@ -0,0 +1,97 @@
1
+ import type { FunctionComponent, Ref } from 'preact';
2
+ import OvalProgress from '../OvalProgress';
3
+
4
+ interface CameraPreviewProps {
5
+ videoRef: Ref<HTMLVideoElement>;
6
+ canvasRef: Ref<HTMLCanvasElement>;
7
+ facingMode: 'user' | 'environment';
8
+ multipleFaces: boolean;
9
+ progress: number;
10
+ interval: number;
11
+ themeColor: string;
12
+ }
13
+
14
+ export const CameraPreview: FunctionComponent<CameraPreviewProps> = ({
15
+ videoRef,
16
+ canvasRef,
17
+ facingMode,
18
+ multipleFaces,
19
+ progress,
20
+ interval,
21
+ themeColor,
22
+ }) => (
23
+ <>
24
+ <div className="camera-preview-container">
25
+ <div
26
+ className="video-wrapper"
27
+ style={{
28
+ clipPath: multipleFaces ? 'none' : 'url(#selfie-clip-path)',
29
+ }}
30
+ >
31
+ <div className="video-container">
32
+ <video
33
+ ref={videoRef}
34
+ autoPlay
35
+ playsInline
36
+ muted
37
+ className={`camera-video ${facingMode === 'user' ? 'mirror' : ''}`}
38
+ />
39
+ <canvas
40
+ ref={canvasRef}
41
+ className={`camera-canvas ${facingMode === 'user' ? 'mirror' : ''}`}
42
+ />
43
+ </div>
44
+ </div>
45
+ {!multipleFaces && (
46
+ <OvalProgress
47
+ progress={progress}
48
+ duration={interval}
49
+ themeColor={themeColor}
50
+ />
51
+ )}
52
+ </div>
53
+
54
+ <style>{`
55
+ .camera-preview-container {
56
+ position: relative;
57
+ width: 100%;
58
+ max-width: 300px;
59
+ margin: 0 auto;
60
+ }
61
+
62
+ .video-wrapper {
63
+ width: 100%;
64
+ max-width: 300px;
65
+ margin: 0 auto;
66
+ position: relative;
67
+ aspect-ratio: 3 / 4;
68
+ overflow: hidden;
69
+ }
70
+
71
+ .video-container {
72
+ position: absolute;
73
+ top: 0;
74
+ left: 0;
75
+ width: 100%;
76
+ height: 100%;
77
+ }
78
+
79
+ .camera-video,
80
+ .camera-canvas {
81
+ position: absolute;
82
+ top: 50%;
83
+ left: 50%;
84
+ transform: translate(-50%, -50%);
85
+ }
86
+
87
+ .camera-video.mirror,
88
+ .camera-canvas.mirror {
89
+ transform: translate(-50%, -50%) scaleX(-1);
90
+ }
91
+
92
+ .camera-canvas {
93
+ pointer-events: none;
94
+ }
95
+ `}</style>
96
+ </>
97
+ );
@@ -0,0 +1,74 @@
1
+ import type { FunctionComponent } from 'preact';
2
+
3
+ interface CaptureControlsProps {
4
+ isCapturing: boolean;
5
+ hasFinishedCapture: boolean;
6
+ isReadyToCapture: boolean;
7
+ allowAgentMode: boolean;
8
+ agentSupported: boolean;
9
+ showAgentModeForTests: boolean;
10
+ facingMode: 'user' | 'environment';
11
+ themeColor?: string;
12
+ onStartCapture: () => void;
13
+ onSwitchCamera: () => void;
14
+ }
15
+
16
+ export const CaptureControls: FunctionComponent<CaptureControlsProps> = ({
17
+ isCapturing,
18
+ hasFinishedCapture,
19
+ isReadyToCapture,
20
+ allowAgentMode,
21
+ agentSupported,
22
+ showAgentModeForTests,
23
+ facingMode,
24
+ themeColor = '#001096',
25
+ onStartCapture,
26
+ onSwitchCamera,
27
+ }) => (
28
+ <>
29
+ <div className="controls">
30
+ <button
31
+ class="btn-primary"
32
+ onClick={onStartCapture}
33
+ disabled={isCapturing || hasFinishedCapture || !isReadyToCapture}
34
+ >
35
+ Start Capture
36
+ </button>
37
+
38
+ {allowAgentMode && (agentSupported || showAgentModeForTests) && (
39
+ <button
40
+ onClick={onSwitchCamera}
41
+ className="agent-mode-btn"
42
+ disabled={isCapturing || hasFinishedCapture}
43
+ >
44
+ {facingMode === 'user' ? 'Agent Mode Off' : 'Agent Mode On'}
45
+ </button>
46
+ )}
47
+ </div>
48
+
49
+ <style>{`
50
+ .controls {
51
+ margin: 1.5rem 0;
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 1rem;
55
+ justify-content: center;
56
+ }
57
+
58
+ .agent-mode-btn {
59
+ padding: 8px 16px;
60
+ font-size: 14px;
61
+ background: ${themeColor};
62
+ color: white;
63
+ border: none;
64
+ border-radius: 4px;
65
+ cursor: pointer;
66
+ }
67
+
68
+ .agent-mode-btn:disabled {
69
+ background: #ccc;
70
+ cursor: not-allowed;
71
+ }
72
+ `}</style>
73
+ </>
74
+ );
@@ -0,0 +1,3 @@
1
+ export * from './CameraPreview';
2
+ export * from './AlertDisplay';
3
+ export * from './CaptureControls';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The type of image submitted in the job request
3
+ * @readonly
4
+ * @enum {number}
5
+ */
6
+ export const ImageType = {
7
+ /** ID_CARD_BACK_IMAGE_BASE64 Base64 encoded back of ID card image (.jpg or .png) */
8
+ ID_CARD_BACK_IMAGE_BASE64: 7,
9
+ /** ID_CARD_BACK_IMAGE_FILE Back of ID card image in .png or .jpg file format */
10
+ ID_CARD_BACK_IMAGE_FILE: 5,
11
+ /** ID_CARD_IMAGE_BASE64 Base64 encoded ID card image (.png or .jpg) */
12
+ ID_CARD_IMAGE_BASE64: 3,
13
+ /** ID_CARD_IMAGE_FILE ID card image in .png or .jpg file format */
14
+ ID_CARD_IMAGE_FILE: 1,
15
+ /** LIVENESS_IMAGE_BASE64 Base64 encoded liveness image (.jpg or .png) */
16
+ LIVENESS_IMAGE_BASE64: 6,
17
+ /** LIVENESS_IMAGE_FILE Liveness image in .png or .jpg file format */
18
+ LIVENESS_IMAGE_FILE: 4,
19
+ /** SELFIE_IMAGE_BASE64 Base64 encoded selfie image (.png or .jpg) */
20
+ SELFIE_IMAGE_BASE64: 2,
21
+ /** SELFIE_IMAGE_FILE Selfie image in .png or .jpg file format */
22
+ SELFIE_IMAGE_FILE: 0,
23
+ };
@@ -0,0 +1,2 @@
1
+ export * from './useCamera';
2
+ export * from './useFaceCapture';
@@ -0,0 +1,94 @@
1
+ import { useRef, useState } from 'preact/hooks';
2
+
3
+ export const useCamera = () => {
4
+ const videoRef = useRef<HTMLVideoElement>(null);
5
+ const streamRef = useRef<MediaStream | null>(null);
6
+ const [facingMode, setFacingMode] = useState<'user' | 'environment'>('user');
7
+ const [agentSupported, setAgentSupported] = useState(false);
8
+
9
+ const startCamera = async () => {
10
+ try {
11
+ if (streamRef.current) {
12
+ streamRef.current.getTracks().forEach((track) => track.stop());
13
+ streamRef.current = null;
14
+ }
15
+
16
+ if (videoRef.current) {
17
+ videoRef.current.srcObject = null;
18
+ }
19
+
20
+ const stream = await navigator.mediaDevices.getUserMedia({
21
+ video: { facingMode },
22
+ });
23
+ streamRef.current = stream;
24
+
25
+ const devices = await navigator.mediaDevices.enumerateDevices();
26
+ const videoDevice = devices.find(
27
+ (device) =>
28
+ device.kind === 'videoinput' &&
29
+ stream.getVideoTracks()[0].getSettings().deviceId === device.deviceId,
30
+ );
31
+
32
+ const smartCameraWeb = document.querySelector('smart-camera-web');
33
+ smartCameraWeb?.dispatchEvent(
34
+ new CustomEvent('metadata.camera-name', {
35
+ detail: { cameraName: videoDevice?.label },
36
+ }),
37
+ );
38
+
39
+ if (videoRef.current) {
40
+ videoRef.current.srcObject = stream;
41
+ await videoRef.current.play();
42
+ }
43
+ } catch (error) {
44
+ console.error('Failed to start camera:', error);
45
+ }
46
+ };
47
+
48
+ const switchCamera = async () => {
49
+ const newFacingMode = facingMode === 'user' ? 'environment' : 'user';
50
+ setFacingMode(newFacingMode);
51
+
52
+ if (streamRef.current) {
53
+ streamRef.current.getTracks().forEach((track) => track.stop());
54
+ streamRef.current = null;
55
+ }
56
+
57
+ await startCamera();
58
+ };
59
+
60
+ const checkAgentSupport = async () => {
61
+ try {
62
+ const devices = await navigator.mediaDevices.enumerateDevices();
63
+ const videoDevices = devices.filter(
64
+ (device) => device.kind === 'videoinput',
65
+ );
66
+ setAgentSupported(videoDevices.length > 1);
67
+ } catch (error) {
68
+ setAgentSupported(false);
69
+ }
70
+ };
71
+
72
+ const stopCamera = () => {
73
+ if (streamRef.current) {
74
+ streamRef.current.getTracks().forEach((track) => track.stop());
75
+ streamRef.current = null;
76
+ }
77
+
78
+ if (videoRef.current) {
79
+ videoRef.current.srcObject = null;
80
+ videoRef.current.load();
81
+ }
82
+ };
83
+
84
+ return {
85
+ videoRef,
86
+ streamRef,
87
+ facingMode,
88
+ agentSupported,
89
+ startCamera,
90
+ switchCamera,
91
+ checkAgentSupport,
92
+ stopCamera,
93
+ };
94
+ };