{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stepper",
  "type": "registry:ui",
  "title": "Stepper",
  "description": "A composable step navigation pattern for guiding people through a small, ordered workflow.",
  "files": [
    {
      "path": "registry/sonaui/stepper/stepper.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport {\n  createContext,\n  type HTMLAttributes,\n  type ReactNode,\n  useContext,\n  useId,\n  useState,\n} from \"react\";\nimport { cn } from \"@/lib/sona-utils\";\n\ntype StepperContextValue = {\n  value: number;\n  setValue: (value: number) => void;\n  orientation: \"horizontal\" | \"vertical\";\n};\n\ntype StepperItemContextValue = {\n  step: number;\n  active: boolean;\n  id: string;\n};\n\nconst StepperContext = createContext<StepperContextValue | null>(null);\nconst StepperItemContext = createContext<StepperItemContextValue | null>(null);\n\nfunction useStepper(component: string) {\n  const context = useContext(StepperContext);\n  if (!context) throw new Error(`${component} must be used within Stepper.`);\n  return context;\n}\n\nfunction useStepperItem(component: string) {\n  const context = useContext(StepperItemContext);\n  if (!context)\n    throw new Error(`${component} must be used within StepperItem.`);\n  return context;\n}\n\nexport interface StepperProps extends HTMLAttributes<HTMLDivElement> {\n  /** Step navigation and panels. */\n  children: ReactNode;\n  /** The active step in controlled mode. */\n  value?: number;\n  /** The initially active step in uncontrolled mode. @default 1 */\n  defaultValue?: number;\n  /** Called when a user selects a different step. */\n  onValueChange?: (value: number) => void;\n  /** The direction of the step navigation. @default \"horizontal\" */\n  orientation?: \"horizontal\" | \"vertical\";\n}\n\nexport function Stepper({\n  children,\n  value,\n  defaultValue = 1,\n  onValueChange,\n  orientation = \"horizontal\",\n  className,\n  ...props\n}: StepperProps) {\n  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n  const activeValue = value ?? uncontrolledValue;\n  const setValue = (nextValue: number) => {\n    if (value === undefined) setUncontrolledValue(nextValue);\n    onValueChange?.(nextValue);\n  };\n\n  return (\n    <StepperContext.Provider\n      value={{ value: activeValue, setValue, orientation }}\n    >\n      <div\n        data-orientation={orientation}\n        className={cn(\n          \"grid gap-6 data-[orientation=vertical]:md:grid-cols-[minmax(11rem,0.35fr)_minmax(0,1fr)]\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </div>\n    </StepperContext.Provider>\n  );\n}\n\nexport function StepperNav({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLElement>) {\n  const { orientation } = useStepper(\"StepperNav\");\n  return (\n    <nav\n      aria-label=\"Steps\"\n      className={cn(\n        \"relative flex min-w-0 gap-2 data-[orientation=vertical]:flex-col data-[orientation=vertical]:before:absolute data-[orientation=vertical]:before:top-5 data-[orientation=vertical]:before:bottom-5 data-[orientation=vertical]:before:left-5 data-[orientation=vertical]:before:w-px data-[orientation=vertical]:before:bg-border\",\n        className,\n      )}\n      data-orientation={orientation}\n      {...props}\n    >\n      {children}\n    </nav>\n  );\n}\n\nexport interface StepperItemProps extends HTMLAttributes<HTMLDivElement> {\n  /** The one-based value that identifies this step. */\n  step: number;\n  /** Step trigger and optional separator. */\n  children: ReactNode;\n}\n\nexport function StepperItem({\n  step,\n  children,\n  className,\n  ...props\n}: StepperItemProps) {\n  const { value } = useStepper(\"StepperItem\");\n  const id = useId();\n  return (\n    <StepperItemContext.Provider value={{ step, active: value === step, id }}>\n      <div className={cn(\"flex min-w-0 items-center\", className)} {...props}>\n        {children}\n      </div>\n    </StepperItemContext.Provider>\n  );\n}\n\nexport function StepperTrigger({\n  children,\n  className,\n  onClick,\n  ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n  const { setValue } = useStepper(\"StepperTrigger\");\n  const { step, active, id } = useStepperItem(\"StepperTrigger\");\n  return (\n    <button\n      type=\"button\"\n      aria-current={active ? \"step\" : undefined}\n      aria-pressed={active}\n      aria-describedby={`${id}-label`}\n      onClick={(event) => {\n        setValue(step);\n        onClick?.(event);\n      }}\n      className={cn(\n        \"group flex min-w-0 items-center gap-3 rounded-lg px-2 py-1.5 text-left text-sm text-muted-foreground transition-colors hover:text-foreground hover:cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n        active && \"text-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </button>\n  );\n}\n\nexport function StepperIndicator({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLSpanElement>) {\n  const { active } = useStepperItem(\"StepperIndicator\");\n  return (\n    <span\n      className={cn(\n        \"grid size-6 shrink-0 place-items-center rounded-full border border-border bg-background font-mono text-[10px] text-muted-foreground transition-colors\",\n        \"relative z-1\",\n        active && \"border-primary bg-primary text-primary-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </span>\n  );\n}\n\nexport function StepperTitle({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLSpanElement>) {\n  const { id } = useStepperItem(\"StepperTitle\");\n  return (\n    <span id={`${id}-label`} className={cn(\"truncate\", className)} {...props}>\n      {children}\n    </span>\n  );\n}\n\nexport function StepperSeparator({ className }: { className?: string }) {\n  return (\n    <span\n      aria-hidden=\"true\"\n      className={cn(\"mx-1 h-px min-w-4 flex-1 bg-border\", className)}\n    />\n  );\n}\n\nexport function StepperPanel({\n  children,\n  className,\n  ...props\n}: HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div className={cn(\"min-w-0\", className)} {...props}>\n      {children}\n    </div>\n  );\n}\n\nexport interface StepperContentProps extends HTMLAttributes<HTMLDivElement> {\n  /** The step value associated with this panel. */\n  value: number;\n  /** Keeps inactive content mounted. @default false */\n  forceMount?: boolean;\n  /** Content shown for this step. */\n  children: ReactNode;\n}\n\nexport function StepperContent({\n  value,\n  forceMount = false,\n  children,\n  className,\n  ...props\n}: StepperContentProps) {\n  const { value: activeValue } = useStepper(\"StepperContent\");\n  const active = activeValue === value;\n  if (!active && !forceMount) return null;\n\n  return (\n    <div\n      hidden={!active && !forceMount}\n      aria-hidden={!active && !forceMount}\n      className={cn(\"min-w-0\", className)}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport default Stepper;\n",
      "target": "components/ui/stepper/stepper.tsx"
    }
  ],
  "dependencies": [],
  "registryDependencies": [
    "@sona-ui/sona-utils"
  ]
}