{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stepper",
  "title": "Stepper",
  "description": "Multi-step flows with linear or free navigation.",
  "dependencies": [
    "@base-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/base/ui/stepper.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { CheckIcon } from \"lucide-react\"\nimport { Tabs as TabsPrimitive } from \"@base-ui/react/tabs\"\nimport { useRender } from \"@base-ui/react/use-render\"\n\nimport { cn } from \"@/registry/default/lib/utils\"\n\ntype StepState = \"completed\" | \"active\" | \"upcoming\"\n\ntype StepperContextValue = {\n  activeStep: number\n  furthestStep: number\n  setActiveStep: (step: number) => void\n  isLinear: boolean\n  stepCount?: number\n}\n\nconst StepperContext = React.createContext<StepperContextValue | null>(null)\nconst StepperItemContext = React.createContext<{\n  step: number\n  state: StepState\n} | null>(null)\n\nfunction useStepper() {\n  const context = React.useContext(StepperContext)\n  if (!context) throw new Error(\"useStepper must be used within <Stepper>\")\n  return context\n}\n\nfunction useStepperItem() {\n  const context = React.useContext(StepperItemContext)\n  if (!context)\n    throw new Error(\"Stepper parts must be used within <StepperItem>\")\n  return context\n}\n\nfunction Stepper({\n  value,\n  defaultValue = 0,\n  onValueChange,\n  linear = false,\n  stepCount,\n  orientation = \"horizontal\",\n  className,\n  ...props\n}: Omit<\n  TabsPrimitive.Root.Props,\n  \"value\" | \"defaultValue\" | \"onValueChange\"\n> & {\n  value?: number\n  defaultValue?: number\n  onValueChange?: (step: number) => void\n  linear?: boolean\n  stepCount?: number\n}) {\n  const [uncontrolledStep, setUncontrolledStep] = React.useState(defaultValue)\n  const activeStep = value ?? uncontrolledStep\n  const [furthestStep, setFurthestStep] = React.useState(activeStep)\n\n  if (activeStep > furthestStep) setFurthestStep(activeStep)\n\n  function setActiveStep(step: number) {\n    if (value === undefined) setUncontrolledStep(step)\n    onValueChange?.(step)\n  }\n\n  return (\n    <StepperContext.Provider\n      value={{\n        activeStep,\n        furthestStep,\n        setActiveStep,\n        isLinear: linear,\n        stepCount,\n      }}\n    >\n      <TabsPrimitive.Root\n        data-slot=\"stepper\"\n        value={activeStep}\n        onValueChange={(next: number) => setActiveStep(next)}\n        orientation={orientation}\n        className={cn(\n          \"group/stepper flex gap-6 data-[orientation=horizontal]:flex-col\",\n          className\n        )}\n        {...props}\n      />\n    </StepperContext.Provider>\n  )\n}\n\nfunction StepperList({ className, ...props }: TabsPrimitive.List.Props) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"stepper-list\"\n      className={cn(\n        \"flex gap-2 group-data-[orientation=horizontal]/stepper:items-center group-data-[orientation=vertical]/stepper:flex-col\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction StepperItem({\n  step,\n  className,\n  ...props\n}: React.ComponentProps<\"div\"> & { step: number }) {\n  const { activeStep } = useStepper()\n  const state: StepState =\n    step < activeStep\n      ? \"completed\"\n      : step === activeStep\n        ? \"active\"\n        : \"upcoming\"\n\n  return (\n    <StepperItemContext.Provider value={{ step, state }}>\n      <div\n        data-slot=\"stepper-item\"\n        data-state={state}\n        className={cn(\n          \"group/step flex flex-1 gap-2 group-data-[orientation=horizontal]/stepper:items-center group-data-[orientation=vertical]/stepper:flex-col last:flex-none\",\n          className\n        )}\n        {...props}\n      />\n    </StepperItemContext.Provider>\n  )\n}\n\nfunction StepperTrigger({\n  className,\n  disabled,\n  ...props\n}: Omit<TabsPrimitive.Tab.Props, \"value\">) {\n  const { furthestStep, isLinear } = useStepper()\n  const { step } = useStepperItem()\n\n  return (\n    <TabsPrimitive.Tab\n      data-slot=\"stepper-trigger\"\n      value={step}\n      disabled={disabled || (isLinear && step > furthestStep)}\n      className={cn(\n        \"flex shrink-0 items-center gap-2.5 rounded-md text-left outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 data-disabled:pointer-events-none data-disabled:opacity-60\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction StepperIndicator({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  const { step, state } = useStepperItem()\n\n  return (\n    <span\n      data-slot=\"stepper-indicator\"\n      data-state={state}\n      className={cn(\n        \"flex size-7 shrink-0 items-center justify-center rounded-full border text-xs font-medium text-muted-foreground tabular-nums transition-colors\",\n        \"data-[state=active]:border-primary data-[state=active]:text-foreground data-[state=active]:ring-[3px] data-[state=active]:ring-primary/15\",\n        \"data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground\",\n        className\n      )}\n      {...props}\n    >\n      {children ??\n        (state === \"completed\" ? <CheckIcon className=\"size-3.5\" /> : step + 1)}\n    </span>\n  )\n}\n\nfunction StepperTitle({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"stepper-title\"\n      className={cn(\n        \"text-sm font-medium group-data-[state=upcoming]/step:text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction StepperDescription({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"stepper-description\"\n      className={cn(\"block text-xs text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction StepperSeparator({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"stepper-separator\"\n      aria-hidden\n      className={cn(\n        \"flex-1 bg-border transition-colors group-last/step:hidden group-data-[state=completed]/step:bg-primary\",\n        \"group-data-[orientation=horizontal]/stepper:h-px group-data-[orientation=horizontal]/stepper:min-w-6\",\n        \"group-data-[orientation=vertical]/stepper:ml-3.5 group-data-[orientation=vertical]/stepper:min-h-6 group-data-[orientation=vertical]/stepper:w-px\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction StepperContent({\n  step,\n  className,\n  ...props\n}: Omit<TabsPrimitive.Panel.Props, \"value\"> & {\n  step: number\n}) {\n  return (\n    <TabsPrimitive.Panel\n      data-slot=\"stepper-content\"\n      value={step}\n      className={cn(\"flex-1 outline-none\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SlotButton({\n  asChild,\n  children,\n  ...props\n}: React.ComponentProps<\"button\"> & { asChild: boolean }) {\n  return useRender({\n    defaultTagName: \"button\",\n    render: asChild ? (children as React.ReactElement) : undefined,\n    props: asChild ? props : { ...props, children },\n  })\n}\n\nfunction StepperPrevious({\n  asChild = false,\n  disabled,\n  onClick,\n  ...props\n}: React.ComponentProps<\"button\"> & { asChild?: boolean }) {\n  const { activeStep, setActiveStep } = useStepper()\n\n  return (\n    <SlotButton\n      asChild={asChild}\n      data-slot=\"stepper-previous\"\n      type=\"button\"\n      disabled={disabled || activeStep === 0}\n      onClick={(event: React.MouseEvent<HTMLButtonElement>) => {\n        onClick?.(event)\n        if (!event.defaultPrevented) setActiveStep(activeStep - 1)\n      }}\n      {...props}\n    />\n  )\n}\n\nfunction StepperNext({\n  asChild = false,\n  disabled,\n  onClick,\n  ...props\n}: React.ComponentProps<\"button\"> & { asChild?: boolean }) {\n  const { activeStep, setActiveStep, stepCount } = useStepper()\n  const isLastStep = stepCount !== undefined && activeStep >= stepCount - 1\n\n  return (\n    <SlotButton\n      asChild={asChild}\n      data-slot=\"stepper-next\"\n      type=\"button\"\n      disabled={disabled || isLastStep}\n      onClick={(event: React.MouseEvent<HTMLButtonElement>) => {\n        onClick?.(event)\n        if (!event.defaultPrevented) setActiveStep(activeStep + 1)\n      }}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Stepper,\n  StepperList,\n  StepperItem,\n  StepperTrigger,\n  StepperIndicator,\n  StepperTitle,\n  StepperDescription,\n  StepperSeparator,\n  StepperContent,\n  StepperPrevious,\n  StepperNext,\n  useStepper,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}