release: WRNexusJS 0.5.0

This commit is contained in:
2026-07-29 12:51:10 +05:30
parent 76c768099d
commit 6afe32f63f
456 changed files with 40879 additions and 8850 deletions
@@ -0,0 +1,11 @@
component AccountStatus {
props { status = "active" title = "Account status" activeMessage = "Your account is active and ready to use." pendingMessage = "Verify your contact details to activate your account." lockedMessage = "Your account is temporarily locked for security." disabledMessage = "Your account has been disabled." supportHref = "/support" color = "primary" size = "md" class = "" }
view {
<section {...attrs} data-status='{status}' class='w-full max-w-lg rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-center {class}'>
<span class='mx-auto flex size-14 items-center justify-center rounded-full bg-[var(--wire-color-surface-2)] text-[var(--wire-color-primary)] data-[status=locked]:text-[var(--wire-color-warning)] data-[status=disabled]:text-[var(--wire-color-danger)]'>{#if status == "active"}<span class="icon-[lucide--circle-check] size-7"></span>{:else if status == "pending"}<span class="icon-[lucide--clock-3] size-7"></span>{:else}<span class="icon-[lucide--shield-alert] size-7"></span>{/if}</span>
<h1 class="mb-0 mt-4 text-2xl font-semibold">{title}</h1>
<p class="mx-auto mt-2 max-w-md text-sm text-[var(--wire-color-muted)]">{status == "active" ? activeMessage : status == "pending" ? pendingMessage : status == "locked" ? lockedMessage : disabledMessage}</p>
{#if status != "active"}<a href='{supportHref}' class="mt-4 inline-flex h-10 items-center justify-center rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white">Contact support</a>{/if}
</section>
}
}
@@ -0,0 +1,69 @@
component AuthenticatorSetup {
props {
setupAction = "/api/auth/totp/setup"
setupSchema = "auth-authenticator-setup"
action = "/api/auth/totp/confirm"
schema = "auth-authenticator-confirm"
credentialId = ""
secret = ""
uri = ""
title = "Set up an authenticator"
description = "Create a setup key, add it to your authenticator app, then enter a current code."
setupLabel = "Create setup key"
submitLabel = "Enable authenticator"
successMessage = "Authenticator enabled."
color = "primary"
size = "md"
class = ""
}
view {
<section
{...attrs}
data-wrnexus-runtime="auth"
data-auth-authenticator-setup
class='w-full max-w-lg rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] {class}'
>
<div class="flex items-start gap-4">
<span class="flex size-11 shrink-0 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]"><span class="icon-[lucide--scan-line] size-5"></span></span>
<div><h1 class="m-0 text-xl font-semibold">{title}</h1><p class="mb-0 mt-1 text-sm text-[var(--wire-color-muted)]">{description}</p></div>
</div>
<form
method="post"
action='{setupAction}'
data-schema='{setupSchema}'
data-auth-authenticator-start
novalidate
class='mt-5 space-y-4 {credentialId == "" ? "" : "hidden"}'
>
<div class="space-y-1.5">
<label for="auth-authenticator-label" class="block text-sm font-medium">Authenticator name</label>
<input id="auth-authenticator-label" name="label" value="Authenticator" autocomplete="off" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3" />
<p data-error="label" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] text-sm font-semibold text-white disabled:opacity-60">{setupLabel}</button>
</form>
<div data-auth-authenticator-details class='{credentialId == "" ? "hidden" : ""}'>
<div class="mt-5 rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-surface-2)] p-4">
<p class="m-0 text-xs font-semibold uppercase tracking-wide text-[var(--wire-color-muted)]">Manual setup key</p>
<code data-auth-authenticator-secret class="mt-2 block break-all text-sm font-semibold tracking-wider">{secret}</code>
<code data-auth-authenticator-uri class="mt-3 block max-h-24 overflow-auto break-all text-xs text-[var(--wire-color-muted)]">{uri}</code>
</div>
<form method="post" action='{action}' data-schema='{schema}' data-auth-authenticator-confirm novalidate class="mt-5 space-y-4">
<input type="hidden" name="credentialId" value='{credentialId}' />
<div class="space-y-1.5">
<label for="auth-authenticator-code" class="block text-sm font-medium">Authenticator code</label>
<input id="auth-authenticator-code" name="code" inputmode="numeric" autocomplete="one-time-code" maxlength="6" class="h-12 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-center text-xl tracking-[0.35em]" />
<p data-error="code" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="credentialId" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] text-sm font-semibold text-white disabled:opacity-60">{submitLabel}</button>
</form>
</div>
</section>
}
}
@@ -0,0 +1,40 @@
component DeviceSessions {
props {
sessions = []
currentSessionId = ""
title = "Active sessions"
description = "Review devices signed in to your account."
revokeAction = "/api/auth/sessions/revoke"
revokeSchema = "auth-session-revoke"
revokeLabel = "Sign out"
successMessage = "Session revoked."
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-2xl rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] {class}'>
<h2 class="m-0 text-xl font-semibold">{title}</h2>
<p class="mt-1 text-sm text-[var(--wire-color-muted)]">{description}</p>
<div class="mt-5 divide-y divide-[var(--wire-color-border)]">
{#each sessions as session}
<article class="flex items-center gap-3 py-4">
<span class="flex size-10 items-center justify-center rounded-full bg-[var(--wire-color-surface-2)]"><span class="icon-[lucide--monitor-smartphone] size-5"></span></span>
<div class="min-w-0 flex-1"><p class="m-0 truncate text-sm font-semibold">{session.userAgent || "Unknown device"}</p><p class="m-0 mt-1 text-xs text-[var(--wire-color-muted)]">{session.ip || "Unknown IP"} · Last active {session.lastSeenAt}</p></div>
{#if session.id == currentSessionId}
<span class="rounded-full bg-[color-mix(in_srgb,var(--wire-color-success)_12%,transparent)] px-2 py-1 text-xs font-semibold text-[var(--wire-color-success)]">Current</span>
{:else}
<form method="post" action='{revokeAction}' data-schema='{revokeSchema}' novalidate>
<input type="hidden" name="sessionId" value='{session.id}' />
<p data-error="sessionId" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 text-xs text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="text-sm font-semibold text-[var(--wire-color-danger)] disabled:opacity-60">{revokeLabel}</button>
</form>
{/if}
</article>
{/each}
</div>
</section>
}
}
@@ -0,0 +1,32 @@
component ForgotPassword {
props {
action = "/api/auth/password/request"
schema = "auth-password-request"
title = "Recover your account"
description = "Enter your email, phone, or username."
identifierLabel = "Account identifier"
submitLabel = "Send recovery link"
successMessage = "If an account matches, a recovery link has been sent."
signInHref = "/sign-in"
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' novalidate class="mt-6 space-y-4">
<div class="space-y-1.5">
<label for="auth-recovery-identifier" class="block text-sm font-medium">{identifierLabel}</label>
<input id="auth-recovery-identifier" name="identifier" autocomplete="username" aria-describedby="auth-recovery-identifier-error" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-sm outline-none focus:border-[var(--wire-color-primary)]" />
<p id="auth-recovery-identifier-error" data-error="identifier" role="alert" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
<a href='{signInHref}' class="mt-4 inline-flex text-sm text-[var(--wire-color-primary)] hover:underline">Back to sign in</a>
</section>
}
}
@@ -0,0 +1,22 @@
component ImpersonationBanner {
props {
visible = true
targetName = "this user"
stopAction = "/api/auth/impersonation/stop"
stopSchema = "auth-empty"
redirect = "/account"
message = "You are viewing the application as"
stopLabel = "Stop impersonating"
color = "warning"
size = "md"
class = ""
}
view {
{#if visible}
<aside {...attrs} data-wrnexus-runtime="auth" role="status" class='flex w-full flex-wrap items-center justify-between gap-3 border-b border-[var(--wire-color-warning)] bg-[color-mix(in_srgb,var(--wire-color-warning)_14%,var(--wire-color-surface))] px-4 py-2 text-sm text-[var(--wire-color-text)] {class}'>
<span class="flex items-center gap-2"><span class="icon-[lucide--scan-face] size-4 text-[var(--wire-color-warning)]"></span><span>{message} <strong>{targetName}</strong>.</span></span>
<form method="post" action='{stopAction}' data-schema='{stopSchema}' data-redirect='{redirect}' novalidate><p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p><button type="submit" class="inline-flex h-8 items-center rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-warning)] px-3 text-xs font-semibold text-black disabled:opacity-60">{stopLabel}</button></form>
</aside>
{/if}
}
}
@@ -0,0 +1,34 @@
component InvitationAccept {
props {
action = "/api/auth/invitations/accept"
schema = "auth-invitation"
token = ""
redirect = "/account"
organization = "your workspace"
inviter = "A workspace administrator"
title = "Accept your invitation"
description = "Create your password to join the workspace."
submitLabel = "Accept invitation"
successMessage = "Invitation accepted."
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<span class="flex size-11 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]"><span class="icon-[lucide--user-round-plus] size-5"></span></span>
<h1 class="mb-0 mt-4 text-2xl font-semibold">{title}</h1>
<p class="mb-0 mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<div class="mt-5 rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] p-4 text-sm"><p class="m-0 font-semibold">{organization}</p><p class="mb-0 mt-1 text-[var(--wire-color-muted)]">Invited by {inviter}</p></div>
<form method="post" action='{action}' data-schema='{schema}' data-redirect='{redirect}' novalidate class="mt-5 space-y-4">
<input type="hidden" name="token" value='{token}' />
<div class="space-y-1.5"><label for="auth-invitation-name" class="block text-sm font-medium">Display name</label><input id="auth-invitation-name" name="displayName" autocomplete="name" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3" /><p data-error="displayName" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p></div>
<div class="space-y-1.5"><label for="auth-invitation-password" class="block text-sm font-medium">Create password</label><input id="auth-invitation-password" name="password" type="password" autocomplete="new-password" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3" /><p data-error="password" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p></div>
<p data-error="token" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] text-sm font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
</section>
}
}
@@ -0,0 +1,29 @@
component MagicLinkSignIn {
props {
action = "/api/auth/magic-link/request"
schema = "auth-magic-link-request"
title = "Email me a sign-in link"
description = "Receive a secure, single-use link that expires automatically."
emailLabel = "Email address"
submitLabel = "Send sign-in link"
successMessage = "If an account matches, a sign-in link has been sent."
signInHref = "/sign-in"
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<div class="mb-5 flex size-11 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]"><span class="icon-[lucide--mail-check] size-5"></span></div>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mb-0 mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' novalidate class="mt-6 space-y-4">
<div class="space-y-1.5"><label for="auth-magic-link-identifier" class="block text-sm font-medium">{emailLabel}</label><input id="auth-magic-link-identifier" name="identifier" type="email" autocomplete="email" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-sm outline-none focus:border-[var(--wire-color-primary)]" /><p data-error="identifier" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p></div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
<a href='{signInHref}' class="mt-4 inline-flex text-sm font-medium text-[var(--wire-color-primary)] hover:underline">Return to password sign-in</a>
</section>
}
}
+77
View File
@@ -0,0 +1,77 @@
component OtpSignIn {
props {
requestAction = "/api/auth/otp/login/request"
requestSchema = "auth-otp-login-request"
completeAction = "/api/auth/otp/login/complete"
completeSchema = "auth-otp-login-complete"
challengeId = ""
returnTo = "/"
mfaHref = "/two-factor"
method = "email-otp"
title = "Sign in with a code"
description = "We will send a one-time code to your email address or phone number."
identifierLabel = "Email address or phone number"
requestLabel = "Send code"
verifyLabel = "Verify and sign in"
successMessage = "A one-time code has been sent."
color = "primary"
size = "md"
class = ""
}
view {
<section
{...attrs}
data-wrnexus-runtime="auth"
data-auth-otp-sign-in
data-mfa-href='{mfaHref}'
class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'
>
<div class="mb-5 flex size-11 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]">
<span class="icon-[lucide--key-round] size-5"></span>
</div>
<h1 class="m-0 text-2xl font-semibold tracking-tight">{title}</h1>
<p class="mb-0 mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form
method="post"
action='{requestAction}'
data-schema='{requestSchema}'
data-auth-otp-request
novalidate
class='mt-6 space-y-4 {challengeId == "" ? "" : "hidden"}'
>
<input type="hidden" name="method" value='{method}' />
<div class="space-y-1.5">
<label for="auth-otp-identifier" class="block text-sm font-medium">{identifierLabel}</label>
<input id="auth-otp-identifier" name="identifier" type="text" autocomplete="username" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-sm outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="identifier" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="method" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white disabled:cursor-wait disabled:opacity-60">{requestLabel}</button>
</form>
<form
method="post"
action='{completeAction}'
data-schema='{completeSchema}'
data-auth-otp-complete
novalidate
class='mt-6 space-y-4 {challengeId == "" ? "hidden" : ""}'
>
<input type="hidden" name="challengeId" value='{challengeId}' />
<input type="hidden" name="returnTo" value='{returnTo}' />
<div class="space-y-1.5">
<label for="auth-otp-code" class="block text-sm font-medium">One-time code</label>
<input id="auth-otp-code" name="code" inputmode="numeric" autocomplete="one-time-code" maxlength="6" class="h-12 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-center text-xl tracking-[0.35em] outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="code" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="challengeId" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white disabled:cursor-wait disabled:opacity-60">{verifyLabel}</button>
<button type="button" data-auth-otp-back class="w-full text-sm text-[var(--wire-color-primary)] hover:underline">Use a different account</button>
</form>
</section>
}
}
@@ -0,0 +1,34 @@
component PasskeyButton {
props {
mode = "authenticate"
label = "Continue with a passkey"
registerLabel = "Add a passkey"
identifier = ""
rpId = ""
rpName = "WRNexusJS"
passkeyName = "Passkey"
optionsEndpoint = ""
verifyEndpoint = ""
redirect = ""
mfaHref = "/two-factor"
conditional = false
fullWidth = false
loadingMessage = "Waiting for your passkey…"
successMessage = "Passkey verified."
color = "primary"
size = "md"
class = ""
@event passkeyRegistered = function
@event passkeyAuthenticated = function
@event error = function
}
view {
<div {...attrs} data-wrnexus-runtime="auth" data-auth-passkey='{mode}' data-identifier='{identifier}' data-rp-id='{rpId}' data-rp-name='{rpName}' data-passkey-name='{passkeyName}' data-options-endpoint='{optionsEndpoint}' data-verify-endpoint='{verifyEndpoint}' data-redirect='{redirect}' data-mfa-href='{mfaHref}' data-conditional='{conditional}' data-loading-message='{loadingMessage}' data-success-message='{successMessage}' data-auth-state="idle" aria-busy="false" class='space-y-2 {class}'>
<button type="button" class='inline-flex h-11 items-center justify-center gap-2 rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] px-4 text-sm font-semibold text-[var(--wire-color-text)] hover:bg-[var(--wire-color-surface-2)] disabled:cursor-wait disabled:opacity-60 {fullWidth ? "w-full" : ""}'>
<span aria-hidden="true" class="icon-[lucide--key-round] size-4"></span>
{mode == "register" ? registerLabel : label}
</button>
<p data-auth-status hidden role="status" class="m-0 text-xs text-[var(--wire-color-muted)]"></p>
</div>
}
}
@@ -0,0 +1,86 @@
component RecoveryCodes {
props {
codes = []
schema = "auth-recovery-codes"
title = "Recovery codes"
description = "Store these codes somewhere safe. Each code can be used once."
downloadLabel = "Download codes"
regenerateLabel = "Generate new codes"
regenerateAction = "/api/auth/recovery-codes"
successMessage = "New recovery codes generated. Previous unused codes are no longer valid."
count = 10
color = "primary"
size = "md"
class = ""
}
view {
<section
{...attrs}
data-wrnexus-runtime="auth"
data-auth-recovery-codes
data-recovery-filename="wrnexus-recovery-codes.txt"
class='w-full max-w-xl rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 {class}'
>
<div class="flex items-start justify-between gap-4">
<div>
<h2 class="m-0 text-xl font-semibold">{title}</h2>
<p class="mt-1 text-sm text-[var(--wire-color-muted)]">{description}</p>
</div>
<span class="icon-[lucide--shield-keyhole] size-6 text-[var(--wire-color-primary)]"></span>
</div>
<div
data-recovery-code-list
class="mt-5 grid grid-cols-2 gap-2 rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-surface-2)] p-4 font-mono text-sm sm:grid-cols-3"
>
{#each codes as code}
<code
data-recovery-code
class="rounded bg-[var(--wire-color-surface)] px-2 py-1.5 text-center"
>{code}</code>
{/each}
</div>
<div class="mt-4 flex flex-wrap gap-2">
<button
type="button"
data-recovery-download
class="h-10 rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] px-4 text-sm font-semibold"
>
{downloadLabel}
</button>
<form
method="post"
action='{regenerateAction}'
data-schema='{schema}'
novalidate
class="flex-1"
>
<input type="hidden" name="count" value='{count}' />
<p data-error="count" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p
data-error="_form"
role="alert"
class="m-0 hidden text-xs text-[var(--wire-color-danger)]"
></p>
<p
data-success='{successMessage}'
role="status"
hidden
class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-xs text-[var(--wire-color-success)]"
>
{successMessage}
</p>
<button
type="submit"
class="h-10 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] px-4 text-sm font-semibold disabled:cursor-wait disabled:opacity-60"
>
{regenerateLabel}
</button>
</form>
</div>
</section>
}
}
@@ -0,0 +1,34 @@
component ResetPassword {
props {
action = "/api/auth/password/reset"
schema = "auth-password-reset"
token = ""
redirect = "/sign-in"
title = "Set a new password"
description = "Choose a strong password you have not used before."
submitLabel = "Reset password"
successMessage = "Your password has been reset."
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' data-redirect='{redirect}' novalidate class="mt-6 space-y-4">
<input type="hidden" name="token" value='{token}' />
<div class="space-y-1.5">
<label for="auth-reset-password" class="block text-sm font-medium">New password</label>
<input id="auth-reset-password" name="password" type="password" autocomplete="new-password" aria-describedby="auth-reset-password-error" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p class="m-0 text-xs text-[var(--wire-color-muted)]">At least 12 characters with uppercase, lowercase, and a number.</p>
<p id="auth-reset-password-error" data-error="password" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-error="token" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
</section>
}
}
+58
View File
@@ -0,0 +1,58 @@
component SignIn {
props {
action = "/api/auth/login"
schema = "auth-login"
returnTo = "/"
redirect = ""
mfaHref = "/two-factor"
title = "Welcome back"
description = "Sign in to continue to your account."
identifierLabel = "Email, phone, or username"
passwordLabel = "Password"
submitLabel = "Sign in"
forgotHref = "/recover"
signUpHref = "/sign-up"
showRemember = true
showPasskey = true
showSignUp = true
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" data-auth-sign-in data-mfa-href='{mfaHref}' class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<header class="mb-6 space-y-1.5">
<h1 class="m-0 text-2xl font-semibold tracking-tight">{title}</h1>
<p class="m-0 text-sm text-[var(--wire-color-muted)]">{description}</p>
</header>
<form method="post" action='{action}' data-schema='{schema}' data-redirect='{redirect}' novalidate class="space-y-4">
<input type="hidden" name="returnTo" value='{returnTo}' />
<input type="hidden" name="deviceFingerprint" value="" />
<input type="hidden" name="deviceName" value="" />
<div class="space-y-1.5">
<label for="auth-sign-in-identifier" class="block text-sm font-medium">{identifierLabel}</label>
<input id="auth-sign-in-identifier" name="identifier" type="text" autocomplete="username webauthn" aria-describedby="auth-sign-in-identifier-error" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-sm outline-none focus:border-[var(--wire-color-primary)] focus:ring-2 focus:ring-[color-mix(in_srgb,var(--wire-color-primary)_25%,transparent)]" />
<p id="auth-sign-in-identifier-error" data-error="identifier" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<div class="space-y-1.5">
<div class="flex items-center justify-between gap-3 text-sm font-medium"><label for="auth-sign-in-password">{passwordLabel}</label><a href='{forgotHref}' class="text-xs text-[var(--wire-color-primary)] hover:underline">Forgot password?</a></div>
<input id="auth-sign-in-password" name="password" type="password" autocomplete="current-password" aria-describedby="auth-sign-in-password-error" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-sm outline-none focus:border-[var(--wire-color-primary)] focus:ring-2 focus:ring-[color-mix(in_srgb,var(--wire-color-primary)_25%,transparent)]" />
<p id="auth-sign-in-password-error" data-error="password" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{#if showRemember}
<label class="flex items-center gap-2 text-sm text-[var(--wire-color-muted)]"><input name="rememberDevice" type="checkbox" class="size-4 rounded border-[var(--wire-color-border)]" />Trust this device</label>
{/if}
<slot></slot>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<button type="submit" class="inline-flex h-11 w-full items-center justify-center rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white transition-opacity hover:opacity-90 disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
{#if showPasskey}
<div class="my-4 flex items-center gap-3 text-xs text-[var(--wire-color-muted)]"><span class="h-px flex-1 bg-[var(--wire-color-border)]"></span><span>or</span><span class="h-px flex-1 bg-[var(--wire-color-border)]"></span></div>
<PasskeyButton mode="authenticate" identifier="" mfaHref='{mfaHref}' fullWidth="true" />
{/if}
{#if showSignUp}
<p class="mb-0 mt-5 text-center text-sm text-[var(--wire-color-muted)]">New here? <a href='{signUpHref}' class="font-semibold text-[var(--wire-color-primary)] hover:underline">Create an account</a></p>
{/if}
</section>
}
}
+90
View File
@@ -0,0 +1,90 @@
component SignUp {
props {
action = "/api/auth/register"
schema = "auth-register"
redirect = ""
title = "Create your account"
description = "Use a strong password and verify your contact details."
submitLabel = "Create account"
signInHref = "/sign-in"
showPhone = true
showUsername = true
requireConsent = true
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-lg rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<header class="mb-6 space-y-1.5">
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="m-0 text-sm text-[var(--wire-color-muted)]">{description}</p>
</header>
<form
method="post"
action='{action}'
data-schema='{schema}'
data-redirect='{redirect}'
novalidate
class="grid gap-4 sm:grid-cols-2"
>
<div class="space-y-1.5 sm:col-span-2">
<label for="auth-sign-up-name" class="text-sm font-medium">Full name</label>
<input id="auth-sign-up-name" name="displayName" autocomplete="name" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="displayName" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<div class="space-y-1.5">
<label for="auth-sign-up-email" class="text-sm font-medium">Email</label>
<input id="auth-sign-up-email" name="email" type="email" autocomplete="email" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="email" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{#if showPhone}
<div class="space-y-1.5">
<label for="auth-sign-up-phone" class="text-sm font-medium">Phone</label>
<input id="auth-sign-up-phone" name="phone" type="tel" autocomplete="tel" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="phone" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{/if}
{#if showUsername}
<div class="space-y-1.5 sm:col-span-2">
<label for="auth-sign-up-username" class="text-sm font-medium">Username</label>
<input id="auth-sign-up-username" name="username" autocomplete="username" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p data-error="username" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{/if}
<div class="space-y-1.5 sm:col-span-2">
<label for="auth-sign-up-password" class="text-sm font-medium">Password</label>
<input id="auth-sign-up-password" name="password" type="password" autocomplete="new-password" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 outline-none focus:border-[var(--wire-color-primary)]" />
<p class="m-0 text-xs text-[var(--wire-color-muted)]">At least 12 characters with uppercase, lowercase, and a number.</p>
<p data-error="password" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{#if requireConsent}
<div class="space-y-1 sm:col-span-2">
<label class="flex items-start gap-2 text-sm text-[var(--wire-color-muted)]">
<input name="consent" type="checkbox" class="mt-0.5 size-4" />
<span>I agree to the terms and privacy policy.</span>
</label>
<p data-error="consent" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
{:else}
<input type="hidden" name="consent" value="true" />
{/if}
<div class="sm:col-span-2"><slot></slot></div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)] sm:col-span-2"></p>
<p data-success="Account created successfully." role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)] sm:col-span-2"></p>
<button type="submit" class="h-11 rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] px-4 text-sm font-semibold text-white sm:col-span-2 disabled:cursor-not-allowed disabled:opacity-60">{submitLabel}</button>
</form>
<p class="mb-0 mt-5 text-center text-sm text-[var(--wire-color-muted)]">Already have an account? <a href='{signInHref}' class="font-semibold text-[var(--wire-color-primary)] hover:underline">Sign in</a></p>
</section>
}
}
@@ -0,0 +1,58 @@
component TwoFactorChallenge {
props {
action = "/api/auth/mfa/complete"
schema = "auth-mfa"
otpAction = "/api/auth/mfa/otp"
mfaToken = ""
challengeId = ""
method = "totp"
returnTo = "/"
title = "Two-step verification"
description = "Choose a verification method and enter the code."
submitLabel = "Verify"
recoveryHref = "/recover"
color = "primary"
size = "md"
class = ""
}
view {
<section
{...attrs}
data-wrnexus-runtime="auth"
data-auth-mfa-challenge
data-mfa-otp-action='{otpAction}'
data-mfa-initial-method='{method}'
class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'
>
<div class="mb-5 flex size-11 items-center justify-center rounded-full bg-[color-mix(in_srgb,var(--wire-color-primary)_12%,transparent)] text-[var(--wire-color-primary)]"><span class="icon-[lucide--shield-check] size-5"></span></div>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' data-auth-mfa-form novalidate class="mt-6 space-y-4">
<input type="hidden" name="mfaToken" value='{mfaToken}' />
<input type="hidden" name="challengeId" value='{challengeId}' />
<input type="hidden" name="returnTo" value='{returnTo}' />
<div class="space-y-1.5">
<label for="auth-mfa-method" class="block text-sm font-medium">Verification method</label>
<select id="auth-mfa-method" name="method" data-auth-mfa-method class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3">
<option value="totp">Authenticator app</option>
<option value="recovery-code">Recovery code</option>
<option value="email-otp">Email code</option>
<option value="sms-otp">SMS code</option>
</select>
<p data-error="method" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<div class="space-y-1.5">
<label for="auth-mfa-code" class="block text-sm font-medium">Verification code</label>
<input id="auth-mfa-code" name="code" inputmode="numeric" autocomplete="one-time-code" class="h-12 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3 text-center text-xl tracking-[0.35em]" />
<p data-error="code" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
</div>
<p data-auth-mfa-status role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-primary)_10%,transparent)] p-3 text-sm text-[var(--wire-color-primary)]"></p>
<p data-error="mfaToken" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="challengeId" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
<a href='{recoveryHref}' class="mt-4 inline-flex text-sm text-[var(--wire-color-primary)] hover:underline">Account recovery options</a>
</section>
}
}
+37
View File
@@ -0,0 +1,37 @@
component VerifyEmail {
props {
kind = "email"
action = "/api/auth/verify/email"
schema = "auth-verification-token"
token = ""
identifier = ""
title = "Verify your email"
description = "Enter the verification token or continue with your secure link."
submitLabel = "Verify email"
resendAction = "/api/auth/verification/request"
resendSchema = "auth-verification-request"
successMessage = "Your email has been verified."
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' novalidate class="mt-6 space-y-4">
<div class="space-y-1.5"><label for="auth-email-token" class="block text-sm font-medium">Verification token</label><input id="auth-email-token" name="token" value='{token}' autocomplete="one-time-code" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3" /><p data-error="token" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p></div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
<form method="post" action='{resendAction}' data-schema='{resendSchema}' novalidate class="mt-3">
<input type="hidden" name="type" value='{kind}' />
<input type="hidden" name="identifier" value='{identifier}' />
<p data-error="type" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<button type="submit" class="text-sm text-[var(--wire-color-primary)] hover:underline disabled:opacity-60">Send a new code</button>
</form>
</section>
}
}
+37
View File
@@ -0,0 +1,37 @@
component VerifyPhone {
props {
kind = "phone"
action = "/api/auth/verify/phone"
schema = "auth-verification-token"
token = ""
identifier = ""
title = "Verify your phone"
description = "Enter the verification token sent to your phone."
submitLabel = "Verify phone"
resendAction = "/api/auth/verification/request"
resendSchema = "auth-verification-request"
successMessage = "Your phone number has been verified."
color = "primary"
size = "md"
class = ""
}
view {
<section {...attrs} data-wrnexus-runtime="auth" class='w-full max-w-md rounded-[var(--wire-radius-lg)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface)] p-6 text-[var(--wire-color-text)] shadow-[var(--wire-shadow-2)] {class}'>
<h1 class="m-0 text-2xl font-semibold">{title}</h1>
<p class="mt-2 text-sm text-[var(--wire-color-muted)]">{description}</p>
<form method="post" action='{action}' data-schema='{schema}' novalidate class="mt-6 space-y-4">
<div class="space-y-1.5"><label for="auth-phone-token" class="block text-sm font-medium">Verification token</label><input id="auth-phone-token" name="token" value='{token}' autocomplete="one-time-code" inputmode="numeric" class="h-11 w-full rounded-[var(--wire-radius-sm)] border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-2)] px-3" /><p data-error="token" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p></div>
<p data-error="_form" role="alert" class="m-0 hidden rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-danger)_10%,transparent)] p-3 text-sm text-[var(--wire-color-danger)]"></p>
<p data-success='{successMessage}' role="status" hidden class="m-0 rounded-[var(--wire-radius-sm)] bg-[color-mix(in_srgb,var(--wire-color-success)_10%,transparent)] p-3 text-sm text-[var(--wire-color-success)]">{successMessage}</p>
<button type="submit" class="h-11 w-full rounded-[var(--wire-radius-sm)] bg-[var(--wire-color-primary)] font-semibold text-white disabled:cursor-wait disabled:opacity-60">{submitLabel}</button>
</form>
<form method="post" action='{resendAction}' data-schema='{resendSchema}' novalidate class="mt-3">
<input type="hidden" name="type" value='{kind}' />
<input type="hidden" name="identifier" value='{identifier}' />
<p data-error="type" class="m-0 min-h-4 text-xs text-[var(--wire-color-danger)]"></p>
<p data-error="_form" role="alert" class="m-0 hidden text-xs text-[var(--wire-color-danger)]"></p>
<button type="submit" class="text-sm text-[var(--wire-color-primary)] hover:underline disabled:opacity-60">Send a new code</button>
</form>
</section>
}
}