{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "timeline",
  "title": "Timeline",
  "description": "A timeline component.",
  "dependencies": [
    "class-variance-authority"
  ],
  "files": [
    {
      "path": "registry/default/timeline/timeline.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst timelineVariants = cva(\"group/timeline flex\", {\n  variants: {\n    orientation: {\n      horizontal: \"w-full flex-row\",\n      vertical: \"flex-col\",\n    },\n  },\n  defaultVariants: {\n    orientation: \"vertical\",\n  },\n});\n\nconst timelineIndicatorVariants = cva(\n  \"absolute flex items-center justify-center rounded-full border-2 transition-all duration-200 size-6\",\n  {\n    variants: {\n      state: {\n        pending:\n          \"border-border/80 bg-muted shadow-[0_1px_2px_0_oklch(0.18_0_0_/_0.08)]\",\n        current:\n          \"border-primary bg-primary/5 outline-2 outline-primary/20 outline-offset-2 shadow-[0_1px_2px_0_oklch(0.18_0_0_/_0.08)]\",\n        completed:\n          \"border-primary bg-primary text-primary-foreground shadow-[0_1px_2px_0_oklch(0.18_0_0_/_0.08)]\",\n      },\n    },\n    defaultVariants: {\n      state: \"pending\",\n    },\n  },\n);\n\nconst timelineSeparatorVariants = cva(\n  \"absolute bg-border transition-all duration-200 group-last/timeline-item:hidden\",\n  {\n    variants: {\n      orientation: {\n        horizontal: \"h-0.5 w-[calc(100%-2rem)] -top-6 left-7 -translate-y-1/2\",\n        vertical: \"w-0.5 h-[calc(100%-2rem)] -left-6 top-7 -translate-x-1/2\",\n      },\n      state: {\n        pending: \"bg-border\",\n        completed: \"bg-primary/40\",\n      },\n    },\n    defaultVariants: {\n      orientation: \"vertical\",\n      state: \"pending\",\n    },\n  },\n);\n\ntype TimelineContextValue = {\n  activeStep: number;\n  setActiveStep: (step: number) => void;\n  orientation: \"horizontal\" | \"vertical\";\n};\n\nconst TimelineContext = React.createContext<TimelineContextValue | undefined>(\n  undefined,\n);\n\nconst TimelineItemContext = React.createContext<{ step: number } | undefined>(\n  undefined,\n);\n\nconst useTimeline = () => {\n  const context = React.useContext(TimelineContext);\n  if (!context) {\n    throw new Error(\"useTimeline must be used within a Timeline\");\n  }\n  return context;\n};\n\ntype RenderFunction<T> = (\n  props: T,\n  ref: React.Ref<HTMLElement>,\n) => React.ReactElement | null;\n\ninterface TimelineProps\n  extends\n    useRender.ComponentProps<\"div\">,\n    VariantProps<typeof timelineVariants> {\n  defaultValue?: number;\n  value?: number;\n  onValueChange?: (value: number) => void;\n}\n\nfunction Timeline({\n  defaultValue = 1,\n  value,\n  onValueChange,\n  orientation = \"vertical\",\n  className,\n  render,\n  ...props\n}: TimelineProps) {\n  const [activeStep, setInternalStep] = React.useState(defaultValue);\n\n  const setActiveStep = React.useCallback(\n    (step: number) => {\n      if (value === undefined) {\n        setInternalStep(step);\n      }\n      onValueChange?.(step);\n    },\n    [value, onValueChange],\n  );\n\n  const currentStep = value ?? activeStep;\n\n  const defaultProps = {\n    className: cn(\n      timelineVariants({ orientation: orientation || \"vertical\" }),\n      className,\n    ),\n    \"data-orientation\": orientation,\n    \"data-slot\": \"timeline\",\n  };\n\n  const element = useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(defaultProps, props),\n  });\n\n  return (\n    <TimelineContext.Provider\n      value={{\n        activeStep: currentStep,\n        setActiveStep,\n        orientation: orientation || \"vertical\",\n      }}\n    >\n      {element}\n    </TimelineContext.Provider>\n  );\n}\n\ninterface TimelineContentProps extends React.HTMLAttributes<HTMLDivElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLDivElement>>;\n}\n\nfunction TimelineContent({\n  className,\n  render,\n  ...props\n}: TimelineContentProps) {\n  const contentProps = mergeProps(props, {\n    className: cn(\"text-muted-foreground text-sm leading-relaxed\", className),\n    \"data-slot\": \"timeline-content\",\n  });\n\n  return render ? render(contentProps, null) : <div {...contentProps} />;\n}\n\ninterface TimelineDateProps extends React.HTMLAttributes<HTMLTimeElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLTimeElement>>;\n}\n\nfunction TimelineDate({ className, render, ...props }: TimelineDateProps) {\n  const dateProps = mergeProps(props, {\n    className: cn(\n      \"text-muted-foreground mb-1 block text-xs font-medium tabular-nums\",\n      className,\n    ),\n    \"data-slot\": \"timeline-date\",\n  });\n\n  return render ? render(dateProps, null) : <time {...dateProps} />;\n}\n\ninterface TimelineHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLDivElement>>;\n}\n\nfunction TimelineHeader({ className, render, ...props }: TimelineHeaderProps) {\n  const headerProps = mergeProps(props, {\n    className: cn(className),\n    \"data-slot\": \"timeline-header\",\n  });\n\n  return render ? render(headerProps, null) : <div {...headerProps} />;\n}\n\ninterface TimelineIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLDivElement>>;\n}\n\nfunction TimelineIndicator({\n  className,\n  children,\n  render,\n  ...props\n}: TimelineIndicatorProps) {\n  const { orientation, activeStep } = useTimeline();\n  const currentItem = React.useContext(TimelineItemContext);\n\n  const state = currentItem\n    ? currentItem.step < activeStep\n      ? \"completed\"\n      : currentItem.step === activeStep\n        ? \"current\"\n        : \"pending\"\n    : \"pending\";\n\n  const indicatorProps = mergeProps(props, {\n    className: cn(\n      timelineIndicatorVariants({ state }),\n      (orientation || \"vertical\") === \"horizontal\"\n        ? \"-top-6 left-0 -translate-y-1/2\"\n        : \"top-0 -left-6 -translate-x-1/2\",\n      className,\n    ),\n    \"aria-hidden\": \"true\",\n    \"data-slot\": \"timeline-indicator\",\n    \"data-state\": state,\n  });\n\n  return render ? (\n    render(indicatorProps, null)\n  ) : (\n    <div {...indicatorProps}>{children}</div>\n  );\n}\n\ninterface TimelineItemProps extends React.HTMLAttributes<HTMLDivElement> {\n  step: number;\n  render?: RenderFunction<React.HTMLAttributes<HTMLDivElement>>;\n}\n\nfunction TimelineItem({\n  step,\n  className,\n  render,\n  ...props\n}: TimelineItemProps) {\n  const { activeStep, orientation } = useTimeline();\n  const isCompleted = step <= activeStep;\n  const isCurrent = step === activeStep;\n\n  const itemProps = mergeProps(props, {\n    className: cn(\n      \"group/timeline-item relative flex flex-1 flex-col gap-2\",\n      orientation === \"horizontal\"\n        ? \"mt-8 not-last:pe-8\"\n        : \"ms-8 not-last:pb-16\",\n      className,\n    ),\n    \"data-completed\": isCompleted || undefined,\n    \"data-current\": isCurrent || undefined,\n    \"data-slot\": \"timeline-item\",\n  });\n\n  return (\n    <TimelineItemContext.Provider value={{ step }}>\n      {render ? render(itemProps, null) : <div {...itemProps} />}\n    </TimelineItemContext.Provider>\n  );\n}\n\ninterface TimelineSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLDivElement>>;\n}\n\nfunction TimelineSeparator({\n  className,\n  render,\n  ...props\n}: TimelineSeparatorProps) {\n  const { orientation, activeStep } = useTimeline();\n  const currentItem = React.useContext(TimelineItemContext);\n\n  const isCompleted = currentItem ? currentItem.step < activeStep : false;\n  const state = isCompleted ? \"completed\" : \"pending\";\n\n  const separatorProps = mergeProps(props, {\n    className: cn(\n      timelineSeparatorVariants({\n        orientation: orientation || \"vertical\",\n        state,\n      }),\n      className,\n    ),\n    \"aria-hidden\": \"true\",\n    \"data-slot\": \"timeline-separator\",\n    \"data-state\": state,\n  });\n\n  return render ? render(separatorProps, null) : <div {...separatorProps} />;\n}\n\ninterface TimelineTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n  render?: RenderFunction<React.HTMLAttributes<HTMLHeadingElement>>;\n}\n\nfunction TimelineTitle({ className, render, ...props }: TimelineTitleProps) {\n  const titleProps = mergeProps(props, {\n    className: cn(\"text-sm font-semibold leading-none\", className),\n    \"data-slot\": \"timeline-title\",\n  });\n\n  return render ? render(titleProps, null) : <h3 {...titleProps} />;\n}\n\nexport {\n  Timeline,\n  TimelineContent,\n  TimelineDate,\n  TimelineHeader,\n  TimelineIndicator,\n  TimelineItem,\n  TimelineSeparator,\n  TimelineTitle,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/timeline.tsx"
    }
  ],
  "type": "registry:ui"
}