{
  "name": "stepper",
  "type": "registry:ui",
  "title": "Stepper",
  "description": "Read-only or interactive ordered workflow progress with open, current, done and blocked states.",
  "registryDependencies": [
    "@siteplane/base"
  ],
  "dependencies": [
    "class-variance-authority@0.7.1",
    "lucide-react@1.18.0"
  ],
  "files": [
    {
      "path": "src/components/ui/stepper.tsx",
      "type": "registry:ui",
      "content": "import { Check, Lock } from \"lucide-react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport function Stepper({\n  className,\n  ...props\n}: React.ComponentProps<\"ol\">): React.ReactElement {\n  return (\n    <ol className={cn(\"flex flex-col\", className)} data-slot=\"stepper\" {...props} />\n  );\n}\n\nconst stepIndicatorVariants = cva(\n  \"relative z-10 flex size-6 shrink-0 items-center justify-center rounded-full border font-semibold text-xs ring-4 ring-background after:pointer-events-none after:absolute after:-inset-1 after:origin-center after:scale-75 after:rounded-full after:border after:border-transparent after:opacity-0 after:ring-1 after:ring-transparent after:transition-[opacity,transform,border-color] after:duration-(--motion-duration-fast) after:ease-(--motion-ease-apple-out) after:content-[''] motion-reduce:after:transition-none [&_svg]:size-3.5\",\n  {\n    defaultVariants: { status: \"open\" },\n    variants: {\n      status: {\n        blocked: \"border-warning border-dashed text-warning\",\n        current: \"border-primary text-foreground\",\n        done: \"border-success bg-success text-white\",\n        open: \"border-input text-muted-foreground\",\n      },\n    },\n  },\n);\n\ntype StepperItemStatus = VariantProps<typeof stepIndicatorVariants>[\"status\"];\n\nexport interface StepperItemProps\n  extends Omit<React.ComponentProps<\"li\">, \"title\">,\n    VariantProps<typeof stepIndicatorVariants> {\n  title: React.ReactNode;\n  description?: React.ReactNode;\n  index?: number;\n}\n\nexport function StepperItem({\n  className,\n  status = \"open\",\n  title,\n  description,\n  index,\n  children,\n  ...props\n}: StepperItemProps): React.ReactElement {\n  return (\n    <li\n      aria-current={status === \"current\" ? \"step\" : undefined}\n      className={cn(\n        \"relative flex gap-3 pb-5 last:pb-0\",\n        \"before:absolute before:top-7 before:bottom-0 before:left-3 before:w-px before:-translate-x-1/2 before:bg-border last:before:hidden\",\n        className,\n      )}\n      data-slot=\"stepper-item\"\n      data-status={status}\n      {...props}\n    >\n      <StepperIndicator index={index} status={status} />\n      <StepperContent description={description} status={status} title={title}>\n        {children}\n      </StepperContent>\n    </li>\n  );\n}\n\nexport interface StepperButtonItemProps\n  extends Omit<React.ComponentProps<\"button\">, \"title\">,\n    VariantProps<typeof stepIndicatorVariants> {\n  title: React.ReactNode;\n  description?: React.ReactNode;\n  index?: number;\n  current?: boolean;\n}\n\nexport function StepperButtonItem({\n  className,\n  status = \"open\",\n  title,\n  description,\n  index,\n  current = false,\n  children,\n  ...props\n}: StepperButtonItemProps): React.ReactElement {\n  return (\n    <li\n      className={cn(\n        \"relative flex pb-5 last:pb-0\",\n        \"before:absolute before:top-7 before:bottom-0 before:left-3 before:w-px before:-translate-x-1/2 before:bg-border last:before:hidden\",\n      )}\n      data-slot=\"stepper-item\"\n      data-status={status}\n    >\n      <button\n        aria-current={current ? \"step\" : undefined}\n        className={cn(\n          \"-m-1 flex min-w-0 flex-1 cursor-pointer gap-3 rounded-lg p-1 text-left outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-64\",\n          \"[&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:scale-100 [&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:border-muted-foreground/30 [&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:opacity-100 [&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:ring-muted-foreground/12 dark:[&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:border-white/24 dark:[&:not(:disabled):not([aria-current=step]):hover_[data-slot=stepper-indicator]]:after:ring-white/12\",\n          \"[&[aria-current=step]_[data-slot=stepper-indicator]]:after:scale-100 [&[aria-current=step]_[data-slot=stepper-indicator]]:after:border-primary/64 [&[aria-current=step]_[data-slot=stepper-indicator]]:after:opacity-100 [&[aria-current=step]_[data-slot=stepper-indicator]]:after:ring-primary/20 [&[aria-current=step]_[data-slot=stepper-title]]:text-foreground\",\n          className,\n        )}\n        data-slot=\"stepper-button-item\"\n        type=\"button\"\n        {...props}\n      >\n        <StepperIndicator index={index} status={status} />\n        <StepperContent description={description} status={status} title={title}>\n          {children}\n        </StepperContent>\n      </button>\n    </li>\n  );\n}\n\nfunction StepperIndicator({\n  index,\n  status,\n}: {\n  index?: number;\n  status: StepperItemStatus;\n}) {\n  return (\n    <span className={cn(stepIndicatorVariants({ status }))} data-slot=\"stepper-indicator\">\n      {status === \"done\" ? (\n        <Check />\n      ) : status === \"blocked\" ? (\n        <Lock />\n      ) : index != null ? (\n        index\n      ) : null}\n    </span>\n  );\n}\n\nfunction StepperContent({\n  children,\n  description,\n  status,\n  title,\n}: {\n  children?: React.ReactNode;\n  description?: React.ReactNode;\n  status: StepperItemStatus;\n  title: React.ReactNode;\n}) {\n  return (\n    <div className=\"min-w-0 flex-1 pt-0.5\">\n      <div\n        className={cn(\n          \"font-medium text-sm\",\n          status === \"open\" ? \"text-muted-foreground\" : \"text-foreground\",\n        )}\n        data-slot=\"stepper-title\"\n      >\n        {title}\n      </div>\n      {description ? (\n        <div className=\"mt-0.5 text-muted-foreground text-xs\" data-slot=\"stepper-description\">\n          {description}\n        </div>\n      ) : null}\n      {children}\n    </div>\n  );\n}\n"
    }
  ],
  "categories": [
    "navigation"
  ],
  "docs": "# Stepper\n\n> Siteplane UI release `0.1.1`.\n\n## Public Purpose\n\nUse Stepper to communicate ordered workflow progress or let users navigate between known steps.\n\n## Import\n\n```tsx\nimport { Stepper, StepperButtonItem, StepperItem } from \"@/components/ui/stepper\";\n```\n\n## Public API\n\n- `Stepper` renders the ordered-list root.\n- `StepperItem` is read-only; `StepperButtonItem` renders an interactive step button. Both accept `status=\"open\" | \"current\" | \"done\" | \"blocked\"`, `title`, `description`, `index` and `children`.\n- `children` render below the title and description inside the content slot, so a step can include supporting fields, actions or status details.\n- `StepperButtonItem` accepts normal button props including `disabled`; `current` sets `aria-current=\"step\"`.\n- `current` controls only the selected indicator ring. It does not mutate `status`, so checkmarks, numbers and locks remain stable when users navigate.\n\n## Public Motion\n\n- Indicator state uses the shared fast transition for its small focus/status accent.\n- Step content does not mount or collapse automatically. The operating-system reduced-motion preference removes the decorative indicator transition; the forced `reducedMotionPreset` shortens its shared fast duration from 140ms to 60ms.\n\n## Public Accessibility\n\n- Keep visual and DOM order identical and preserve the ordered-list structure.\n- Mark exactly one current step when the workflow has a current position.\n- Use `StepperButtonItem` only when clicking a step performs a real navigation or state change; disabled steps must remain clearly unavailable.\n\n## Public Agent Guidance\n\n- Use Timeline for read-only history and Stepper for ordered workflow progress.\n- Put supporting content in the documented `children` slot instead of creating a parallel item wrapper.\n- Do not make a read-only `StepperItem` appear clickable.\n\n## Public Links\n\n- [Documentation and preview](https://ui.siteplane.io/docs/components/navigation/stepper)\n\n- [Registry source](https://ui.siteplane.io/r/stepper.json)\n",
  "meta": {
    "siteplane:agentContractVersion": 1,
    "siteplane:docs": "https://ui.siteplane.io/docs/components/navigation/stepper",
    "siteplane:releaseVersion": "0.1.1",
    "siteplane:sourceOwned": true
  },
  "devDependencies": []
}
