@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.
Files changed (73) hide show
  1. package/.eslintrc.cjs +72 -0
  2. package/components/README.md +14 -0
  3. package/components/attribution/PoweredBySmileId.js +42 -0
  4. package/components/camera-permission/CameraPermission.js +136 -0
  5. package/components/camera-permission/CameraPermission.stories.js +21 -0
  6. package/components/combobox/src/Combobox.js +586 -0
  7. package/components/combobox/src/index.js +1 -0
  8. package/components/document/src/DocumentCaptureScreens.js +317 -0
  9. package/components/document/src/DocumentCaptureScreens.stories.js +51 -0
  10. package/components/document/src/README.md +108 -0
  11. package/components/document/src/document-capture/DocumentCapture.js +677 -0
  12. package/components/document/src/document-capture/DocumentCapture.stories.js +71 -0
  13. package/components/document/src/document-capture/README.md +89 -0
  14. package/components/document/src/document-capture/index.js +3 -0
  15. package/components/document/src/document-capture-instructions/DocumentCaptureInstructions.js +499 -0
  16. package/components/document/src/document-capture-instructions/DocumentCaptureInstructions.stories.js +17 -0
  17. package/components/document/src/document-capture-instructions/README.md +56 -0
  18. package/components/document/src/document-capture-instructions/index.js +3 -0
  19. package/components/document/src/document-capture-review/DocumentCaptureReview.js +378 -0
  20. package/components/document/src/document-capture-review/DocumentCaptureReview.stories.js +14 -0
  21. package/components/document/src/document-capture-review/README.md +79 -0
  22. package/components/document/src/document-capture-review/index.js +3 -0
  23. package/components/document/src/index.js +3 -0
  24. package/components/end-user-consent/src/EndUserConsent.js +809 -0
  25. package/components/end-user-consent/src/EndUserConsent.stories.js +23 -0
  26. package/components/end-user-consent/src/index.js +4 -0
  27. package/components/navigation/src/Navigation.js +160 -0
  28. package/components/navigation/src/Navigation.stories.js +24 -0
  29. package/components/navigation/src/index.js +3 -0
  30. package/components/selfie/README.md +201 -0
  31. package/components/selfie/src/SelfieCaptureScreens.js +224 -0
  32. package/components/selfie/src/SelfieCaptureScreens.stories.js +21 -0
  33. package/components/selfie/src/index.js +5 -0
  34. package/components/selfie/src/selfie-capture/SelfieCapture.js +878 -0
  35. package/components/selfie/src/selfie-capture/SelfieCapture.stories.js +23 -0
  36. package/components/selfie/src/selfie-capture/index.js +3 -0
  37. package/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.js +638 -0
  38. package/components/selfie/src/selfie-capture-instructions/SelfieCaptureInstructions.stories.js +17 -0
  39. package/components/selfie/src/selfie-capture-instructions/index.js +3 -0
  40. package/components/selfie/src/selfie-capture-review/SelfieCaptureReview.js +348 -0
  41. package/components/selfie/src/selfie-capture-review/SelfieCaptureReview.stories.js +17 -0
  42. package/components/selfie/src/selfie-capture-review/index.js +3 -0
  43. package/components/signature-pad/package.json +30 -0
  44. package/components/signature-pad/src/SignaturePad.js +477 -0
  45. package/components/signature-pad/src/SignaturePad.stories.js +24 -0
  46. package/components/signature-pad/src/index.js +3 -0
  47. package/components/smart-camera-web/src/SmartCameraWeb.js +246 -0
  48. package/components/smart-camera-web/src/SmartCameraWeb.stories.js +35 -0
  49. package/components/totp-consent/src/TotpConsent.js +935 -0
  50. package/components/totp-consent/src/index.js +4 -0
  51. package/cypress/e2e/smart-camera-web-attribution.cy.js +21 -0
  52. package/cypress/e2e/smart-camera-web-back-press.cy.js +481 -0
  53. package/cypress/e2e/smart-camera-web-hide-instructions.cy.js +334 -0
  54. package/cypress/e2e/smart-camera-web.cy.js +309 -0
  55. package/cypress/fixtures/example.json +5 -0
  56. package/cypress/pages/capture-back-of-id-hide-attribution.html +44 -0
  57. package/cypress/pages/capture-back-of-id-navigation.html +72 -0
  58. package/cypress/pages/smart-camera-web-hide-instructions.html +38 -0
  59. package/cypress/pages/smart-camera-web.html +38 -0
  60. package/cypress/support/commands.js +144 -0
  61. package/cypress/support/e2e.js +20 -0
  62. package/cypress.config.js +11 -0
  63. package/domain/camera/src/README.md +38 -0
  64. package/domain/camera/src/SmartCamera.js +81 -0
  65. package/domain/constants/src/Constants.js +27 -0
  66. package/domain/file-upload/README.md +35 -0
  67. package/domain/file-upload/src/SmartFileUpload.js +65 -0
  68. package/esbuild.js +119 -0
  69. package/index.js +5 -0
  70. package/package.json +46 -0
  71. package/styles/README.md +3 -0
  72. package/styles/src/styles.js +348 -0
  73. package/styles/src/typography.js +52 -0
@@ -0,0 +1,477 @@
1
+ import SignaturePadCore from 'signature_pad';
2
+
3
+ class SmartFileUpload {
4
+ static memoryLimit = 2048000;
5
+
6
+ static supportedTypes = ['image/jpeg', 'image/png', 'image/svg+xml'];
7
+
8
+ static getHumanSize(numberOfBytes) {
9
+ // Approximate to the closest prefixed unit
10
+ const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
11
+ const exponent = Math.min(
12
+ Math.floor(Math.log(numberOfBytes) / Math.log(1024)),
13
+ units.length - 1,
14
+ );
15
+ const approx = numberOfBytes / 1024 ** exponent;
16
+ const output =
17
+ exponent === 0
18
+ ? `${numberOfBytes} bytes`
19
+ : `${approx.toFixed(0)} ${units[exponent]}`;
20
+
21
+ return output;
22
+ }
23
+
24
+ static getData(file) {
25
+ return new Promise((resolve, reject) => {
26
+ const reader = new FileReader();
27
+
28
+ reader.onload = (e) => {
29
+ resolve(e.target.result);
30
+ };
31
+ reader.onerror = () => {
32
+ reject(
33
+ new Error(
34
+ 'An error occurred reading the file. Please check the file, and try again',
35
+ ),
36
+ );
37
+ };
38
+ reader.readAsDataURL(file);
39
+ });
40
+ }
41
+
42
+ static async retrieve(files) {
43
+ if (files.length > 1) {
44
+ throw new Error('Only one file upload is permitted at a time');
45
+ }
46
+
47
+ const file = files[0];
48
+
49
+ if (!SmartFileUpload.supportedTypes.includes(file.type)) {
50
+ throw new Error(
51
+ 'Unsupported file format. Please ensure that you are providing a JPG, PNG or SVG image',
52
+ );
53
+ }
54
+
55
+ if (file.size > SmartFileUpload.memoryLimit) {
56
+ throw new Error(
57
+ `${
58
+ file.name
59
+ } is too large. Please ensure that the file is less than ${SmartFileUpload.getHumanSize(
60
+ SmartFileUpload.memoryLimit,
61
+ )}.`,
62
+ );
63
+ }
64
+
65
+ const imageAsDataUrl = await SmartFileUpload.getData(file);
66
+
67
+ return imageAsDataUrl;
68
+ }
69
+ }
70
+
71
+ class SignaturePad extends HTMLElement {
72
+ connectedCallback() {
73
+ const shadow = this.attachShadow({ mode: 'open' });
74
+
75
+ const style = document.createElement('style');
76
+ style.textContent = `
77
+ :host {
78
+ display: block;
79
+ block-size: auto;
80
+ inline-size: 30rem;
81
+ max-inline-size: 100%;
82
+ position: relative;
83
+ --color-active: #2D2B2A;
84
+ --color-default: #001096;
85
+ --color-disabled: #848282;
86
+ }
87
+
88
+ :host::part(upload) {
89
+ text-align: center;
90
+ }
91
+
92
+ :host::part(signature-controls) {
93
+ display: inline-flex;
94
+ position: absolute;
95
+ top: 1rem;
96
+ right: 1rem;
97
+ }
98
+
99
+ :host::part(upload) svg + * {
100
+ margin-inline-start: .5rem;
101
+ }
102
+
103
+ :host::part(canvas) {
104
+ background-color: #F9F0E7;
105
+ --dot-bg: #F9F0E7;
106
+ --dot-color: black;
107
+ --dot-size: 1px;
108
+ --dot-space: 22px;
109
+ background:
110
+ linear-gradient(90deg, var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space),
111
+ linear-gradient(var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space),
112
+ var(--dot-color);
113
+ border-radius: 2rem;
114
+ inline-size: 30rem;
115
+ max-inline-size: 100%;
116
+ aspect-ratio: 2 / 1;
117
+ }
118
+
119
+ :host::part(upload-preview-image) {
120
+ max-inline-size: 10rem;
121
+ margin-inline: auto;
122
+ }
123
+
124
+ .visually-hidden {
125
+ clip: rect(0 0 0 0);
126
+ clip-path: inset(50%);
127
+ height: 1px;
128
+ overflow: hidden;
129
+ position: absolute;
130
+ white-space: nowrap;
131
+ width: 1px;
132
+ }
133
+
134
+ button,
135
+ label {
136
+ font: inherit;
137
+ cursor: pointer;
138
+ }
139
+
140
+ label {
141
+ display: inline-flex;
142
+ text-decoration: underline;
143
+ }
144
+
145
+ label svg + * {
146
+ margin-inline-start: .5rem;
147
+ }
148
+
149
+ [type="file"] {
150
+ display: none;
151
+ }
152
+
153
+ .center {
154
+ text-align: center;
155
+ margin-inline: auto;
156
+ }
157
+
158
+ .color-red {
159
+ color: red;
160
+ }
161
+
162
+ button[data-variant="icon"] {
163
+ appearance: none;
164
+ -webkit-appearance: none;
165
+ background-color: transparent;
166
+ border: 0px;
167
+ }
168
+
169
+ button[data-variant="text"] {
170
+ appearance: none;
171
+ -webkit-appearance: none;
172
+ background-color: transparent;
173
+ border: 0px;
174
+ text-decoration: underline;
175
+ display: inline-flex;
176
+ align-items: baseline;
177
+ }
178
+
179
+ button[data-variant="solid"] {
180
+ --button-color: var(--color-default);
181
+ border-radius: 2.5rem;
182
+ border: 0;
183
+ background-color: transparent;
184
+ color: #fff;
185
+ cursor: pointer;
186
+ inline-size: 100%;
187
+ display: inline-flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+ font-size: 18px;
191
+ font-weight: 600;
192
+ padding: .75rem 1.5rem;
193
+ text-align: center;
194
+ background-color: var(--button-color);
195
+ border: 2px solid var(--button-color);
196
+ }
197
+
198
+ button:hover,
199
+ button:focus,
200
+ button:active {
201
+ --button-color: var(--color-active);
202
+ }
203
+
204
+ button:disabled {
205
+ --button-color: var(--color-disabled);
206
+ }
207
+ `;
208
+
209
+ const wrapper = document.createElement('div');
210
+ const errorMessage = document.createElement('div');
211
+ errorMessage.innerHTML = `
212
+ <p id="error" class="color-red | center"><p>
213
+ `;
214
+
215
+ const signatureControls = document.createElement('div');
216
+ signatureControls.setAttribute('id', 'controls');
217
+ signatureControls.setAttribute('part', 'signature-controls');
218
+ signatureControls.innerHTML = `
219
+ <button data-variant="icon" type="button" name="clear" id="clear">
220
+ <span class="visually-hidden">
221
+ Clear Signature
222
+ </span>
223
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" width="18" viewBox="0 0 17 18">
224
+ <path d="M3.314 15.646a8.004 8.004 0 01-2.217-4.257 8.06 8.06 0 01.545-4.655l1.789.788a6.062 6.062 0 001.264 6.737 6.033 6.033 0 008.551 0c2.358-2.37 2.358-6.224 0-8.592a5.996 5.996 0 00-4.405-1.782l.662 2.354-3.128-.796-3.127-.796 2.25-2.324L7.748 0l.55 1.953a7.966 7.966 0 016.33 2.326 8.004 8.004 0 012.342 5.684 8.005 8.005 0 01-2.343 5.683A7.928 7.928 0 018.97 18a7.928 7.928 0 01-5.656-2.354z" fill="currentColor" />
225
+ </svg>
226
+ </button>
227
+ `;
228
+
229
+ const canvas = document.createElement('canvas');
230
+
231
+ /**
232
+ * NOTE: In order to make this responsive, we need to calculate the width
233
+ * / height of the canvas element relative to the closest visible element
234
+ *
235
+ * Within our consuming context, we do follow these steps:
236
+ * - Find the closest ancestor that is visible
237
+ * - Find the visible child of that ancestor
238
+ * - Get the reference width / inline-size of the element
239
+ * - Compute the canvas.height as the lesser of the reference width or the
240
+ * inline size of the canvas set in CSS
241
+ * - Compute the canvas.height as half the size of the canvas.width or the
242
+ * block size computed by the aspect-ratio property
243
+ */
244
+
245
+ const closestVisibleAncestor = this.parentElement.closest(':not([hidden])');
246
+ const visibleChild = closestVisibleAncestor.querySelector(':not([hidden])');
247
+ const containerWidth = visibleChild.offsetWidth;
248
+
249
+ const remInPx = getComputedStyle(document.documentElement).fontSize.split(
250
+ 'px',
251
+ )[0];
252
+ const componentMaxInlineSize = 30 * remInPx; // 30rem from the style declaration
253
+ const aspectRatio = 2; // 2 from the canvas style aspect ratio declaration
254
+
255
+ canvas.width =
256
+ containerWidth < componentMaxInlineSize
257
+ ? containerWidth
258
+ : componentMaxInlineSize;
259
+ canvas.height =
260
+ (containerWidth < componentMaxInlineSize
261
+ ? containerWidth
262
+ : componentMaxInlineSize) / aspectRatio;
263
+
264
+ canvas.setAttribute('id', 'signature-canvas');
265
+ canvas.setAttribute('part', 'canvas');
266
+
267
+ const uploadControl = document.createElement('div');
268
+ uploadControl.setAttribute('id', 'signature-upload-wrapper');
269
+ uploadControl.innerHTML = `
270
+ <p part="upload">
271
+ <strong>or</strong>
272
+ <label>
273
+ <input type='file' onclick='this.value=null;' id='upload-signature' accept='image/jpeg, image/png, image/svg+xml' />
274
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none">
275
+ <rect width="16" height="16" fill="#F9F0E7" rx="2"/>
276
+ <mask id="sign" width="16" height="16" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha">
277
+ <rect width="16" height="16" fill="#D9D9D9" rx="2"/>
278
+ </mask>
279
+ <g mask="url(#sign)">
280
+ <path fill="#2D2B2A" d="M0 13.333h16V16H0z"/>
281
+ </g>
282
+ <path fill="#2D2B2A" fill-rule="evenodd" d="M2.69 7.346a.23.23 0 0 1 .059-.073.275.275 0 0 1 .284-.034c.07.036.146.064.224.084h.12c0-.012.105-.048.105-.395a.796.796 0 0 1 .211-.61.667.667 0 0 1 .607-.096c.202.061.39.154.555.275.194.138.38.286.555.443.146.134.31.25.489.347l.092.047c.119.06.238-.023.185-.143l-.04-.12a.817.817 0 0 1-.066-.694.675.675 0 0 1 .244-.273.774.774 0 0 1 .364-.12c.324-.028.651 0 .964.083h.026c.027-.861.225-1.83.82-2.523.593-.694 1.478-.993 2.205-.837.726.155 1.307.73 1.307 1.602 0 1.34-.872 2.26-1.915 2.93.471.374.85.835 1.11 1.351.027.046.05.094.065.144h.014a.55.55 0 0 0 .079.203.44.44 0 0 0 .04.18c.002.025.011.05.026.07h-.013c.037.17.041.344.013.515a.955.955 0 0 1-.188.493 1.097 1.097 0 0 1-.433.344 1.346 1.346 0 0 1-1.122.012 2.194 2.194 0 0 1-.846-.67 5.024 5.024 0 0 1-.462-.681h-.026a.502.502 0 0 0-.106-.144.014.014 0 0 1-.01-.003.011.011 0 0 1-.003-.009.035.035 0 0 1-.013-.023.047.047 0 0 1-.011-.017.626.626 0 0 0-.055-.163.24.24 0 0 0-.014-.095h.014a3.477 3.477 0 0 1-.198-.49 6.318 6.318 0 0 1-.278-1.699L7.51 6.51c-.243-.07-.5-.094-.753-.071-.158.024-.198.071-.211.107-.014.036-.04.168.053.359.092.191.171.478.118.658a.45.45 0 0 1-.21.25.66.66 0 0 1-.305.06 1.521 1.521 0 0 1-.568-.19 3.533 3.533 0 0 1-.58-.42 3.54 3.54 0 0 0-.49-.394 1.49 1.49 0 0 0-.409-.203c-.053-.024-.079-.024-.092-.012H4.05c-.014.012-.066.072-.066.275 0 .395-.12.705-.423.813a.813.813 0 0 1-.41.024 1.646 1.646 0 0 1-.343-.12.237.237 0 0 1-.126-.127.208.208 0 0 1 .007-.172Zm5.731.766c.068.204.152.404.251.598.011.053.03.105.053.155.036.068.08.132.132.191.02.05.047.099.08.144.085.152.186.296.303.43.167.22.389.4.647.526a.847.847 0 0 0 .687-.011.655.655 0 0 0 .247-.204.573.573 0 0 0 .11-.287 1.435 1.435 0 0 0-.04-.454h-.014a.496.496 0 0 0-.079-.335.491.491 0 0 0-.119-.191 3.842 3.842 0 0 0-1.017-1.16l-.356.18a.253.253 0 0 1-.193.027.248.248 0 0 1-.088-.041.22.22 0 0 1-.063-.07.219.219 0 0 1-.02-.172.242.242 0 0 1 .113-.14l.172-.083a3.388 3.388 0 0 0-.463-.251l-.58-.24c.022.47.101.935.237 1.388Zm.568-1.555c.24.12.474.252.7.395 1.017-.634 1.81-1.459 1.81-2.63 0-.67-.41-1.053-.912-1.16-.502-.108-1.189.083-1.704.669-.515.586-.7 1.47-.713 2.32v.083c.251.084.515.192.819.323Z" clip-rule="evenodd"/>
283
+ </svg>
284
+ <span>upload a signature</span>
285
+ </label>
286
+ </p>
287
+ `;
288
+
289
+ const publishSignatureContainer = document.createElement('p');
290
+ publishSignatureContainer.innerHTML = `
291
+ <button data-variant="solid" type="button" name="publish" id="publish">
292
+ <span>
293
+ Continue
294
+ </span>
295
+ <svg
296
+ aria-hidden="true"
297
+ width="25"
298
+ height="24"
299
+ fill="none"
300
+ xmlns="http://www.w3.org/2000/svg"
301
+ >
302
+ <path
303
+ d="M7 12h11m0 0-4.588-4M18 12l-4.588 4"
304
+ stroke="#fff"
305
+ stroke-width="1.5"
306
+ stroke-linecap="round"
307
+ stroke-linejoin="round"
308
+ />
309
+ </svg>
310
+ </button>
311
+ `;
312
+
313
+ wrapper.appendChild(errorMessage);
314
+ wrapper.appendChild(signatureControls);
315
+ wrapper.appendChild(canvas);
316
+ if (this.allowUpload) wrapper.appendChild(uploadControl);
317
+ wrapper.appendChild(publishSignatureContainer);
318
+
319
+ shadow.appendChild(style);
320
+ shadow.appendChild(wrapper);
321
+
322
+ this.core = new SignaturePadCore(canvas);
323
+
324
+ // Error Message
325
+ this.errorMessage = errorMessage.querySelector('#error');
326
+
327
+ // Canvas Resize / Sizing
328
+ if (window) {
329
+ window.onresize = this.resizeCanvas();
330
+ }
331
+
332
+ // Signature Pad Controls
333
+ this.clearSignatureButton = signatureControls.querySelector('#clear');
334
+ this.clearSignatureButton.addEventListener('click', () =>
335
+ this.clearSignature(),
336
+ );
337
+
338
+ // Upload Controls
339
+ this.uploadSignatureButton =
340
+ uploadControl.querySelector('#upload-signature');
341
+ this.uploadSignatureButton.addEventListener('change', (event) =>
342
+ this.uploadSignature(event),
343
+ );
344
+
345
+ // Publish Signature
346
+ this.publishSignatureButton =
347
+ publishSignatureContainer.querySelector('#publish');
348
+ this.publishSignatureButton.addEventListener('click', () =>
349
+ this.publishSignature(),
350
+ );
351
+ }
352
+
353
+ disconnectedCallback() {
354
+ this.publishSignatureButton.removeEventListener('click', () =>
355
+ this.publishSignature(),
356
+ );
357
+ this.clearSignatureButton.removeEventListener('click', () =>
358
+ this.clearSignature(),
359
+ );
360
+ this.uploadSignatureButton.removeEventListener('change', (event) =>
361
+ this.uploadSignature(event),
362
+ );
363
+ }
364
+
365
+ // Adjust canvas coordinate space taking into account pixel ratio,
366
+ // to make it look crisp on mobile devices.
367
+ // This also causes canvas to be cleared.
368
+ resizeCanvas() {
369
+ // When zoomed out to less than 100%, for some very strange reason,
370
+ // some browsers report devicePixelRatio as less than 1
371
+ // and only part of the canvas is cleared then.
372
+ const canvas = this.shadowRoot.querySelector('canvas');
373
+ const ratio = Math.max(window.devicePixelRatio || 1, 1);
374
+
375
+ // This part causes the canvas to be cleared
376
+ canvas.width = (canvas.offsetWidth || canvas.width) * ratio;
377
+ canvas.height = (canvas.offsetHeight || canvas.height) * ratio;
378
+ canvas.getContext('2d').scale(ratio, ratio);
379
+
380
+ // This library does not listen for canvas changes, so after the canvas is automatically
381
+ // cleared by the browser, SignaturePad#isEmpty might still return false, even though the
382
+ // canvas looks empty, because the internal data of this library wasn't cleared. To make sure
383
+ // that the state of this library is consistent with visual state of the canvas, you
384
+ // have to clear it manually.
385
+ // signaturePad.clear();
386
+
387
+ // If you want to keep the drawing on resize instead of clearing it you can reset the data.
388
+ this.core.fromData(this.core.toData());
389
+ }
390
+
391
+ publishSignature() {
392
+ try {
393
+ this.resetErrorMessage();
394
+ const previewImage = this.shadowRoot.querySelector('img');
395
+ let image = previewImage ? previewImage.src : undefined;
396
+ if (!image && !this.core.isEmpty()) {
397
+ image = this.core.toDataURL('image/svg+xml');
398
+ }
399
+
400
+ if (image) {
401
+ this.dispatchEvent(
402
+ new CustomEvent('signature-pad.publish', {
403
+ detail: image,
404
+ }),
405
+ );
406
+ } else {
407
+ throw new Error(
408
+ `No signature present. ${
409
+ this.allowUpload ? 'Draw or upload' : 'Draw'
410
+ } a signature`,
411
+ );
412
+ }
413
+ } catch (error) {
414
+ this.handleError(error.message);
415
+ }
416
+ }
417
+
418
+ resetErrorMessage() {
419
+ this.errorMessage.textContent = '';
420
+ }
421
+
422
+ handleError(error) {
423
+ this.errorMessage.textContent = error;
424
+ }
425
+
426
+ clearSignature() {
427
+ this.resetErrorMessage();
428
+ const canvas = this.shadowRoot.querySelector('canvas');
429
+ const img = this.shadowRoot.querySelector('img');
430
+
431
+ if (img) {
432
+ img.remove();
433
+ canvas.removeAttribute('hidden');
434
+ }
435
+
436
+ this.core.clear();
437
+ }
438
+
439
+ previewUpload(fileData) {
440
+ const canvas = this.shadowRoot.querySelector('canvas');
441
+ let img = this.shadowRoot.querySelector('img');
442
+
443
+ if (!img) {
444
+ img = document.createElement('img');
445
+ }
446
+
447
+ img.src = fileData;
448
+ img.setAttribute('part', 'upload-preview-image');
449
+ canvas.setAttribute('hidden', true);
450
+ canvas.insertAdjacentElement('afterend', img);
451
+ }
452
+
453
+ async uploadSignature(event) {
454
+ try {
455
+ this.resetErrorMessage();
456
+ const { files } = event.target;
457
+
458
+ // validate file, and convert file to data url
459
+ const fileData = await SmartFileUpload.retrieve(files);
460
+
461
+ // swap out canvas for an image for preview
462
+ this.previewUpload(fileData);
463
+ } catch (error) {
464
+ this.handleError(error.message);
465
+ }
466
+ }
467
+
468
+ get allowUpload() {
469
+ return this.hasAttribute('allow-upload');
470
+ }
471
+ }
472
+
473
+ if ('customElements' in window) {
474
+ window.customElements.define('smileid-signature-pad', SignaturePad);
475
+ }
476
+
477
+ export default SignaturePad;
@@ -0,0 +1,24 @@
1
+ import './SignaturePad';
2
+
3
+ const meta = {
4
+ component: 'smileid-signature-pad',
5
+ };
6
+
7
+ export default meta;
8
+
9
+ export const SignaturePad = {
10
+ render: () => `
11
+ <smileid-signature-pad
12
+ >
13
+ </smileid-signature-pad>
14
+ `,
15
+ };
16
+
17
+ export const SignaturePadWithUploads = {
18
+ render: () => `
19
+ <smileid-signature-pad
20
+ allow-upload
21
+ >
22
+ </smileid-signature-pad>
23
+ `,
24
+ };
@@ -0,0 +1,3 @@
1
+ import SignaturePad from './SignaturePad';
2
+
3
+ export default SignaturePad;