@zkpassport/ui 0.14.2

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.
@@ -0,0 +1,548 @@
1
+ @layer zkpassport {
2
+ .zkp-card {
3
+ --zkp-bg: #ffffff;
4
+ --zkp-fg: #111827;
5
+ --zkp-muted: #6b7280;
6
+ --zkp-border: #e5e7eb;
7
+ --zkp-surface: #f3f4f6;
8
+ --zkp-accent: #111827;
9
+ --zkp-brand: #2139a3;
10
+ --zkp-success: #16a34a;
11
+ --zkp-error: #dc2626;
12
+
13
+ all: revert;
14
+ position: relative;
15
+ box-sizing: border-box;
16
+ display: flex;
17
+ flex-direction: column;
18
+ width: 100%;
19
+ min-width: 280px;
20
+ max-width: 380px;
21
+ padding: 26px 20px 18px;
22
+ border: 1px solid var(--zkp-border);
23
+ border-radius: 14px;
24
+ background: var(--zkp-bg);
25
+ color: var(--zkp-fg);
26
+ font-family: ui-sans-serif, system-ui, sans-serif;
27
+ font-size: 14px;
28
+ line-height: 1.4;
29
+ }
30
+
31
+ .zkp-card[data-theme="dark"] {
32
+ --zkp-bg: #0f172a;
33
+ --zkp-fg: #f1f5f9;
34
+ --zkp-muted: #94a3b8;
35
+ --zkp-border: #334155;
36
+ --zkp-surface: #1e293b;
37
+ --zkp-accent: #f1f5f9;
38
+ --zkp-brand: #6b86d8;
39
+ --zkp-success: #4ade80;
40
+ --zkp-error: #f87171;
41
+ }
42
+
43
+ @media (prefers-color-scheme: dark) {
44
+ .zkp-card[data-theme="auto"] {
45
+ --zkp-bg: #0f172a;
46
+ --zkp-fg: #f1f5f9;
47
+ --zkp-muted: #94a3b8;
48
+ --zkp-border: #334155;
49
+ --zkp-surface: #1e293b;
50
+ --zkp-accent: #f1f5f9;
51
+ --zkp-brand: #6b86d8;
52
+ --zkp-success: #4ade80;
53
+ --zkp-error: #f87171;
54
+ }
55
+ }
56
+
57
+ .zkp-card * {
58
+ box-sizing: border-box;
59
+ }
60
+ .zkp-card button {
61
+ font: inherit;
62
+ cursor: pointer;
63
+ }
64
+
65
+ /* Header */
66
+ .zkp-header {
67
+ display: flex;
68
+ flex-direction: column;
69
+ align-items: center;
70
+ gap: 16px;
71
+ }
72
+ .zkp-header-icons {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ gap: 10px;
77
+ }
78
+ .zkp-zkp-icon,
79
+ .zkp-app-icon-slot {
80
+ flex: 0 0 auto;
81
+ height: 32px;
82
+ display: grid;
83
+ place-items: center;
84
+ }
85
+ .zkp-zkp-icon {
86
+ width: 32px;
87
+ }
88
+ .zkp-zkp-icon svg {
89
+ width: 100%;
90
+ height: 100%;
91
+ display: block;
92
+ }
93
+ .zkp-app-icon-slot {
94
+ max-width: 96px;
95
+ min-width: 32px;
96
+ }
97
+ .zkp-app-icon {
98
+ max-height: 100%;
99
+ max-width: 100%;
100
+ width: auto;
101
+ height: auto;
102
+ object-fit: contain;
103
+ display: block;
104
+ }
105
+ .zkp-header-dots {
106
+ display: flex;
107
+ gap: 4px;
108
+ }
109
+ .zkp-header-dots span {
110
+ width: 4px;
111
+ height: 4px;
112
+ border-radius: 50%;
113
+ background: var(--zkp-muted);
114
+ opacity: 0.5;
115
+ }
116
+ .zkp-title {
117
+ margin: 0;
118
+ text-align: center;
119
+ color: var(--zkp-muted);
120
+ font-size: 13px;
121
+ line-height: 1.45;
122
+ }
123
+ .zkp-title strong {
124
+ color: var(--zkp-fg);
125
+ font-weight: 600;
126
+ }
127
+
128
+ /* Restart button */
129
+ .zkp-restart {
130
+ position: absolute;
131
+ top: 6px;
132
+ right: 8px;
133
+ width: 24px;
134
+ height: 24px;
135
+ padding: 0;
136
+ border: 1px solid var(--zkp-border);
137
+ border-radius: 999px;
138
+ background: var(--zkp-bg);
139
+ color: var(--zkp-muted);
140
+ display: grid;
141
+ place-items: center;
142
+ transition:
143
+ color 120ms ease,
144
+ border-color 120ms ease;
145
+ }
146
+ .zkp-restart:hover {
147
+ color: var(--zkp-accent);
148
+ border-color: var(--zkp-accent);
149
+ }
150
+ .zkp-restart svg {
151
+ width: 14px;
152
+ height: 14px;
153
+ }
154
+
155
+ /* Dividers */
156
+ .zkp-divider {
157
+ height: 1px;
158
+ background: var(--zkp-border);
159
+ }
160
+ .zkp-divider-header {
161
+ margin: 16px 0 0;
162
+ }
163
+ .zkp-divider-top {
164
+ margin: 14px 0;
165
+ }
166
+ .zkp-divider-bottom {
167
+ margin: 10px 0 14px;
168
+ }
169
+
170
+ /* QR slot */
171
+ .zkp-qr-slot {
172
+ position: relative;
173
+ width: 100%;
174
+ aspect-ratio: 1;
175
+ margin: 16px 0 0;
176
+ background: var(--zkp-bg);
177
+ display: grid;
178
+ place-items: center;
179
+ overflow: hidden;
180
+ }
181
+ .zkp-qr {
182
+ width: 100%;
183
+ height: 100%;
184
+ color: black;
185
+ transition:
186
+ opacity 200ms ease,
187
+ transform 200ms ease;
188
+ }
189
+ .zkp-qr svg {
190
+ width: 100%;
191
+ height: 100%;
192
+ display: block;
193
+ }
194
+ .zkp-qr-logo {
195
+ position: absolute;
196
+ top: 50%;
197
+ left: 50%;
198
+ transform: translate(-50%, -50%);
199
+ width: 14%;
200
+ aspect-ratio: 1;
201
+ background: var(--zkp-bg);
202
+ padding: 3px;
203
+ border-radius: 50%;
204
+ display: grid;
205
+ place-items: center;
206
+ }
207
+ .zkp-qr-logo svg {
208
+ width: 100%;
209
+ height: 100%;
210
+ display: block;
211
+ }
212
+ .zkp-skeleton {
213
+ position: absolute;
214
+ inset: 0;
215
+ border-radius: 8px;
216
+ background: var(--zkp-surface);
217
+ }
218
+
219
+ /* QR slot state visibility */
220
+ .zkp-qr-slot[data-state="preparing"] .zkp-qr,
221
+ .zkp-qr-slot[data-state="preparing"] .zkp-qr-logo {
222
+ visibility: hidden;
223
+ }
224
+ .zkp-qr-slot[data-state="preparing"] .zkp-skeleton {
225
+ display: block;
226
+ }
227
+ .zkp-qr-slot:not([data-state="preparing"]) .zkp-skeleton {
228
+ display: none;
229
+ }
230
+ .zkp-qr-slot[data-state="connecting"] .zkp-qr,
231
+ .zkp-qr-slot[data-state="scanned"] .zkp-qr {
232
+ opacity: 0.65;
233
+ }
234
+ .zkp-qr-slot[data-state="generating"] .zkp-qr,
235
+ .zkp-qr-slot[data-state="success"] .zkp-qr,
236
+ .zkp-qr-slot[data-state="error"] .zkp-qr {
237
+ opacity: 0.35;
238
+ }
239
+ .zkp-qr-slot[data-state="generating"] .zkp-qr-logo,
240
+ .zkp-qr-slot[data-state="success"] .zkp-qr-logo,
241
+ .zkp-qr-slot[data-state="error"] .zkp-qr-logo {
242
+ opacity: 0;
243
+ }
244
+ .zkp-qr-slot[data-state="connecting"] .zkp-overlay,
245
+ .zkp-qr-slot[data-state="scanned"] .zkp-overlay,
246
+ .zkp-qr-slot[data-state="generating"] .zkp-overlay,
247
+ .zkp-qr-slot[data-state="success"] .zkp-overlay,
248
+ .zkp-qr-slot[data-state="error"] .zkp-overlay {
249
+ display: block;
250
+ }
251
+
252
+ /* Overlay */
253
+ .zkp-overlay {
254
+ position: absolute;
255
+ inset: 0;
256
+ display: none;
257
+ text-align: center;
258
+ background: color-mix(in srgb, var(--zkp-bg) 80%, transparent);
259
+ }
260
+ .zkp-overlay-body {
261
+ position: absolute;
262
+ top: 50%;
263
+ left: 50%;
264
+ transform: translate(-50%, -50%);
265
+ display: grid;
266
+ place-items: center;
267
+ }
268
+ .zkp-overlay-caption {
269
+ position: absolute;
270
+ top: calc(50% + 40px);
271
+ left: 8%;
272
+ right: 8%;
273
+ text-align: center;
274
+ color: var(--zkp-fg);
275
+ font-size: 14px;
276
+ font-weight: 500;
277
+ line-height: 1.4;
278
+ }
279
+
280
+ /* State icons */
281
+ .zkp-spinner {
282
+ width: 96px;
283
+ height: 96px;
284
+ color: var(--zkp-brand);
285
+ }
286
+ .zkp-spinner svg {
287
+ width: 100%;
288
+ height: 100%;
289
+ display: block;
290
+ }
291
+ .zkp-spinner-arc {
292
+ transform-origin: 50% 50%;
293
+ animation: zkp-spinner-rotate 1.4s linear infinite;
294
+ }
295
+ .zkp-scanned-phone {
296
+ width: 56px;
297
+ height: 56px;
298
+ border-radius: 50%;
299
+ background: #efefef;
300
+ color: var(--zkp-accent);
301
+ display: grid;
302
+ place-items: center;
303
+ animation: zkp-scanned-pulse 1.6s ease-in-out infinite;
304
+ }
305
+ .zkp-scanned-phone svg {
306
+ width: 28px;
307
+ height: 28px;
308
+ }
309
+ .zkp-check,
310
+ .zkp-error-icon {
311
+ width: 44px;
312
+ height: 44px;
313
+ border-radius: 50%;
314
+ color: #fff;
315
+ display: grid;
316
+ place-items: center;
317
+ animation: zkp-pop 220ms ease both;
318
+ }
319
+ .zkp-check {
320
+ background: var(--zkp-success);
321
+ }
322
+ .zkp-error-icon {
323
+ background: var(--zkp-error);
324
+ }
325
+ .zkp-check svg,
326
+ .zkp-error-icon svg {
327
+ width: 60%;
328
+ height: 60%;
329
+ }
330
+
331
+ /* Steps */
332
+ .zkp-steps {
333
+ display: flex;
334
+ flex-direction: column;
335
+ gap: 6px;
336
+ }
337
+ .zkp-step {
338
+ display: grid;
339
+ grid-template-columns: 28px 1fr;
340
+ column-gap: 10px;
341
+ align-items: center;
342
+ min-height: 28px;
343
+ transition: opacity 200ms ease;
344
+ }
345
+ .zkp-step-marker {
346
+ width: 20px;
347
+ height: 20px;
348
+ border-radius: 50%;
349
+ border: 2px solid var(--zkp-muted);
350
+ background: var(--zkp-surface);
351
+ color: transparent;
352
+ display: grid;
353
+ place-items: center;
354
+ justify-self: center;
355
+ align-self: center;
356
+ transition:
357
+ width 200ms ease,
358
+ height 200ms ease,
359
+ background 200ms ease,
360
+ border-color 200ms ease,
361
+ color 200ms ease;
362
+ }
363
+ .zkp-step-marker svg {
364
+ width: 12px;
365
+ height: 12px;
366
+ }
367
+ .zkp-step[data-status="done"] .zkp-step-marker {
368
+ background: var(--zkp-success);
369
+ border-color: var(--zkp-success);
370
+ color: #fff;
371
+ }
372
+ .zkp-step[data-status="current"] .zkp-step-marker {
373
+ border-color: var(--zkp-brand);
374
+ animation: zkp-step-pulse 1.4s ease-in-out infinite;
375
+ }
376
+ .zkp-step[data-mode="icon"] .zkp-step-marker {
377
+ width: 28px;
378
+ height: 28px;
379
+ border-radius: 7px;
380
+ border: 1px solid var(--zkp-border);
381
+ color: var(--zkp-fg);
382
+ animation: none;
383
+ }
384
+ .zkp-step[data-mode="icon"] .zkp-step-marker svg {
385
+ width: 14px;
386
+ height: 14px;
387
+ }
388
+ .zkp-step-text {
389
+ font-size: 13px;
390
+ color: var(--zkp-muted);
391
+ line-height: 1.4;
392
+ transition: color 200ms ease;
393
+ }
394
+ .zkp-step[data-status="current"] .zkp-step-text,
395
+ .zkp-step[data-status="pending"] .zkp-step-text {
396
+ color: var(--zkp-fg);
397
+ }
398
+ .zkp-step[data-status="current"] .zkp-step-text {
399
+ font-weight: 500;
400
+ }
401
+ .zkp-step-text a {
402
+ color: inherit;
403
+ text-decoration: underline;
404
+ font-weight: 600;
405
+ }
406
+
407
+ /* Collapse */
408
+ .zkp-collapse {
409
+ display: flex;
410
+ flex-direction: column;
411
+ gap: 6px;
412
+ height: auto;
413
+ transition: height 320ms ease;
414
+ }
415
+ .zkp-collapse-out {
416
+ height: 0;
417
+ overflow: hidden;
418
+ }
419
+
420
+ /* Open-in-app deep link (mobile only, waiting state) */
421
+ .zkp-open-app {
422
+ display: none;
423
+ margin: 16px 0 0;
424
+ padding: 12px 16px;
425
+ border-radius: 10px;
426
+ background: var(--zkp-accent);
427
+ color: var(--zkp-bg);
428
+ font-size: 15px;
429
+ font-weight: 600;
430
+ text-align: center;
431
+ text-decoration: none;
432
+ box-shadow: 0 4px 12px rgba(17, 24, 39, 0.18);
433
+ transition: transform 150ms ease;
434
+ }
435
+ .zkp-open-app:active {
436
+ transform: translateY(1px);
437
+ }
438
+ @media (hover: none) and (pointer: coarse) {
439
+ .zkp-card[data-state="waiting"] .zkp-open-app {
440
+ display: block;
441
+ }
442
+ }
443
+
444
+ /* Retry */
445
+ .zkp-result-actions {
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: center;
449
+ }
450
+ .zkp-result-actions:empty {
451
+ display: none;
452
+ }
453
+ .zkp-retry {
454
+ margin-top: 4px !important;
455
+ padding: 10px 20px !important;
456
+ border: none !important;
457
+ border-radius: 999px !important;
458
+ background: var(--zkp-accent) !important;
459
+ color: var(--zkp-bg) !important;
460
+ font-size: 14px !important;
461
+ font-weight: 600 !important;
462
+ line-height: 1.2 !important;
463
+ transition: transform 150ms ease;
464
+ }
465
+ .zkp-retry:active {
466
+ transform: translateY(1px);
467
+ }
468
+
469
+ /* Footer */
470
+ .zkp-footer {
471
+ display: flex;
472
+ align-items: center;
473
+ justify-content: space-between;
474
+ gap: 8px;
475
+ }
476
+ .zkp-footer-label {
477
+ font-size: 13px;
478
+ color: var(--zkp-muted);
479
+ }
480
+ .zkp-store-buttons {
481
+ display: flex;
482
+ align-items: center;
483
+ gap: 6px;
484
+ }
485
+ .zkp-store-button {
486
+ display: inline-flex;
487
+ text-decoration: none;
488
+ transition: transform 150ms ease;
489
+ }
490
+ .zkp-store-button:hover {
491
+ transform: translateY(-1px);
492
+ }
493
+ .zkp-store-button svg {
494
+ display: block;
495
+ height: 28px;
496
+ width: auto;
497
+ }
498
+
499
+ /* Keyframes */
500
+ @keyframes zkp-spinner-rotate {
501
+ to {
502
+ transform: rotate(360deg);
503
+ }
504
+ }
505
+ @keyframes zkp-pop {
506
+ from {
507
+ transform: scale(0.6);
508
+ opacity: 0;
509
+ }
510
+ to {
511
+ transform: scale(1);
512
+ opacity: 1;
513
+ }
514
+ }
515
+ @keyframes zkp-scanned-pulse {
516
+ 0%,
517
+ 100% {
518
+ transform: scale(1);
519
+ }
520
+ 50% {
521
+ transform: scale(1.08);
522
+ }
523
+ }
524
+ @keyframes zkp-step-pulse {
525
+ 0%,
526
+ 100% {
527
+ transform: scale(1);
528
+ }
529
+ 50% {
530
+ transform: scale(1.08);
531
+ }
532
+ }
533
+
534
+ /* Reduced motion */
535
+ @media (prefers-reduced-motion: reduce) {
536
+ .zkp-qr {
537
+ transition: none;
538
+ }
539
+ .zkp-spinner-arc {
540
+ animation-duration: 3.5s;
541
+ }
542
+ .zkp-scanned-phone,
543
+ .zkp-check,
544
+ .zkp-error-icon {
545
+ animation: none;
546
+ }
547
+ }
548
+ }
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@zkpassport/ui",
3
+ "version": "0.14.2",
4
+ "description": "Drop-in QR verification card for ZKPassport. Vanilla JS by default; React component available at @zkpassport/ui/react.",
5
+ "author": "ZKPassport",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/zkpassport/zkpassport-packages",
10
+ "directory": "packages/zkpassport-ui"
11
+ },
12
+ "type": "module",
13
+ "main": "./dist/cjs/index.cjs",
14
+ "module": "./dist/esm/index.js",
15
+ "types": "./dist/esm/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": {
19
+ "types": "./dist/esm/index.d.ts",
20
+ "default": "./dist/esm/index.js"
21
+ },
22
+ "require": {
23
+ "types": "./dist/cjs/index.d.cts",
24
+ "default": "./dist/cjs/index.cjs"
25
+ }
26
+ },
27
+ "./react": {
28
+ "import": {
29
+ "types": "./dist/esm/react.d.ts",
30
+ "default": "./dist/esm/react.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/cjs/react.d.cts",
34
+ "default": "./dist/cjs/react.cjs"
35
+ }
36
+ },
37
+ "./styles.css": "./dist/styles.css"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup --config tsup.config.ts",
41
+ "dev:build": "DEV_BUILD=true bun run build",
42
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
43
+ "test": "echo 'no tests yet'",
44
+ "check": "tsc --noEmit && prettier -c src && eslint src --ext .ts,.tsx",
45
+ "format": "prettier -c -w src && eslint src --ext .ts,.tsx --fix",
46
+ "validate-package": "../../scripts/validate-package.sh --exclude-entrypoints ./styles.css",
47
+ "prepublishOnly": "../../scripts/prepublish.sh"
48
+ },
49
+ "files": [
50
+ "dist"
51
+ ],
52
+ "sideEffects": [
53
+ "*.css"
54
+ ],
55
+ "keywords": [
56
+ "zkpassport",
57
+ "zkpassport-ui",
58
+ "ui",
59
+ "react",
60
+ "qrcode",
61
+ "verification",
62
+ "widget"
63
+ ],
64
+ "dependencies": {
65
+ "qrcode": "^1.5.4"
66
+ },
67
+ "peerDependencies": {
68
+ "@zkpassport/sdk": "^0.14.2",
69
+ "react": ">=18",
70
+ "react-dom": ">=18",
71
+ "typescript": "^5.0.0"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "react": {
75
+ "optional": true
76
+ },
77
+ "react-dom": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "devDependencies": {
82
+ "@types/qrcode": "^1.5.5",
83
+ "@types/react": "^18.3.0",
84
+ "@types/react-dom": "^18.3.0",
85
+ "@zkpassport/sdk": "0.14.2",
86
+ "preact": "^10.22.0",
87
+ "react": "^18.3.0",
88
+ "react-dom": "^18.3.0"
89
+ },
90
+ "packageManager": "bun@1.3.1"
91
+ }