@smileid/web-components 1.0.0-beta
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/.eslintrc.cjs +72 -0
- package/components/README.md +14 -0
- package/components/attribution/PoweredBySmileId.js +42 -0
- package/components/camera-permission/CameraPermission.js +136 -0
- package/components/camera-permission/CameraPermission.stories.js +21 -0
- package/components/combobox/src/Combobox.js +586 -0
- package/components/combobox/src/index.js +1 -0
- package/components/document/src/DocumentCaptureScreens.js +317 -0
- package/components/document/src/DocumentCaptureScreens.stories.js +51 -0
- package/components/document/src/README.md +108 -0
- package/components/document/src/document-capture/DocumentCapture.js +677 -0
- package/components/document/src/document-capture/DocumentCapture.stories.js +71 -0
- package/components/document/src/document-capture/README.md +89 -0
- package/components/document/src/document-capture/index.js +3 -0
- package/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +499 -0
- package/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +17 -0
- package/components/document/src/document-capture-instructions/README.md +56 -0
- package/components/document/src/document-capture-instructions/index.js +3 -0
- package/components/document/src/document-capture-review/DocumentCaptureReview.js +378 -0
- package/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +14 -0
- package/components/document/src/document-capture-review/README.md +79 -0
- package/components/document/src/document-capture-review/index.js +3 -0
- package/components/document/src/index.js +3 -0
- package/components/end-user-consent/src/EndUserConsent.js +809 -0
- package/components/end-user-consent/src/EndUserConsent.stories.js +23 -0
- package/components/end-user-consent/src/index.js +4 -0
- package/components/navigation/src/Navigation.js +160 -0
- package/components/navigation/src/Navigation.stories.js +24 -0
- package/components/navigation/src/index.js +3 -0
- package/components/selfie/README.md +201 -0
- package/components/selfie/src/SelfieCaptureScreens.js +224 -0
- package/components/selfie/src/SelfieCaptureScreens.stories.js +21 -0
- package/components/selfie/src/index.js +5 -0
- package/components/selfie/src/selfie-capture/SelfieCapture.js +878 -0
- package/components/selfie/src/selfie-capture/SelfieCapture.stories.js +23 -0
- package/components/selfie/src/selfie-capture/index.js +3 -0
- package/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +638 -0
- package/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +17 -0
- package/components/selfie/src/selfie-capture-instructions/index.js +3 -0
- package/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +348 -0
- package/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +17 -0
- package/components/selfie/src/selfie-capture-review/index.js +3 -0
- package/components/signature-pad/package.json +30 -0
- package/components/signature-pad/src/SignaturePad.js +477 -0
- package/components/signature-pad/src/SignaturePad.stories.js +24 -0
- package/components/signature-pad/src/index.js +3 -0
- package/components/smart-camera-web/src/SmartCameraWeb.js +246 -0
- package/components/smart-camera-web/src/SmartCameraWeb.stories.js +35 -0
- package/components/totp-consent/src/TotpConsent.js +935 -0
- package/components/totp-consent/src/index.js +4 -0
- package/cypress/e2e/smart-camera-web-attribution.cy.js +21 -0
- package/cypress/e2e/smart-camera-web-back-press.cy.js +481 -0
- package/cypress/e2e/smart-camera-web-hide-instructions.cy.js +334 -0
- package/cypress/e2e/smart-camera-web.cy.js +309 -0
- package/cypress/fixtures/example.json +5 -0
- package/cypress/pages/capture-back-of-id-hide-attribution.html +44 -0
- package/cypress/pages/capture-back-of-id-navigation.html +72 -0
- package/cypress/pages/smart-camera-web-hide-instructions.html +38 -0
- package/cypress/pages/smart-camera-web.html +38 -0
- package/cypress/support/commands.js +144 -0
- package/cypress/support/e2e.js +20 -0
- package/cypress.config.js +11 -0
- package/domain/camera/src/README.md +38 -0
- package/domain/camera/src/SmartCamera.js +81 -0
- package/domain/constants/src/Constants.js +27 -0
- package/domain/file-upload/README.md +35 -0
- package/domain/file-upload/src/SmartFileUpload.js +65 -0
- package/esbuild.js +119 -0
- package/index.js +5 -0
- package/package.json +46 -0
- package/styles/README.md +3 -0
- package/styles/src/styles.js +348 -0
- package/styles/src/typography.js +52 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import './EndUserConsent';
|
|
2
|
+
|
|
3
|
+
const meta = {
|
|
4
|
+
component: 'end-user-consent',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export default meta;
|
|
8
|
+
|
|
9
|
+
export const EndUserConsent = {
|
|
10
|
+
render: () => `
|
|
11
|
+
<end-user-consent
|
|
12
|
+
country="NG"
|
|
13
|
+
id-type="NATIONAL_ID"
|
|
14
|
+
id-type-label="National ID"
|
|
15
|
+
partner-id="007"
|
|
16
|
+
partner-name="SmileID Stories"
|
|
17
|
+
policy-url="https://usesmileid.com/privacy-policy"
|
|
18
|
+
theme-color="#001096"
|
|
19
|
+
partner-logo="https://portal.usesmileid.com/favicon.ico"
|
|
20
|
+
>
|
|
21
|
+
</end-user-consent>
|
|
22
|
+
`,
|
|
23
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
class Navigation extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
const shadow = this.attachShadow({ mode: 'open' });
|
|
4
|
+
|
|
5
|
+
const style = document.createElement('style');
|
|
6
|
+
style.textContent = `
|
|
7
|
+
:host {
|
|
8
|
+
display: flex;
|
|
9
|
+
max-inline-size: 100%;
|
|
10
|
+
justify-content: ${this.showBackButton ? 'space-between' : 'flex-end'};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
button {
|
|
14
|
+
--button-color: var(--color-default);
|
|
15
|
+
--flow-space: 3rem;
|
|
16
|
+
-webkit-appearance: none;
|
|
17
|
+
-moz-appearance: none;
|
|
18
|
+
align-items: center;
|
|
19
|
+
appearance: none;
|
|
20
|
+
background-color: transparent;
|
|
21
|
+
border-radius: 2.5rem;
|
|
22
|
+
border: none;
|
|
23
|
+
color: #ffffff;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
font-size: 20px;
|
|
27
|
+
font-weight: 500;
|
|
28
|
+
inline-size: 100%;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
letter-spacing: 0.05ch;
|
|
31
|
+
line-height: 1;
|
|
32
|
+
padding: 1rem 2.5rem;
|
|
33
|
+
text-align: center;
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
button[data-type="icon"] {
|
|
38
|
+
align-items: center;
|
|
39
|
+
background-color: transparent;
|
|
40
|
+
border: 0;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
display: flex;
|
|
43
|
+
padding: 0;
|
|
44
|
+
width: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:host::part(back-button) {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:host::part(back-button-text) {
|
|
53
|
+
line-height: 1;
|
|
54
|
+
color: rgb(21, 31, 114) !important;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:host::part(close-button) {
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.visually-hidden {
|
|
61
|
+
clip: rect(0 0 0 0);
|
|
62
|
+
clip-path: inset(50%);
|
|
63
|
+
block-size: 1px;
|
|
64
|
+
overflow: hidden;
|
|
65
|
+
position: absolute;
|
|
66
|
+
white-space: nowrap;
|
|
67
|
+
inline-size: 1px;
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
const backButton = document.createElement('button');
|
|
72
|
+
backButton.setAttribute('class', 'back-button');
|
|
73
|
+
backButton.setAttribute('data-type', 'icon');
|
|
74
|
+
backButton.setAttribute('part', 'back-button');
|
|
75
|
+
backButton.setAttribute('type', 'button');
|
|
76
|
+
backButton.innerHTML = `
|
|
77
|
+
<svg
|
|
78
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
79
|
+
width="40"
|
|
80
|
+
height="40"
|
|
81
|
+
viewBox="0 0 24 24"
|
|
82
|
+
fill="none"
|
|
83
|
+
>
|
|
84
|
+
<path
|
|
85
|
+
fill="#DBDBC4"
|
|
86
|
+
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Z"
|
|
87
|
+
opacity=".4"
|
|
88
|
+
/>
|
|
89
|
+
<path
|
|
90
|
+
fill="#001096"
|
|
91
|
+
d="M15.5 11.25h-5.19l1.72-1.72c.29-.29.29-.77 0-1.06a.754.754 0 0 0-1.06 0l-3 3c-.29.29-.29.77 0 1.06l3 3c.15.15.34.22.53.22s.38-.07.53-.22c.29-.29.29-.77 0-1.06l-1.72-1.72h5.19c.41 0 .75-.34.75-.75s-.34-.75-.75-.75Z"
|
|
92
|
+
/>
|
|
93
|
+
</svg>
|
|
94
|
+
<span part="back-button-text">Back</span>
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
const closeButton = document.createElement('button');
|
|
98
|
+
closeButton.setAttribute('class', 'close-button');
|
|
99
|
+
closeButton.setAttribute('data-type', 'icon');
|
|
100
|
+
closeButton.setAttribute('part', 'close-button');
|
|
101
|
+
closeButton.setAttribute('type', 'button');
|
|
102
|
+
closeButton.innerHTML = `
|
|
103
|
+
<svg
|
|
104
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
105
|
+
viewBox="0 0 24 24"
|
|
106
|
+
width="40"
|
|
107
|
+
height="40"
|
|
108
|
+
fill="none"
|
|
109
|
+
>
|
|
110
|
+
<path
|
|
111
|
+
fill="#DBDBC4"
|
|
112
|
+
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Z"
|
|
113
|
+
opacity=".4"
|
|
114
|
+
/>
|
|
115
|
+
<path
|
|
116
|
+
fill="#91190F"
|
|
117
|
+
d="m13.06 12 2.3-2.3c.29-.29.29-.77 0-1.06a.754.754 0 0 0-1.06 0l-2.3 2.3-2.3-2.3a.754.754 0 0 0-1.06 0c-.29.29-.29.77 0 1.06l2.3 2.3-2.3 2.3c-.29.29-.29.77 0 1.06.15.15.34.22.53.22s.38-.07.53-.22l2.3-2.3 2.3 2.3c.15.15.34.22.53.22s.38-.07.53-.22c.29-.29.29-.77 0-1.06l-2.3-2.3Z"
|
|
118
|
+
/>
|
|
119
|
+
</svg>
|
|
120
|
+
<span class="visually-hidden"
|
|
121
|
+
>Close SmileIdentity Verification frame</span
|
|
122
|
+
>
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
shadow.appendChild(style);
|
|
126
|
+
if (this.showBackButton) shadow.appendChild(backButton);
|
|
127
|
+
shadow.appendChild(closeButton);
|
|
128
|
+
|
|
129
|
+
// Back Button Controls
|
|
130
|
+
this.backButton = backButton;
|
|
131
|
+
this.backButton.addEventListener('click', () => this.handleBack());
|
|
132
|
+
|
|
133
|
+
// Close Button Controls
|
|
134
|
+
this.closeButton = closeButton;
|
|
135
|
+
this.closeButton.addEventListener('click', () => this.handleClose());
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
disconnectedCallback() {
|
|
139
|
+
this.backButton.removeEventListener('click', () => this.handleBack());
|
|
140
|
+
this.closeButton.removeEventListener('click', () => this.handleClose());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
handleBack() {
|
|
144
|
+
this.dispatchEvent(new CustomEvent('navigation.back'));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
handleClose() {
|
|
148
|
+
this.dispatchEvent(new CustomEvent('navigation.close'));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get showBackButton() {
|
|
152
|
+
return !this.hasAttribute('hide-back');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if ('customElements' in window) {
|
|
157
|
+
window.customElements.define('smileid-navigation', Navigation);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default Navigation;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './Navigation';
|
|
2
|
+
|
|
3
|
+
const meta = {
|
|
4
|
+
component: 'smileid-navigation',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export default meta;
|
|
8
|
+
|
|
9
|
+
export const Navigation = {
|
|
10
|
+
render: () => `
|
|
11
|
+
<smileid-navigation
|
|
12
|
+
>
|
|
13
|
+
</smileid-navigation>
|
|
14
|
+
`,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const NavigationWithBackHidden = {
|
|
18
|
+
render: () => `
|
|
19
|
+
<smileid-navigation
|
|
20
|
+
hide-back
|
|
21
|
+
>
|
|
22
|
+
</smileid-navigation>
|
|
23
|
+
`,
|
|
24
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# SelfieCaptureScreens Web Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `SelfieCaptureScreens` is a custom web component designed to capture selfies and liveness images using a camera. It uses the `SmartCamera` module to interact with the device's camera and handle permissions.
|
|
6
|
+
|
|
7
|
+
### Importing the Component
|
|
8
|
+
|
|
9
|
+
To use the SelfieCaptureScreens component, you need to import it into your JavaScript file:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import '@smileid/web-components/selfie-capture-screens';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Using the Component
|
|
16
|
+
|
|
17
|
+
You can use the SelfieCaptureScreens component in your HTML like any other HTML element:
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<selfie-capture-screens></selfie-capture-screens>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### SelfieCaptureScreens Web Component Attributes
|
|
24
|
+
|
|
25
|
+
You can use a mixture of the following attributes to configure the behavior of the component.
|
|
26
|
+
|
|
27
|
+
#### hide-instructions
|
|
28
|
+
|
|
29
|
+
This attribute, when present, hides the instructions for the liveness capture process. It does not require a value.
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<selfie-capture-screens hide-instructions></selfie-capture-screens>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### show-navigation
|
|
38
|
+
|
|
39
|
+
This attribute, when present, shows the navigation controls for the liveness capture process. It does not require a value.
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<selfie-capture-screens show-navigation></selfie-capture-screens>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Permissions
|
|
48
|
+
|
|
49
|
+
The `SelfieCaptureScreens` component requires camera permissions to function. It will automatically request these permissions when used. If the permissions are granted, it will remove the `data-camera-error` attribute from the capture screen and set the `data-camera-ready` attribute to true. If the permissions are denied, it will remove the `data-camera-ready` attribute and set the `data-camera-error` attribute with the error message.
|
|
50
|
+
|
|
51
|
+
If you handle the permissions yourself, make sure to set `data-camera-ready` and `data-camera-error` appropriately.
|
|
52
|
+
|
|
53
|
+
### Error Handling
|
|
54
|
+
|
|
55
|
+
If there is an error while requesting permissions or capturing the images, the `SelfieCaptureScreens` component will handle it and set the `data-camera-error` attribute with the error message.
|
|
56
|
+
|
|
57
|
+
### Event Handlers
|
|
58
|
+
|
|
59
|
+
To receive the images after they have been captured, you can listen to the custom event `selfie-capture-screens.publish`. The data posted to this event has the structure:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"detail": {
|
|
64
|
+
"images": [{ "image": "base64 image", "image_type_id": "" }],
|
|
65
|
+
"meta": {
|
|
66
|
+
"version": "version of the library in use"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Usage:
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
document
|
|
76
|
+
.querySelector('selfie-capture-screens')
|
|
77
|
+
.addEventListener('selfie-capture-screens.publish', function (event) {
|
|
78
|
+
console.log(event.detail);
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Dependencies
|
|
83
|
+
|
|
84
|
+
The `SelfieCaptureScreens` component depends on the following modules:
|
|
85
|
+
|
|
86
|
+
- [selfie-capture](#selfiecapture-web-component)
|
|
87
|
+
- [selfie-capture-review](#selfie-capture-review-web-component)
|
|
88
|
+
- Selfie-instructions
|
|
89
|
+
- SmartCamera
|
|
90
|
+
|
|
91
|
+
These modules are imported when you use the `SelfieCaptureScreens` component in your projects.
|
|
92
|
+
|
|
93
|
+
### SelfieCapture Web Component
|
|
94
|
+
|
|
95
|
+
#### Overview
|
|
96
|
+
|
|
97
|
+
The `SelfieCapture` is a custom web component designed to capture selfies and liveness images using a camera. It uses the `SmartCamera` module to interact with the device's camera and handle permissions.
|
|
98
|
+
|
|
99
|
+
#### Importing the SelfieCapture Component
|
|
100
|
+
|
|
101
|
+
To use the SelfieCapture component, you need to import it into your JavaScript file:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
import '@smileid/web-components/selfie-capture';
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Using the Component
|
|
108
|
+
|
|
109
|
+
You can use the SelfieCapture component in your HTML like any other HTML element:
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<selfie-capture></selfie-capture>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### SelfieCapture Web Component Attributes
|
|
116
|
+
|
|
117
|
+
You can use a mixture of the following attributes to configure the behavior of the component.
|
|
118
|
+
|
|
119
|
+
#### show-navigation
|
|
120
|
+
|
|
121
|
+
This attribute, when present, shows the navigation controls for the document capture process. It does not require a value.
|
|
122
|
+
|
|
123
|
+
Usage:
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<selfie-capture show-navigation></selfie-capture>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Permissions
|
|
130
|
+
|
|
131
|
+
The `SelfieCapture` component requires camera permissions to function. It will automatically request these permissions when used. If the permissions are granted, it will remove the `data-camera-error` attribute from the capture screen and set the `data-camera-ready` attribute to true. If the permissions are denied, it will remove the `data-camera-ready` attribute and set the `data-camera-error` attribute with the error message.
|
|
132
|
+
|
|
133
|
+
If you handle the permissions yourself, make sure to set `data-camera-ready` and `data-camera-error` appropriately.
|
|
134
|
+
|
|
135
|
+
### Error Handling
|
|
136
|
+
|
|
137
|
+
If there is an error while requesting permissions or capturing the images, the `SelfieCapture` component will handle it and set the `data-camera-error` attribute with the error message.
|
|
138
|
+
|
|
139
|
+
### Event Handlers
|
|
140
|
+
|
|
141
|
+
To receive the images after they have been captured, you can listen to the custom event `selfie-capture.publish`. The data posted to this event has the structure:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"detail": {
|
|
146
|
+
"images": [
|
|
147
|
+
{"image": "
|
|
148
|
+
|
|
149
|
+
base64 image", "image_type_id": ""}
|
|
150
|
+
],
|
|
151
|
+
"meta": {
|
|
152
|
+
"version": "version of the library in use"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Usage:
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
document
|
|
162
|
+
.querySelector('selfie-capture')
|
|
163
|
+
.addEventListener('selfie-capture.publish', function (event) {
|
|
164
|
+
console.log(event.detail);
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### SelfieCaptureReview Web Component
|
|
169
|
+
|
|
170
|
+
This component is used to allow the user to verify the accuracy of the capture.
|
|
171
|
+
The user can choose to use the captured image or recapture a new selfie.
|
|
172
|
+
|
|
173
|
+
Usage:
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<selfie-capture-review
|
|
177
|
+
data-image="base64 image"
|
|
178
|
+
show-navigation
|
|
179
|
+
hide-back-to-host
|
|
180
|
+
></selfie-capture-review>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
When a user accepts an image, an event is triggered as shown below:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
document
|
|
187
|
+
.querySelector('selfie-capture-review')
|
|
188
|
+
.addEventListener('selfie-capture-review.accepted', function (event) {});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
When a user wants to recapture a selfie, an event is triggered as shown below:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
document
|
|
195
|
+
.querySelector('selfie-capture-review')
|
|
196
|
+
.addEventListener('selfie-capture-review.rejected', function (event) {});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Compatibility
|
|
200
|
+
|
|
201
|
+
The SelfieCaptureScreens component is designed to work on all modern browsers that support custom web components. However, it includes a special case for multi-camera Samsung devices to mitigate blurry images at the edges. Please report any issues found on other devices to our support team.
|
|
@@ -0,0 +1,224 @@
|
|
|
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 { version as COMPONENTS_VERSION } from '../../../package.json';
|
|
7
|
+
|
|
8
|
+
async function getPermissions(captureScreen) {
|
|
9
|
+
try {
|
|
10
|
+
await SmartCamera.getMedia({ audio: false, video: true });
|
|
11
|
+
captureScreen.removeAttribute('data-camera-error');
|
|
12
|
+
captureScreen.setAttribute('data-camera-ready', true);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
captureScreen.removeAttribute('data-camera-ready');
|
|
15
|
+
captureScreen.setAttribute(
|
|
16
|
+
'data-camera-error',
|
|
17
|
+
SmartCamera.handleCameraError(error),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class SelfieCaptureScreens extends HTMLElement {
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.activeScreen = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
connectedCallback() {
|
|
29
|
+
this.innerHTML = `
|
|
30
|
+
${styles}
|
|
31
|
+
<div>
|
|
32
|
+
<selfie-capture-instructions ${this.showNavigation} ${this.hideAttribution} ${this.hideBack} hidden></selfie-capture-instructions>
|
|
33
|
+
<selfie-capture ${this.showNavigation} ${this.hideAttribution} ${this.disableImageTests} hidden></selfie-capture>
|
|
34
|
+
<selfie-capture-review ${this.showNavigation} ${this.hideAttribution} hidden></selfie-capture-review>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
this._data = {
|
|
39
|
+
images: [],
|
|
40
|
+
meta: {
|
|
41
|
+
libraryVersion: COMPONENTS_VERSION,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
this.selfieInstruction = this.querySelector('selfie-capture-instructions');
|
|
46
|
+
this.selfieCapture = this.querySelector('selfie-capture');
|
|
47
|
+
this.selfieReview = this.querySelector('selfie-capture-review');
|
|
48
|
+
|
|
49
|
+
if (this.hideInstructions && !this.hasAttribute('hidden')) {
|
|
50
|
+
getPermissions(this.selfieCapture);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.getAttribute('initial-screen') === 'selfie-capture') {
|
|
54
|
+
getPermissions(this.selfieCapture);
|
|
55
|
+
this.setActiveScreen(this.selfieCapture);
|
|
56
|
+
} else if (this.hideInstructions) {
|
|
57
|
+
this.setActiveScreen(this.selfieCapture);
|
|
58
|
+
} else {
|
|
59
|
+
this.setActiveScreen(this.selfieInstruction);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.setUpEventListeners();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
disconnectedCallback() {
|
|
66
|
+
SmartCamera.stopMedia();
|
|
67
|
+
if (this.activeScreen) {
|
|
68
|
+
this.activeScreen.removeAttribute('hidden');
|
|
69
|
+
}
|
|
70
|
+
this.activeScreen = null;
|
|
71
|
+
this.innerHTML = '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setUpEventListeners() {
|
|
75
|
+
this.selfieInstruction.addEventListener(
|
|
76
|
+
'selfie-capture-instructions.capture',
|
|
77
|
+
async () => {
|
|
78
|
+
await getPermissions(this.selfieCapture);
|
|
79
|
+
this.setActiveScreen(this.selfieCapture);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
this.selfieInstruction.addEventListener(
|
|
83
|
+
'selfie-capture-instructions.cancelled',
|
|
84
|
+
() => {
|
|
85
|
+
this.handleBackEvents();
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
this.selfieCapture.addEventListener('selfie-capture.cancelled', () => {
|
|
90
|
+
if (this.hideInstructions) {
|
|
91
|
+
this.dispatchEvent(new CustomEvent('selfie-capture-screens.cancelled'));
|
|
92
|
+
} else {
|
|
93
|
+
this.setActiveScreen(this.selfieInstruction);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
this.selfieCapture.addEventListener('selfie-capture.publish', (event) => {
|
|
98
|
+
this.selfieReview.setAttribute('data-image', event.detail.referenceImage);
|
|
99
|
+
this._data.images = event.detail.images;
|
|
100
|
+
SmartCamera.stopMedia();
|
|
101
|
+
this.setActiveScreen(this.selfieReview);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.selfieCapture.addEventListener('selfie-capture.cancelled', () => {
|
|
105
|
+
this.selfieCapture.reset();
|
|
106
|
+
SmartCamera.stopMedia();
|
|
107
|
+
if (this.hideInstructions) {
|
|
108
|
+
this.handleBackEvents();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.setActiveScreen(this.selfieInstruction);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this.selfieReview.addEventListener(
|
|
116
|
+
'selfie-capture-review.rejected',
|
|
117
|
+
async () => {
|
|
118
|
+
this.selfieReview.removeAttribute('data-image');
|
|
119
|
+
this._data.images = [];
|
|
120
|
+
if (this.hideInstructions) {
|
|
121
|
+
this.setActiveScreen(this.selfieCapture);
|
|
122
|
+
await getPermissions(this.selfieCapture);
|
|
123
|
+
} else {
|
|
124
|
+
this.setActiveScreen(this.selfieInstruction);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
this.selfieReview.addEventListener(
|
|
130
|
+
'selfie-capture-review.accepted',
|
|
131
|
+
async () => {
|
|
132
|
+
this._publishSelectedImages();
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
[this.selfieInstruction, this.selfieCapture, this.selfieReview].forEach(
|
|
137
|
+
(screen) => {
|
|
138
|
+
screen.addEventListener(
|
|
139
|
+
`${screen.nodeName.toLowerCase()}.close`,
|
|
140
|
+
() => {
|
|
141
|
+
this.handleCloseEvent();
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_publishSelectedImages() {
|
|
149
|
+
this.dispatchEvent(
|
|
150
|
+
new CustomEvent('selfie-capture-screens.publish', { detail: this._data }),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get hideInstructions() {
|
|
155
|
+
return this.hasAttribute('hide-instructions');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get hideAttribution() {
|
|
159
|
+
return this.hasAttribute('hide-attribution') ? 'hide-attribution' : '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
get hideBackOfId() {
|
|
163
|
+
return this.hasAttribute('hide-back-of-id');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get showNavigation() {
|
|
167
|
+
return this.hasAttribute('show-navigation') ? 'show-navigation' : '';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get hideBack() {
|
|
171
|
+
return this.hasAttribute('hide-back-to-host') ? 'hide-back' : '';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get disableImageTests() {
|
|
175
|
+
return this.hasAttribute('disable-image-tests')
|
|
176
|
+
? 'disable-image-tests'
|
|
177
|
+
: '';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
setActiveScreen(screen) {
|
|
181
|
+
this.activeScreen?.setAttribute('hidden', '');
|
|
182
|
+
screen.removeAttribute('hidden');
|
|
183
|
+
this.activeScreen = screen;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
handleBackEvents() {
|
|
187
|
+
this.dispatchEvent(new CustomEvent('selfie-capture-screens.cancelled'));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
handleCloseEvent() {
|
|
191
|
+
this.dispatchEvent(new CustomEvent('selfie-capture-screens.close'));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static get observedAttributes() {
|
|
195
|
+
return [
|
|
196
|
+
'title',
|
|
197
|
+
'hidden',
|
|
198
|
+
'show-navigation',
|
|
199
|
+
'hide-back-to-host',
|
|
200
|
+
'initial-screen',
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
attributeChangedCallback(name) {
|
|
205
|
+
switch (name) {
|
|
206
|
+
case 'title':
|
|
207
|
+
case 'hidden':
|
|
208
|
+
case 'initial-screen':
|
|
209
|
+
this.connectedCallback();
|
|
210
|
+
break;
|
|
211
|
+
default:
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (
|
|
218
|
+
'customElements' in window &&
|
|
219
|
+
!customElements.get('selfie-capture-screens')
|
|
220
|
+
) {
|
|
221
|
+
customElements.define('selfie-capture-screens', SelfieCaptureScreens);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export default SelfieCaptureScreens;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import './SelfieCaptureScreens';
|
|
2
|
+
|
|
3
|
+
const meta = {
|
|
4
|
+
component: 'selfie-capture-screens',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export default meta;
|
|
8
|
+
|
|
9
|
+
export const SelfieCaptureFlow = {
|
|
10
|
+
render: () => `
|
|
11
|
+
<selfie-capture-screens>
|
|
12
|
+
</selfie-capture-screens>
|
|
13
|
+
`,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const SelfieCaptureFlowHiddenInstructions = {
|
|
17
|
+
render: () => `
|
|
18
|
+
<selfie-capture-screens hide-instructions >
|
|
19
|
+
</selfie-capture-screens>
|
|
20
|
+
`,
|
|
21
|
+
};
|