{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "onboarding-checklist",
  "title": "Onboarding checklist",
  "description": "A collapsible getting-started card with a progress meter and the next step marked.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/onboarding-checklist/onboarding-checklist.tsx",
      "content": "// Based on Watermelon UI's “Onboarding checklist” (MIT, © 2026 Watermelon Platform Contributors,\n// github.com/WatermelonCorp/watermelon-platform). Rewritten with a real disclosure button and actionable steps.\nimport { Check, ChevronDown, ChevronRight } from 'lucide-react'\nimport { AnimatePresence, MotionConfig, motion } from 'motion/react'\nimport { useId, useState } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type ChecklistStep = {\n  id: string\n  title: string\n  done?: boolean\n  /** Runs when the person picks a step that is not done yet. */\n  onSelect?: () => void\n}\n\nexport type OnboardingChecklistProps = {\n  steps: ChecklistStep[]\n  title?: string\n  defaultOpen?: boolean\n  className?: string\n}\n\nconst BARS = 14\n\n/** A collapsible “getting started” card with a segmented progress meter. The first open step is marked as next. */\nexport function OnboardingChecklist({ steps, title = 'Getting started', defaultOpen = false, className }: OnboardingChecklistProps) {\n  const [open, setOpen] = useState(defaultOpen)\n  const panel = useId()\n  const done = steps.filter((s) => s.done).length\n  const next = steps.find((s) => !s.done)?.id\n  const spring = { type: 'spring', stiffness: 300, damping: 35 } as const\n\n  return (\n    <MotionConfig reducedMotion=\"user\" transition={spring}>\n      <motion.section layout style={{ borderRadius: 16 }} className={cn('relative w-full overflow-hidden rounded-2xl border bg-card text-card-foreground shadow-sm', className)}>\n        <motion.button\n          layout=\"position\"\n          type=\"button\"\n          aria-expanded={open}\n          aria-controls={panel}\n          onClick={() => setOpen(!open)}\n          className=\"flex min-h-14 w-full items-center gap-3 px-4 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\"\n        >\n          <ChevronDown className={cn('size-5 shrink-0 text-muted-foreground transition-transform duration-200', open && 'rotate-180')} aria-hidden />\n          <span className=\"min-w-0 flex-1 truncate font-semibold\">{title}</span>\n          <span className=\"flex shrink-0 items-center gap-3\">\n            <span\n              role=\"progressbar\"\n              aria-label=\"Progress\"\n              aria-valuemin={0}\n              aria-valuemax={steps.length}\n              aria-valuenow={done}\n              className=\"hidden gap-1 min-[400px]:flex\"\n            >\n              {Array.from({ length: BARS }, (_, i) => (\n                <span\n                  key={i}\n                  className={cn('h-4 w-1 rounded-full transition-colors duration-500', i < (done / Math.max(1, steps.length)) * BARS ? 'bg-primary' : 'bg-muted')}\n                />\n              ))}\n            </span>\n            <span className=\"font-mono text-sm text-muted-foreground tabular-nums\">\n              {done}/{steps.length}\n            </span>\n          </span>\n        </motion.button>\n\n        {/* The card grows with a layout (transform) animation; the list only fades. popLayout lets the card shrink while it fades out. */}\n        <AnimatePresence initial={false} mode=\"popLayout\">\n          {open && (\n            <motion.div\n              id={panel}\n              layout=\"position\"\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n              className=\"w-full border-t bg-background\"\n            >\n              <ol className=\"space-y-1 p-2\">\n                {steps.map((step, i) => (\n                  <li key={step.id}>\n                    <button\n                      type=\"button\"\n                      disabled={step.done}\n                      onClick={step.onSelect}\n                      aria-current={step.id === next ? 'step' : undefined}\n                      className=\"flex min-h-12 w-full items-center gap-3 rounded-xl px-3 text-left transition-colors duration-150 enabled:hover:bg-accent/60 disabled:cursor-default\"\n                    >\n                      {step.done ? (\n                        <span className=\"grid size-6 shrink-0 place-items-center rounded-full bg-primary text-primary-foreground\">\n                          <Check className=\"size-3.5\" strokeWidth={3} aria-hidden />\n                          <span className=\"sr-only\">Done:</span>\n                        </span>\n                      ) : (\n                        <span\n                          className={cn(\n                            'grid size-6 shrink-0 place-items-center rounded-full border-2 text-xs font-semibold',\n                            step.id === next ? 'border-foreground bg-foreground text-background' : 'text-muted-foreground',\n                          )}\n                        >\n                          {i + 1}\n                        </span>\n                      )}\n                      <span className={cn('min-w-0 flex-1 truncate text-sm font-medium', step.done && 'text-muted-foreground line-through decoration-muted-foreground/40')}>\n                        {step.title}\n                      </span>\n                      {!step.done && <ChevronRight className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />}\n                    </button>\n                  </li>\n                ))}\n              </ol>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </motion.section>\n    </MotionConfig>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "credit": "Adapted from Watermelon UI (MIT)."
  },
  "categories": [
    "widgets"
  ],
  "type": "registry:component"
}