@mrgnw/anahtar 0.0.17 → 0.0.19
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.
|
@@ -15,6 +15,7 @@ interface PasskeyInfo {
|
|
|
15
15
|
interface Props {
|
|
16
16
|
apiBase?: string;
|
|
17
17
|
user?: { email: string } | null;
|
|
18
|
+
compact?: boolean;
|
|
18
19
|
locale?: string;
|
|
19
20
|
messages?: Partial<AuthMessages>;
|
|
20
21
|
onSuccess?: () => void | Promise<void>;
|
|
@@ -26,6 +27,7 @@ interface Props {
|
|
|
26
27
|
let {
|
|
27
28
|
apiBase = '/api/auth',
|
|
28
29
|
user = null,
|
|
30
|
+
compact = false,
|
|
29
31
|
locale,
|
|
30
32
|
messages: messageOverrides,
|
|
31
33
|
onSuccess,
|
|
@@ -34,6 +36,8 @@ let {
|
|
|
34
36
|
getPasskeys,
|
|
35
37
|
}: Props = $props();
|
|
36
38
|
|
|
39
|
+
let expanded = $state(false);
|
|
40
|
+
|
|
37
41
|
let m = $derived(resolveMessages(locale ?? detectLocaleClient(), messageOverrides));
|
|
38
42
|
|
|
39
43
|
let email = $state('');
|
|
@@ -43,17 +47,26 @@ let otpStep = $state(false);
|
|
|
43
47
|
let otpDigits = $state<string[]>(['', '', '', '', '']);
|
|
44
48
|
let otpInputs = $state<HTMLInputElement[]>([]);
|
|
45
49
|
let showPasskeys = $state(false);
|
|
50
|
+
let isTouch = $state(false);
|
|
46
51
|
let hoveredKey = $state<string | null>(null);
|
|
47
52
|
let passkeyRefresh = $state(0);
|
|
48
53
|
let passkeyOnboarding = $state(false);
|
|
49
54
|
let conditionalAbort: AbortController | null = null;
|
|
50
55
|
|
|
51
56
|
const isAuthenticated = $derived(!!user);
|
|
57
|
+
|
|
58
|
+
function shortDate(ts?: number): string {
|
|
59
|
+
if (!ts) return '';
|
|
60
|
+
const d = new Date(ts);
|
|
61
|
+
const mon = d.toLocaleDateString(undefined, { month: 'short' });
|
|
62
|
+
return `${mon} ${d.getFullYear()}`;
|
|
63
|
+
}
|
|
52
64
|
const passkeyPromise = $derived(
|
|
53
65
|
isAuthenticated && getPasskeys && passkeyRefresh >= 0 ? getPasskeys() : null
|
|
54
66
|
);
|
|
55
67
|
|
|
56
68
|
onMount(() => {
|
|
69
|
+
isTouch = matchMedia('(pointer: coarse)').matches;
|
|
57
70
|
if (!isAuthenticated) tryConditionalWebAuthn();
|
|
58
71
|
return () => conditionalAbort?.abort();
|
|
59
72
|
});
|
|
@@ -63,6 +76,7 @@ async function handleSignOut() {
|
|
|
63
76
|
otpStep = false;
|
|
64
77
|
passkeyOnboarding = false;
|
|
65
78
|
showPasskeys = false;
|
|
79
|
+
expanded = false;
|
|
66
80
|
error = '';
|
|
67
81
|
await onSignOut?.();
|
|
68
82
|
}
|
|
@@ -304,7 +318,13 @@ async function removePasskey(id: string) {
|
|
|
304
318
|
|
|
305
319
|
<div class="anahtar-pill-island" class:anahtar-pill-loading={loading}>
|
|
306
320
|
<div class="anahtar-pill">
|
|
307
|
-
{#if isAuthenticated}
|
|
321
|
+
{#if isAuthenticated && compact && !expanded}
|
|
322
|
+
<button class="anahtar-pill-icon" onclick={() => (expanded = true)} title={user?.email}>
|
|
323
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
324
|
+
<circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/>
|
|
325
|
+
</svg>
|
|
326
|
+
</button>
|
|
327
|
+
{:else if isAuthenticated}
|
|
308
328
|
<span class="anahtar-pill-email">{user?.email}</span>
|
|
309
329
|
<span class="anahtar-pill-sep">·</span>
|
|
310
330
|
{#if getPasskeys}
|
|
@@ -326,6 +346,14 @@ async function removePasskey(id: string) {
|
|
|
326
346
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/>
|
|
327
347
|
</svg>
|
|
328
348
|
</button>
|
|
349
|
+
{#if compact}
|
|
350
|
+
<span class="anahtar-pill-sep">·</span>
|
|
351
|
+
<button class="anahtar-pill-icon" onclick={() => { expanded = false; showPasskeys = false; }} title="Collapse">
|
|
352
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
353
|
+
<line x1="18" x2="6" y1="6" y2="18"/><line x1="6" x2="18" y1="6" y2="18"/>
|
|
354
|
+
</svg>
|
|
355
|
+
</button>
|
|
356
|
+
{/if}
|
|
329
357
|
|
|
330
358
|
{:else if otpStep}
|
|
331
359
|
<span class="anahtar-pill-otp-label">{email}</span>
|
|
@@ -390,7 +418,7 @@ async function removePasskey(id: string) {
|
|
|
390
418
|
{#await passkeyPromise then keys}
|
|
391
419
|
{#each keys as key}
|
|
392
420
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
393
|
-
|
|
421
|
+
<div
|
|
394
422
|
class="anahtar-pill-key-row"
|
|
395
423
|
onmouseenter={() => (hoveredKey = key.id)}
|
|
396
424
|
onmouseleave={() => (hoveredKey = null)}
|
|
@@ -399,7 +427,10 @@ async function removePasskey(id: string) {
|
|
|
399
427
|
<circle cx="7.5" cy="15.5" r="5.5"/><path d="m11.5 12 4-4"/><path d="m15 7 2 2"/><path d="m17.5 4.5 2 2"/>
|
|
400
428
|
</svg>
|
|
401
429
|
<span class="anahtar-pill-key-name">{key.name ?? 'Passkey'}</span>
|
|
402
|
-
{#if
|
|
430
|
+
{#if key.createdAt}
|
|
431
|
+
<span class="anahtar-pill-key-date">{shortDate(key.createdAt)}</span>
|
|
432
|
+
{/if}
|
|
433
|
+
{#if isTouch || hoveredKey === key.id}
|
|
403
434
|
<button
|
|
404
435
|
class="anahtar-pill-key-remove"
|
|
405
436
|
onclick={() => removePasskey(key.id)}
|
|
@@ -414,7 +445,7 @@ async function removePasskey(id: string) {
|
|
|
414
445
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
415
446
|
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
|
|
416
447
|
</svg>
|
|
417
|
-
Add
|
|
448
|
+
Add
|
|
418
449
|
</button>
|
|
419
450
|
</div>
|
|
420
451
|
{/if}
|
|
@@ -588,21 +619,21 @@ async function removePasskey(id: string) {
|
|
|
588
619
|
backdrop-filter: blur(8px);
|
|
589
620
|
border: 1px solid var(--anahtar-pill-border, rgba(0,0,0,0.06));
|
|
590
621
|
border-radius: 0.75rem;
|
|
591
|
-
padding: 0.
|
|
622
|
+
padding: 0.375rem 0.625rem;
|
|
592
623
|
box-shadow: var(--anahtar-pill-shadow, 0 2px 12px rgba(0,0,0,0.08));
|
|
593
624
|
display: flex;
|
|
594
625
|
flex-direction: column;
|
|
595
|
-
gap: 0.
|
|
596
|
-
min-width:
|
|
626
|
+
gap: 0.125rem;
|
|
627
|
+
min-width: 160px;
|
|
597
628
|
}
|
|
598
629
|
|
|
599
630
|
.anahtar-pill-key-row {
|
|
600
631
|
display: flex;
|
|
601
632
|
align-items: center;
|
|
602
|
-
gap: 0.
|
|
603
|
-
font-size: 0.
|
|
633
|
+
gap: 0.3rem;
|
|
634
|
+
font-size: 0.75rem;
|
|
604
635
|
color: var(--anahtar-pill-fg, #374151);
|
|
605
|
-
padding: 0.
|
|
636
|
+
padding: 0.15rem 0;
|
|
606
637
|
}
|
|
607
638
|
|
|
608
639
|
.anahtar-pill-key-name {
|
|
@@ -612,12 +643,18 @@ async function removePasskey(id: string) {
|
|
|
612
643
|
white-space: nowrap;
|
|
613
644
|
}
|
|
614
645
|
|
|
646
|
+
.anahtar-pill-key-date {
|
|
647
|
+
font-size: 0.6875rem;
|
|
648
|
+
color: var(--anahtar-pill-icon, #9ca3af);
|
|
649
|
+
white-space: nowrap;
|
|
650
|
+
}
|
|
651
|
+
|
|
615
652
|
.anahtar-pill-key-remove {
|
|
616
653
|
background: none;
|
|
617
654
|
border: none;
|
|
618
655
|
color: var(--anahtar-pill-icon, #9ca3af);
|
|
619
656
|
cursor: pointer;
|
|
620
|
-
font-size:
|
|
657
|
+
font-size: 0.875rem;
|
|
621
658
|
line-height: 1;
|
|
622
659
|
padding: 0 0.125rem;
|
|
623
660
|
transition: color 0.15s;
|
|
@@ -628,15 +665,14 @@ async function removePasskey(id: string) {
|
|
|
628
665
|
.anahtar-pill-key-add {
|
|
629
666
|
display: flex;
|
|
630
667
|
align-items: center;
|
|
631
|
-
gap: 0.
|
|
632
|
-
font-size: 0.
|
|
668
|
+
gap: 0.25rem;
|
|
669
|
+
font-size: 0.6875rem;
|
|
633
670
|
color: var(--anahtar-pill-icon, #6b7280);
|
|
634
671
|
background: none;
|
|
635
672
|
border: none;
|
|
636
673
|
cursor: pointer;
|
|
637
|
-
padding: 0.
|
|
674
|
+
padding: 0.15rem 0;
|
|
638
675
|
transition: color 0.15s;
|
|
639
|
-
margin-top: 0.125rem;
|
|
640
676
|
}
|
|
641
677
|
.anahtar-pill-key-add:hover:not(:disabled) { color: var(--anahtar-primary, #3730a3); }
|
|
642
678
|
.anahtar-pill-key-add:disabled { opacity: 0.4; cursor: not-allowed; }
|