{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "multi-step-form",
  "title": "Multi Step Form",
  "description": "A dynamic, animated multi-step form with validation.",
  "dependencies": [
    "motion",
    "date-fns",
    "react-hook-form",
    "@hookform/resolvers",
    "zod",
    "sonner",
    "lucide-react",
    "react-use-measure",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "card",
    "button",
    "input",
    "textarea",
    "select",
    "badge",
    "calendar",
    "popover"
  ],
  "files": [
    {
      "path": "registry/default/example/multi-step-form.tsx",
      "content": "\"use client\";\n\nimport React, { useState, useMemo } from \"react\";\nimport { format } from \"date-fns\";\nimport { Check, ChevronRight, ChevronLeft, CalendarIcon } from \"lucide-react\";\nimport { useForm, FormProvider as Form } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { z } from \"zod\";\nimport { toast } from \"sonner\";\nimport {\n  Field,\n  FieldLabel,\n  FieldDescription,\n  FieldError,\n} from \"@/components/ui/field\";\nimport {\n  Card,\n  CardHeader,\n  CardTitle,\n  CardDescription,\n  CardContent,\n  CardFooter,\n} from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Calendar } from \"@/components/ui/calendar\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, MotionConfig } from \"motion/react\";\nimport useMeasure from \"react-use-measure\";\n\nconst TEAM_SIZE_OPTIONS = [\n  { label: \"Select team size\", value: null },\n  { label: \"1-5 Members\", value: \"1-5\" },\n  { label: \"5-10 Members\", value: \"5-10\" },\n  { label: \"10+ Members\", value: \"10+\" },\n];\n\nconst PRIORITY_OPTIONS = [\n  { label: \"Select priority\", value: null },\n  { label: \"Low\", value: \"Low\" },\n  { label: \"Medium\", value: \"Medium\" },\n  { label: \"High\", value: \"High\" },\n  { label: \"Critical\", value: \"Critical\" },\n];\n\nconst formSchema = z.object({\n  \"project-name\": z.string().optional(),\n  \"due-date\": z.date().optional(),\n  description: z.string().optional(),\n  \"team-size\": z.string().nullable().optional(),\n  priority: z.string().nullable().optional(),\n  tag: z.array(z.string()).optional(),\n  mood: z.string().optional(),\n  comment: z.string().optional(),\n});\n\ntype FormValues = z.infer<typeof formSchema>;\n\nexport default function MultiStepFormDemo() {\n  const [currentStep, setCurrentStep] = useState(0);\n  const [direction, setDirection] = useState<number>();\n  const [ref, bounds] = useMeasure();\n\n  const form = useForm<FormValues>({\n    resolver: zodResolver(formSchema),\n    defaultValues: {\n      \"project-name\": \"\",\n      \"due-date\": undefined,\n      description: \"\",\n      \"team-size\": null,\n      priority: null,\n      tag: [],\n      mood: \"\",\n      comment: \"\",\n    },\n  });\n\n  function onSubmit(values: FormValues) {\n    try {\n      console.log(values);\n      toast(\n        <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n          <code className=\"text-white\">{JSON.stringify(values, null, 2)}</code>\n        </pre>\n      );\n    } catch (error) {\n      console.error(\"Form submission error\", error);\n      toast.error(\"Failed to submit the form. Please try again.\");\n    }\n  }\n\n  const nextStep = () => {\n    if (currentStep === 2) {\n      form.handleSubmit(onSubmit)();\n      return;\n    }\n    if (currentStep < 2) {\n      setDirection(1);\n      setCurrentStep((prev) => prev + 1);\n    }\n  };\n\n  const prevStep = () => {\n    if (currentStep > 0) {\n      setDirection(-1);\n      setCurrentStep((prev) => prev - 1);\n    }\n  };\n\n  // Change Here\n  const stepTitles = [\n    {\n      title: \"Create New Project\",\n      description:\n        \"Start by providing the essential details for your workspace.\",\n    },\n    {\n      title: \"Configuration\",\n      description: \"Define team access and project priority settings.\",\n    },\n    {\n      title: \"Project Kickoff Mood\",\n      description: \"How confident do you feel about this new project?\",\n    },\n  ];\n\n  const watchedValues = form.watch();\n\n  const content = useMemo(() => {\n    switch (currentStep) {\n      case 0:\n        return (\n          <div className=\"space-y-6 py-4\">\n            <Field>\n              <FieldLabel htmlFor=\"project-name\">Project Name</FieldLabel>\n              <Input\n                id=\"project-name\"\n                placeholder=\"e.g Website Design\"\n                {...form.register(\"project-name\")}\n              />\n              <FieldError>\n                {form.formState.errors[\"project-name\"]?.message}\n              </FieldError>\n            </Field>\n\n            <Field>\n              <FieldLabel htmlFor=\"due-date\">Due Date</FieldLabel>\n              <Popover>\n                <PopoverTrigger\n                  render={\n                    <Button\n                      variant={\"outline\"}\n                      className={cn(\n                        \"w-full justify-start text-left font-normal\",\n                        !watchedValues[\"due-date\"] && \"text-muted-foreground\"\n                      )}\n                    >\n                      <CalendarIcon className=\"mr-2 h-4 w-4\" />\n                      {watchedValues[\"due-date\"] ? (\n                        format(watchedValues[\"due-date\"] as Date, \"PPP\")\n                      ) : (\n                        <span>Pick a date</span>\n                      )}\n                    </Button>\n                  }\n                />\n                <PopoverContent className=\"w-auto p-0\" align=\"start\">\n                  <Calendar\n                    mode=\"single\"\n                    selected={watchedValues[\"due-date\"]}\n                    onSelect={(date) => form.setValue(\"due-date\", date)}\n                    initialFocus\n                  />\n                </PopoverContent>\n              </Popover>\n              <FieldError>\n                {form.formState.errors[\"due-date\"]?.message}\n              </FieldError>\n            </Field>\n\n            <Field>\n              <FieldLabel htmlFor=\"description\">Description</FieldLabel>\n              <Textarea\n                id=\"description\"\n                placeholder=\"Describe the project goals and scope...\"\n                className=\"min-h-[100px]\"\n                {...form.register(\"description\")}\n              />\n              <FieldError>\n                {form.formState.errors.description?.message}\n              </FieldError>\n            </Field>\n          </div>\n        );\n      case 1:\n        return (\n          <div className=\"space-y-6 py-4\">\n            <div className=\"grid grid-cols-2 gap-4\">\n              <Field>\n                <FieldLabel htmlFor=\"team-size\">Team Size</FieldLabel>\n                <Select\n                  items={TEAM_SIZE_OPTIONS}\n                  value={watchedValues[\"team-size\"] ?? null}\n                  onValueChange={(val) => form.setValue(\"team-size\", val)}\n                >\n                  <SelectTrigger id=\"team-size\" className=\"w-full\">\n                    <SelectValue />\n                  </SelectTrigger>\n                  <SelectContent>\n                    {TEAM_SIZE_OPTIONS.map((opt) => (\n                      <SelectItem key={opt.label} value={opt.value as any}>\n                        {opt.label}\n                      </SelectItem>\n                    ))}\n                  </SelectContent>\n                </Select>\n                <FieldError>\n                  {form.formState.errors[\"team-size\"]?.message}\n                </FieldError>\n              </Field>\n\n              <Field>\n                <FieldLabel htmlFor=\"priority\">Priority</FieldLabel>\n                <Select\n                  items={PRIORITY_OPTIONS}\n                  value={watchedValues[\"priority\"] ?? null}\n                  onValueChange={(val) => form.setValue(\"priority\", val)}\n                >\n                  <SelectTrigger id=\"priority\" className=\"w-full\">\n                    <SelectValue />\n                  </SelectTrigger>\n                  <SelectContent>\n                    {PRIORITY_OPTIONS.map((opt) => (\n                      <SelectItem key={opt.label} value={opt.value as any}>\n                        {opt.label}\n                      </SelectItem>\n                    ))}\n                  </SelectContent>\n                </Select>\n                <FieldError>\n                  {form.formState.errors.priority?.message}\n                </FieldError>\n              </Field>\n            </div>\n\n            <Field>\n              <FieldLabel htmlFor=\"tag\">Tags</FieldLabel>\n              <div className=\"space-y-2\">\n                <div className=\"flex flex-wrap gap-2 mb-2\">\n                  {watchedValues[\"tag\"]?.map((t, i) => (\n                    <Badge key={i} variant=\"secondary\" className=\"gap-1\">\n                      {t}\n                      <button\n                        type=\"button\"\n                        onClick={() => {\n                          const tags = form.getValues(\"tag\") || [];\n                          form.setValue(\n                            \"tag\",\n                            tags.filter((_, index) => index !== i)\n                          );\n                        }}\n                        className=\"hover:text-destructive\"\n                      >\n                        ×\n                      </button>\n                    </Badge>\n                  ))}\n                </div>\n                <Input\n                  id=\"tag\"\n                  placeholder=\"e.g. Design, Marketing\"\n                  onKeyDown={(e) => {\n                    if (e.key === \"Enter\") {\n                      e.preventDefault();\n                      const val = e.currentTarget.value.trim();\n                      if (val) {\n                        const tags = form.getValues(\"tag\") || [];\n                        if (!tags.includes(val)) {\n                          form.setValue(\"tag\", [...tags, val]);\n                        }\n                        e.currentTarget.value = \"\";\n                      }\n                    }\n                  }}\n                />\n              </div>\n              <FieldError>{form.formState.errors.tag?.message}</FieldError>\n            </Field>\n          </div>\n        );\n      case 2:\n        return (\n          <div className=\"space-y-4 py-4\">\n            <div className=\"rounded-xl border bg-background overflow-hidden relative\">\n              <div className=\"flex w-full border-b divide-x bg-muted/5\">\n                {[\n                  { emoji: \"😰\", value: \"anxious\", label: \"Anxious\" },\n                  { emoji: \"😟\", value: \"worried\", label: \"Worried\" },\n                  { emoji: \"😐\", value: \"neutral\", label: \"Neutral\" },\n                  { emoji: \"🙂\", value: \"good\", label: \"Good\" },\n                  { emoji: \"🤩\", value: \"excited\", label: \"Excited\" },\n                ].map((option) => (\n                  <button\n                    key={option.value}\n                    className={cn(\n                      \"flex-1 p-3 md:p-4 text-2xl md:text-3xl transition-all hover:bg-muted focus:outline-none\",\n                      watchedValues[\"mood\"] === option.value\n                        ? \"bg-primary/10 grayscale-0\"\n                        : \"grayscale-[1] hover:grayscale-0\"\n                    )}\n                    type=\"button\"\n                    title={option.label}\n                    onClick={() => form.setValue(\"mood\", option.value)}\n                  >\n                    {option.emoji}\n                  </button>\n                ))}\n              </div>\n              <Textarea\n                id=\"comment\"\n                placeholder=\"Add a comment...\"\n                className=\"min-h-[140px] resize-none border-0 focus-visible:ring-0 rounded-none bg-transparent p-4 placeholder:text-muted-foreground/60\"\n                {...form.register(\"comment\")}\n              />\n            </div>\n            <p className=\"text-sm text-muted-foreground\">\n              Your feedback helps us understand the project kickoff vibe.\n            </p>\n          </div>\n        );\n      default:\n        return null;\n    }\n  }, [currentStep, form, watchedValues]);\n\n  const variants = {\n    initial: (direction: number) => {\n      return { x: `${110 * direction}%`, opacity: 0 };\n    },\n    animate: { x: \"0%\", opacity: 1 },\n    exit: (direction: number) => {\n      return { x: `${-110 * direction}%`, opacity: 0 };\n    },\n  };\n\n  return (\n    <Form {...form}>\n      <MotionConfig\n        transition={{\n          duration: 0.5,\n          type: \"spring\",\n          bounce: 0,\n        }}\n      >\n        <div className=\"flex w-full items-center justify-center bg-muted/10 p-4\">\n          <Card className=\"w-full max-w-xl shadow-none border overflow-hidden bg-background\">\n            <motion.div layout>\n              <CardHeader className=\"flex flex-row items-start justify-between space-y-0 px-6 py-4\">\n                <div className=\"flex flex-col gap-1\">\n                  <CardTitle className=\"text-xl\">\n                    {stepTitles[currentStep].title}\n                  </CardTitle>\n                  <CardDescription>\n                    {stepTitles[currentStep].description}\n                  </CardDescription>\n                </div>\n                <div className=\"flex items-center gap-1.5 pt-1\">\n                  {stepTitles.map((_, index) => (\n                    <div\n                      key={index}\n                      className={cn(\n                        \"h-2 rounded-full transition-all duration-300\",\n                        currentStep === index\n                          ? \"w-8 bg-primary\"\n                          : \"w-2 bg-primary/20\"\n                      )}\n                    />\n                  ))}\n                </div>\n              </CardHeader>\n\n              <motion.div\n                animate={{ height: bounds.height > 0 ? bounds.height : \"auto\" }}\n                className=\"relative overflow-hidden\"\n                transition={{ type: \"spring\", bounce: 0, duration: 0.5 }}\n              >\n                <div ref={ref}>\n                  <CardContent className=\"px-6 py-2 relative\">\n                    <AnimatePresence\n                      mode=\"popLayout\"\n                      initial={false}\n                      custom={direction}\n                    >\n                      <motion.div\n                        key={currentStep}\n                        variants={variants}\n                        initial=\"initial\"\n                        animate=\"animate\"\n                        exit=\"exit\"\n                        className=\"w-full\"\n                        custom={direction}\n                      >\n                        {content}\n                      </motion.div>\n                    </AnimatePresence>\n                  </CardContent>\n                </div>\n              </motion.div>\n\n              <CardFooter className=\"flex justify-between items-center border-t py-4\">\n                <Button\n                  variant={\"secondary\"}\n                  type=\"button\"\n                  onClick={prevStep}\n                  disabled={currentStep === 0}\n                >\n                  <ChevronLeft className=\"h-4 w-4\" />\n                  Back\n                </Button>\n                <Button type=\"button\" onClick={nextStep}>\n                  {currentStep === stepTitles.length - 1 ? (\n                    <>\n                      Finish <Check className=\"h-4 w-4\" />\n                    </>\n                  ) : (\n                    <>\n                      Continue <ChevronRight className=\"h-4 w-4\" />\n                    </>\n                  )}\n                </Button>\n              </CardFooter>\n            </motion.div>\n          </Card>\n        </div>\n      </MotionConfig>\n    </Form>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}