"use client"; import { CheckIcon, EyeIcon, EyeOffIcon } from "lucide-react"; import { motion, useReducedMotion } from "motion/react"; import { type FormEvent, type ReactNode, useId, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group"; import { Label } from "@/components/ui/label"; import { cn } from "@/lib/utils"; export type SignUpResult = { ok: true } | { ok: false; error: string }; export interface SignUpDetails { name: string; email: string; password: string; } export interface SignUpProps { product?: string; logo?: ReactNode; minLength?: number; onSignUp?: (details: SignUpDetails) => Promise; onSignIn?: () => void; onTerms?: () => void; onPrivacy?: () => void; className?: string; } const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; async function demoSignUp(): Promise { await new Promise((resolve) => setTimeout(resolve, 900)); return { ok: true }; } function Mark() { return ( ); } const linkClass = "cursor-pointer rounded-sm text-foreground underline underline-offset-4 outline-none decoration-border hover:decoration-foreground focus-visible:ring-2 focus-visible:ring-ring"; export function SignUp({ product = "Ridgeline", logo, minLength = 8, onSignUp = demoSignUp, onSignIn, onTerms, onPrivacy, className, }: SignUpProps) { const id = useId(); const reduce = useReducedMotion(); const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [reveal, setReveal] = useState(false); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const [tried, setTried] = useState(false); const [done, setDone] = useState(false); const longEnough = password.length >= minLength; const emailValid = EMAIL.test(email.trim()); const emailError = tried && !emailValid ? "Enter a valid email address." : null; const passwordError = tried && !longEnough; const submit = async (event: FormEvent) => { event.preventDefault(); if (busy || done) return; setTried(true); setError(null); if (!emailValid || !longEnough) return; setBusy(true); const result = await onSignUp({ name: name.trim(), email: email.trim(), password }); setBusy(false); if (result.ok) setDone(true); else setError(result.error); }; return (
{logo ?? }

Create your {product} account

Free for your first three projects. No card needed.

setName(e.target.value)} placeholder="Ada Lindqvist" value={name} />
setEmail(e.target.value)} placeholder="you@company.com" type="email" value={email} /> {emailError && (

{emailError}

)}
setPassword(e.target.value)} placeholder="Create a password" type={reveal ? "text" : "password"} value={password} />

{longEnough && ( )} At least {minLength} characters

{error && (

{error}

)}

By continuing you agree to the{" "} {" "} and{" "} .

Already have an account?{" "}

); }