{
  "name": "stepper-validation-demo",
  "type": "registry:example",
  "dependencies": [
    "@hookform/resolvers",
    "react-hook-form",
    "sonner",
    "zod"
  ],
  "registryDependencies": [
    "stepper",
    "form"
  ],
  "files": [
    {
      "path": "examples/stepper-validation-demo.tsx",
      "type": "registry:example",
      "content": "\"use client\";\n\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as React from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport * as z from \"zod\";\n\nimport { Button } from \"@/registry/bases/radix/ui/button\";\nimport {\n  Form,\n  FormControl,\n  FormField,\n  FormItem,\n  FormLabel,\n  FormMessage,\n} from \"@/registry/bases/radix/ui/form\";\nimport { Input } from \"@/registry/bases/radix/ui/input\";\nimport {\n  Stepper,\n  StepperContent,\n  StepperDescription,\n  StepperIndicator,\n  StepperItem,\n  StepperList,\n  StepperNext,\n  StepperPrev,\n  type StepperProps,\n  StepperSeparator,\n  StepperTitle,\n  StepperTrigger,\n} from \"@/registry/bases/radix/ui/stepper\";\nimport { Textarea } from \"@/registry/bases/radix/ui/textarea\";\n\nconst formSchema = z.object({\n  username: z\n    .string()\n    .min(3, \"Username must be at least 3 characters\")\n    .regex(\n      /^[a-zA-Z0-9_]+$/,\n      \"Username can only contain letters, numbers, and underscores\",\n    ),\n  email: z.email(\"Please enter a valid email address\"),\n  firstName: z.string().min(1, \"First name is required\"),\n  lastName: z.string().min(1, \"Last name is required\"),\n  bio: z.string().min(10, \"Bio must be at least 10 characters\"),\n});\n\ntype FormSchema = z.infer<typeof formSchema>;\n\nconst steps = [\n  {\n    value: \"account\",\n    title: \"Account Setup\",\n    description: \"Create your account\",\n    fields: [\"username\", \"email\"] as const,\n  },\n  {\n    value: \"profile\",\n    title: \"Profile Info\",\n    description: \"Complete your profile\",\n    fields: [\"firstName\", \"lastName\", \"bio\"] as const,\n  },\n  {\n    value: \"review\",\n    title: \"Review\",\n    description: \"Review your information\",\n    fields: [] as const,\n  },\n];\n\nexport default function StepperValidationDemo() {\n  const [step, setStep] = React.useState(\"account\");\n\n  const form = useForm<FormSchema>({\n    resolver: zodResolver(formSchema),\n    defaultValues: {\n      username: \"\",\n      email: \"\",\n      firstName: \"\",\n      lastName: \"\",\n      bio: \"\",\n    },\n  });\n\n  const stepIndex = React.useMemo(\n    () => steps.findIndex((s) => s.value === step),\n    [step],\n  );\n\n  const onValidate: NonNullable<StepperProps[\"onValidate\"]> = React.useCallback(\n    async (_value, direction) => {\n      if (direction === \"prev\") return true;\n\n      const stepData = steps.find((s) => s.value === step);\n      if (!stepData) return true;\n\n      const isValid = await form.trigger(stepData.fields);\n\n      if (!isValid) {\n        toast.info(\"Please complete all required fields to continue\", {\n          description: \"Fix the validation errors and try again.\",\n        });\n      }\n\n      return isValid;\n    },\n    [form, step],\n  );\n\n  const onSubmit = React.useCallback((input: FormSchema) => {\n    toast.success(\n      <pre className=\"w-full\">{JSON.stringify(input, null, 2)}</pre>,\n    );\n  }, []);\n\n  return (\n    <Form {...form}>\n      <form className=\"w-full\" onSubmit={form.handleSubmit(onSubmit)}>\n        <Stepper value={step} onValueChange={setStep} onValidate={onValidate}>\n          <StepperList>\n            {steps.map((step) => (\n              <StepperItem key={step.value} value={step.value}>\n                <StepperTrigger>\n                  <StepperIndicator />\n                  <div className=\"flex flex-col gap-1\">\n                    <StepperTitle>{step.title}</StepperTitle>\n                    <StepperDescription>{step.description}</StepperDescription>\n                  </div>\n                </StepperTrigger>\n                <StepperSeparator className=\"mx-4\" />\n              </StepperItem>\n            ))}\n          </StepperList>\n          <StepperContent\n            value=\"account\"\n            className=\"flex flex-col gap-4 rounded-md border bg-card p-4 text-card-foreground\"\n          >\n            <FormField\n              control={form.control}\n              name=\"username\"\n              render={({ field }) => (\n                <FormItem>\n                  <FormLabel>Username</FormLabel>\n                  <FormControl>\n                    <Input placeholder=\"Enter username\" {...field} />\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n            <FormField\n              control={form.control}\n              name=\"email\"\n              render={({ field }) => (\n                <FormItem>\n                  <FormLabel>Email</FormLabel>\n                  <FormControl>\n                    <Input type=\"email\" placeholder=\"Enter email\" {...field} />\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n          </StepperContent>\n          <StepperContent\n            value=\"profile\"\n            className=\"flex flex-col gap-4 rounded-md border bg-card p-4 text-card-foreground\"\n          >\n            <div className=\"grid grid-cols-2 gap-4\">\n              <FormField\n                control={form.control}\n                name=\"firstName\"\n                render={({ field }) => (\n                  <FormItem>\n                    <FormLabel>First Name</FormLabel>\n                    <FormControl>\n                      <Input placeholder=\"Enter first name\" {...field} />\n                    </FormControl>\n                    <FormMessage />\n                  </FormItem>\n                )}\n              />\n              <FormField\n                control={form.control}\n                name=\"lastName\"\n                render={({ field }) => (\n                  <FormItem>\n                    <FormLabel>Last Name</FormLabel>\n                    <FormControl>\n                      <Input placeholder=\"Enter last name\" {...field} />\n                    </FormControl>\n                    <FormMessage />\n                  </FormItem>\n                )}\n              />\n            </div>\n            <FormField\n              control={form.control}\n              name=\"bio\"\n              render={({ field }) => (\n                <FormItem>\n                  <FormLabel>Bio</FormLabel>\n                  <FormControl>\n                    <Textarea\n                      placeholder=\"Tell us about yourself...\"\n                      className=\"min-h-[80px]\"\n                      {...field}\n                    />\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n          </StepperContent>\n          <StepperContent\n            value=\"review\"\n            className=\"grid grid-cols-2 gap-4 rounded-md border bg-card p-4 text-card-foreground lg:grid-cols-3\"\n          >\n            <div className=\"flex flex-col gap-1 rounded-md border p-2\">\n              <span className=\"text-sm font-medium\">Username</span>\n              <p className=\"text-sm\">\n                {form.watch(\"username\") ?? \"Not provided\"}\n              </p>\n            </div>\n            <div className=\"flex flex-col gap-1 rounded-md border p-2\">\n              <span className=\"text-sm font-medium\">Email</span>\n              <p className=\"text-sm\">{form.watch(\"email\") ?? \"Not provided\"}</p>\n            </div>\n            <div className=\"flex flex-col gap-1 rounded-md border p-2\">\n              <span className=\"text-sm font-medium\">First Name</span>\n              <p className=\"text-sm\">\n                {form.watch(\"firstName\") ?? \"Not provided\"}\n              </p>\n            </div>\n            <div className=\"flex flex-col gap-1 rounded-md border p-2\">\n              <span className=\"text-sm font-medium\">Last Name</span>\n              <p className=\"text-sm\">\n                {form.watch(\"lastName\") ?? \"Not provided\"}\n              </p>\n            </div>\n            <div className=\"flex flex-col gap-1 rounded-md border p-2\">\n              <span className=\"text-sm font-medium\">Bio</span>\n              <p className=\"text-sm\">{form.watch(\"bio\") ?? \"Not provided\"}</p>\n            </div>\n          </StepperContent>\n          <div className=\"flex justify-between\">\n            <StepperPrev asChild>\n              <Button type=\"button\" variant=\"outline\">\n                Previous\n              </Button>\n            </StepperPrev>\n            <div className=\"text-sm text-muted-foreground\">\n              Step {stepIndex + 1} of {steps.length}\n            </div>\n            {stepIndex === steps.length - 1 ? (\n              <Button type=\"submit\">Complete Setup</Button>\n            ) : (\n              <StepperNext asChild>\n                <Button>Next</Button>\n              </StepperNext>\n            )}\n          </div>\n        </Stepper>\n      </form>\n    </Form>\n  );\n}\n",
      "target": ""
    }
  ]
}