@tn3w/openage 1.0.5 → 1.0.6
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/README.md +22 -6
- package/dist/openage.esm.js +144 -18
- package/dist/openage.esm.js.map +1 -1
- package/dist/openage.min.js +1 -1
- package/dist/openage.min.js.map +1 -1
- package/dist/openage.umd.js +144 -18
- package/dist/openage.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/challenge.js +25 -6
- package/src/constants.js +1 -2
- package/src/index.d.ts +1 -0
- package/src/index.js +17 -0
- package/src/ui.js +14 -0
- package/src/widget.d.ts +1 -0
- package/src/widget.js +87 -10
package/package.json
CHANGED
package/src/challenge.js
CHANGED
|
@@ -143,9 +143,18 @@ function resolveChallengeErrorMessage(error) {
|
|
|
143
143
|
return 'Verification failed. Please try again.';
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
function isInlineLayout(widget) {
|
|
147
|
+
return widget?.params?.layout === 'inline';
|
|
148
|
+
}
|
|
149
|
+
|
|
146
150
|
async function showErrorStep(widget, error) {
|
|
147
151
|
const message = resolveChallengeErrorMessage(error);
|
|
148
152
|
|
|
153
|
+
if (isInlineLayout(widget)) {
|
|
154
|
+
widget.showResult?.('retry', message);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
149
158
|
if (!widget.popup) {
|
|
150
159
|
widget.openPopup?.();
|
|
151
160
|
}
|
|
@@ -198,10 +207,14 @@ async function runServerless(widget, emitter) {
|
|
|
198
207
|
await Promise.all([loadVision(), initAgeEstimator()]);
|
|
199
208
|
|
|
200
209
|
modelBuffer = await loadModel();
|
|
201
|
-
widget.showReady();
|
|
202
210
|
|
|
203
|
-
|
|
204
|
-
|
|
211
|
+
if (isInlineLayout(widget)) {
|
|
212
|
+
await startCameraFlow(widget, modelBuffer);
|
|
213
|
+
} else {
|
|
214
|
+
widget.showReady();
|
|
215
|
+
await waitForStart(widget);
|
|
216
|
+
await startCameraFlow(widget, modelBuffer);
|
|
217
|
+
}
|
|
205
218
|
|
|
206
219
|
const transport = createTransport('serverless', params);
|
|
207
220
|
|
|
@@ -290,10 +303,16 @@ async function runServer(widget, emitter) {
|
|
|
290
303
|
captureFrame: () => (captureFrame() ? 'true' : 'null'),
|
|
291
304
|
});
|
|
292
305
|
|
|
293
|
-
|
|
294
|
-
|
|
306
|
+
let video;
|
|
307
|
+
|
|
308
|
+
if (isInlineLayout(widget)) {
|
|
309
|
+
video = widget.showCamera();
|
|
310
|
+
} else {
|
|
311
|
+
widget.showReady();
|
|
312
|
+
await waitForStart(widget);
|
|
313
|
+
video = widget.showCamera();
|
|
314
|
+
}
|
|
295
315
|
|
|
296
|
-
const video = widget.showCamera();
|
|
297
316
|
widget.setVideoStatus('Requesting camera…');
|
|
298
317
|
await startCamera(video);
|
|
299
318
|
exposeMirrorVideo(video);
|
package/src/constants.js
CHANGED
|
@@ -11,8 +11,7 @@ export const MEDIAPIPE_MODEL =
|
|
|
11
11
|
'face_landmarker/face_landmarker/float16/1/' +
|
|
12
12
|
'face_landmarker.task';
|
|
13
13
|
|
|
14
|
-
export const FACEAPI_CDN =
|
|
15
|
-
'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js';
|
|
14
|
+
export const FACEAPI_CDN = 'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js';
|
|
16
15
|
|
|
17
16
|
export const FACEAPI_MODEL_CDN =
|
|
18
17
|
'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js@master/weights';
|
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
|
@@ -52,8 +52,19 @@ export class EventEmitter {
|
|
|
52
52
|
const emitter = new EventEmitter();
|
|
53
53
|
const widgets = new Map();
|
|
54
54
|
|
|
55
|
+
function normalizeLayout(layout) {
|
|
56
|
+
if (layout === 'inline' || layout === 'embed' || layout === 'embedded') {
|
|
57
|
+
return 'inline';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return 'widget';
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
function normalizeParams(params) {
|
|
56
64
|
const globalConfig = typeof window !== 'undefined' ? window.openage || {} : {};
|
|
65
|
+
const layout = normalizeLayout(
|
|
66
|
+
params.layout ?? params.display ?? globalConfig.layout ?? globalConfig.display
|
|
67
|
+
);
|
|
57
68
|
|
|
58
69
|
return {
|
|
59
70
|
mode: 'serverless',
|
|
@@ -62,6 +73,7 @@ function normalizeParams(params) {
|
|
|
62
73
|
minAge: 18,
|
|
63
74
|
...globalConfig,
|
|
64
75
|
...params,
|
|
76
|
+
layout,
|
|
65
77
|
};
|
|
66
78
|
}
|
|
67
79
|
|
|
@@ -70,6 +82,10 @@ function startWidget(widget) {
|
|
|
70
82
|
emitter.emit('opened', widget.id);
|
|
71
83
|
runChallenge(widget, emitter);
|
|
72
84
|
};
|
|
85
|
+
|
|
86
|
+
if (widget.params.layout === 'inline') {
|
|
87
|
+
widget.startChallenge();
|
|
88
|
+
}
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
function render(container, params = {}) {
|
|
@@ -218,6 +234,7 @@ function autoRender() {
|
|
|
218
234
|
size: element.dataset.size,
|
|
219
235
|
action: element.dataset.action,
|
|
220
236
|
mode: element.dataset.mode,
|
|
237
|
+
layout: element.dataset.layout || element.dataset.display,
|
|
221
238
|
server: element.dataset.server,
|
|
222
239
|
};
|
|
223
240
|
|
package/src/ui.js
CHANGED
|
@@ -541,6 +541,20 @@ export const STYLES = `
|
|
|
541
541
|
flex-direction: column;
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
+
.oa-inline-shell {
|
|
545
|
+
background: var(--oa-bg);
|
|
546
|
+
border: 1px solid var(--oa-border);
|
|
547
|
+
border-radius: var(--oa-radius);
|
|
548
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.18),
|
|
549
|
+
0 0 0 1px rgba(0,0,0,0.06);
|
|
550
|
+
width: min(100%, 360px);
|
|
551
|
+
max-width: 100%;
|
|
552
|
+
overflow: hidden;
|
|
553
|
+
display: flex;
|
|
554
|
+
flex-direction: column;
|
|
555
|
+
margin: 0 auto;
|
|
556
|
+
}
|
|
557
|
+
|
|
544
558
|
.oa-modal-overlay {
|
|
545
559
|
position: fixed;
|
|
546
560
|
inset: 0;
|
package/src/widget.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export interface WidgetParams {
|
|
|
2
2
|
sitekey?: string;
|
|
3
3
|
server?: string;
|
|
4
4
|
mode?: "serverless" | "sitekey" | "custom";
|
|
5
|
+
layout?: "widget" | "inline" | "embed" | "embedded";
|
|
5
6
|
theme?: "light" | "dark" | "auto";
|
|
6
7
|
size?: "compact" | "normal" | "invisible";
|
|
7
8
|
action?: string;
|
package/src/widget.js
CHANGED
|
@@ -27,6 +27,7 @@ export class Widget {
|
|
|
27
27
|
this.popup = null;
|
|
28
28
|
this.shadow = null;
|
|
29
29
|
this.elements = {};
|
|
30
|
+
this.popupElements = null;
|
|
30
31
|
this.onChallenge = null;
|
|
31
32
|
this.onStartClick = null;
|
|
32
33
|
this.popupFrame = 0;
|
|
@@ -39,6 +40,7 @@ export class Widget {
|
|
|
39
40
|
const host = document.createElement('div');
|
|
40
41
|
host.id = this.id;
|
|
41
42
|
this.shadow = host.attachShadow({ mode: 'open' });
|
|
43
|
+
this.host = host;
|
|
42
44
|
|
|
43
45
|
const style = document.createElement('style');
|
|
44
46
|
style.textContent = STYLES;
|
|
@@ -51,7 +53,12 @@ export class Widget {
|
|
|
51
53
|
if (this.params.size === 'invisible') {
|
|
52
54
|
host.style.display = 'none';
|
|
53
55
|
this.container.appendChild(host);
|
|
54
|
-
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (this.isInlineLayout()) {
|
|
60
|
+
this.renderInlineShell();
|
|
61
|
+
this.container.appendChild(host);
|
|
55
62
|
return;
|
|
56
63
|
}
|
|
57
64
|
|
|
@@ -87,7 +94,32 @@ export class Widget {
|
|
|
87
94
|
this.elements.errorSlot = this.shadow.querySelector('.oa-error-slot');
|
|
88
95
|
|
|
89
96
|
this.container.appendChild(host);
|
|
90
|
-
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
isInlineLayout() {
|
|
100
|
+
return this.params.layout === 'inline';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
renderInlineShell() {
|
|
104
|
+
const inlineShell = document.createElement('div');
|
|
105
|
+
inlineShell.className = 'oa-inline-shell';
|
|
106
|
+
inlineShell.innerHTML = this.buildPopupContent({ closeable: false });
|
|
107
|
+
this.shadow.appendChild(inlineShell);
|
|
108
|
+
|
|
109
|
+
this.popup = {
|
|
110
|
+
host: this.host,
|
|
111
|
+
root: inlineShell,
|
|
112
|
+
inline: true,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
this.bindPopupEvents(inlineShell);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
resetInlineShell() {
|
|
119
|
+
if (!this.popup?.root) return;
|
|
120
|
+
|
|
121
|
+
this.popup.root.innerHTML = this.buildPopupContent({ closeable: false });
|
|
122
|
+
this.bindPopupEvents(this.popup.root);
|
|
91
123
|
}
|
|
92
124
|
|
|
93
125
|
startChallenge() {
|
|
@@ -120,6 +152,14 @@ export class Widget {
|
|
|
120
152
|
}
|
|
121
153
|
|
|
122
154
|
openPopup() {
|
|
155
|
+
if (this.isInlineLayout()) {
|
|
156
|
+
if (!this.popup) {
|
|
157
|
+
this.renderInlineShell();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return this.getVideo();
|
|
161
|
+
}
|
|
162
|
+
|
|
123
163
|
if (this.popup) return this.getVideo();
|
|
124
164
|
|
|
125
165
|
const anchor = this.getPopupAnchor();
|
|
@@ -297,7 +337,7 @@ export class Widget {
|
|
|
297
337
|
this.popup.root.style.pointerEvents = 'auto';
|
|
298
338
|
}
|
|
299
339
|
|
|
300
|
-
buildPopupContent() {
|
|
340
|
+
buildPopupContent({ closeable = true } = {}) {
|
|
301
341
|
return `
|
|
302
342
|
<div class="oa-header">
|
|
303
343
|
<div class="oa-title">
|
|
@@ -308,10 +348,14 @@ export class Widget {
|
|
|
308
348
|
</a>
|
|
309
349
|
<span class="oa-badge">on-device</span>
|
|
310
350
|
</div>
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
351
|
+
${
|
|
352
|
+
closeable
|
|
353
|
+
? `<button class="oa-close-btn"
|
|
354
|
+
aria-label="Close">
|
|
355
|
+
${CLOSE_SVG}
|
|
356
|
+
</button>`
|
|
357
|
+
: ''
|
|
358
|
+
}
|
|
315
359
|
</div>
|
|
316
360
|
<div class="oa-body">
|
|
317
361
|
${heroTemplate('Initializing…')}
|
|
@@ -324,7 +368,7 @@ export class Widget {
|
|
|
324
368
|
`;
|
|
325
369
|
}
|
|
326
370
|
|
|
327
|
-
bindPopupEvents(root
|
|
371
|
+
bindPopupEvents(root) {
|
|
328
372
|
const closeBtn = root.querySelector('.oa-close-btn');
|
|
329
373
|
if (closeBtn) {
|
|
330
374
|
closeBtn.addEventListener('click', () => {
|
|
@@ -442,6 +486,22 @@ export class Widget {
|
|
|
442
486
|
}
|
|
443
487
|
|
|
444
488
|
showResult(outcome, message) {
|
|
489
|
+
if (this.isInlineLayout()) {
|
|
490
|
+
if (!this.popupElements?.body) return;
|
|
491
|
+
|
|
492
|
+
this.popupElements.body.innerHTML = resultTemplate(outcome, message);
|
|
493
|
+
this.hideActions();
|
|
494
|
+
|
|
495
|
+
if (outcome === 'pass') {
|
|
496
|
+
this.setState('verified');
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
this.setState(outcome === 'fail' ? 'failed' : 'retry');
|
|
501
|
+
this.showActions('Try Again');
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
445
505
|
if (outcome === 'pass') {
|
|
446
506
|
this.closePopup();
|
|
447
507
|
this.setState('verified');
|
|
@@ -481,8 +541,9 @@ export class Widget {
|
|
|
481
541
|
if (!this.popupElements?.body) return;
|
|
482
542
|
|
|
483
543
|
this.popupElements.body.innerHTML = errorStepTemplate(message);
|
|
484
|
-
this.popupElements.errorCountdown =
|
|
485
|
-
|
|
544
|
+
this.popupElements.errorCountdown = this.popupElements.body.querySelector(
|
|
545
|
+
'.oa-error-step-countdown'
|
|
546
|
+
);
|
|
486
547
|
this.hideActions();
|
|
487
548
|
}
|
|
488
549
|
|
|
@@ -501,6 +562,22 @@ export class Widget {
|
|
|
501
562
|
|
|
502
563
|
closePopup() {
|
|
503
564
|
if (!this.popup) return;
|
|
565
|
+
|
|
566
|
+
if (this.popup.inline) {
|
|
567
|
+
this.popup.cleanup?.();
|
|
568
|
+
if (this.popupFrame) {
|
|
569
|
+
cancelAnimationFrame(this.popupFrame);
|
|
570
|
+
this.popupFrame = 0;
|
|
571
|
+
}
|
|
572
|
+
this.resetInlineShell();
|
|
573
|
+
|
|
574
|
+
if (this.state === 'loading') {
|
|
575
|
+
this.setState('idle');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
|
|
504
581
|
this.popup.cleanup?.();
|
|
505
582
|
this.popup.themeCleanup?.();
|
|
506
583
|
this.popup.host.remove();
|