crucıble

Wicket

Auth card block covering every flow — sign in, sign up, magic link, OTP/2FA, forgot and reset password — morphing between steps with direction-aware slides and a spring height. SSO buttons with per-button spinners, password reveal + caps-lock warning, a 4-segment strength meter with a live rule checklist, an envelope that folds shut on 'Check your inbox' with a resend countdown, Passcode cells that auto-submit and shake on a wrong code, and async callbacks driving pending, a slide-in error banner and a drawn-check success state.

motionfree

Installation

CLI

npx shadcn@latest add @crucible/wicket

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
viewWicketViewControlled view. Omit for internal navigation (see defaultView).
defaultViewWicketView"sign-in"Initial view when uncontrolled.
onViewChange(view: WicketView) => voidFires whenever the card asks to move to another view (links, flow steps).
providersWicketProvider[]Google + GitHub with generic glyphsSSO buttons shown on sign-in and sign-up. Pass [] to hide the row.
logoReact.ReactNodea neutral accent markLogo slot above the header.
titlestring"Halyard"Product name woven into the default copy ("Sign in to {title}").
copyPartial<Record<WicketView, WicketCopy>>Override the title/subtitle of any view.
onSignIn(values: WicketSignInValues) => Async<Outcome>Sign in with email + password. Resolve to "otp" to require a second factor.
onSignUp(values: WicketSignUpValues) => Async<Outcome>Create an account. Resolve to a view to continue (e.g. "otp" to verify).
onMagicLink(email: string) => Async<void>Send a magic sign-in link. Resolving shows the "Check your inbox" state.
onVerifyOtp(code: string) => Async<void>Verify a one-time code (auto-submits once every cell is filled). Reject to shake + clear.
onForgot(email: string) => Async<void>Send a password-reset email. Resolving shows the sent state.
onReset(values: { password: string }) => Async<void>Set a new password from a reset link.
onProvider(id: string) => Async<Outcome>SSO button pressed. Resolve to finish, or to a view to continue.
onResend(view: "magic-link" | "otp" | "forgot", email: string) => Async<void>A "Resend" button was pressed (after its countdown).
onComplete(view: WicketView) => voidFires when a flow reaches its final success state.
defaultEmailstringPrefill the email field.
resendSecondsnumber30Seconds before "Resend" re-enables.
otpLengthnumber6Number of OTP cells.
accentColorstringviolet #a78bfaThe single signature accent — primary button, focus rings, links.
refReact.Ref<WicketHandle>Imperative handle (setView, reset, replay). React 19 ref-as-prop.
classNamestring

Honors prefers-reduced-motion with a designed static fallback, and passes className through.