1import { createSignal, onMount, onCleanup } from 'solid-js';23interface PasskeyToastProps {4 site: string;5 displayName: string;6 username: string;7 requestId: string;8 onSignIn: () => void;9 onDeny: () => void;10}1112const TIMEOUT_MS = 30_000;1314export function PasskeyToast(props: PasskeyToastProps) {15 const [visible, setVisible] = createSignal(false);16 const [exiting, setExiting] = createSignal(false);17 let timeoutId: number;1819 onMount(() => {20 requestAnimationFrame(() => setVisible(true));2122 timeoutId = window.setTimeout(() => {23 handleDeny();24 }, TIMEOUT_MS);25 });2627 onCleanup(() => {28 clearTimeout(timeoutId);29 });3031 function handleSignIn() {32 clearTimeout(timeoutId);33 exit(props.onSignIn);34 }3536 function handleDeny() {37 clearTimeout(timeoutId);38 exit(props.onDeny);39 }4041 function exit(callback: () => void) {42 setExiting(true);43 setTimeout(callback, 220);44 }4546 47 48 return (49 <div50 class={[51 'peach-passkey-toast',52 visible() ? 'is-visible' : '',53 exiting() ? 'is-exiting' : '',54 ].join(' ')}55 >56 <div class="peach-passkey-toast-body">57 <h2 class="peach-passkey-toast-headline">58 sign in to {props.site}?59 </h2>6061 <div class="peach-passkey-toast-user">62 {props.displayName} · {props.username}63 </div>6465 <div class="peach-passkey-toast-countdown">66 <div67 class="peach-passkey-toast-countdown-bar"68 style={{ 'animation-duration': `${TIMEOUT_MS}ms` }}69 />70 </div>7172 <div class="peach-passkey-toast-actions">73 <button74 class="peach-passkey-toast-btn peach-passkey-toast-btn--deny"75 on:click={handleDeny}76 >77 deny78 </button>79 <button80 class="peach-passkey-toast-btn peach-passkey-toast-btn--signin"81 on:click={handleSignIn}82 >83 sign in84 </button>85 </div>86 </div>87 </div>88 );89}90