{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "onboarding-wizard",
  "title": "Onboarding Wizard",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/onboarding-wizard/OnboardingWizard.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { Check, ChevronLeft, ChevronRight, Globe, Plus, X } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { SectionCard } from '@/components/ui/section-card'\nimport { Stepper } from '@/components/ui/stepper'\nimport { Switch } from '@/components/ui/switch'\n\ninterface Preference {\n  id: string\n  label: string\n  description: string\n  enabled: boolean\n}\n\nexport interface OnboardingWizardProps {\n  /** Jump straight to a step (1 Workspace · 2 Team · 3 Preferences · 4 Done). */\n  initialStep?: number\n  /** Pre-fill the workspace name so later steps read naturally in isolation. */\n  initialWorkspaceName?: string\n  /** Pre-seed invited teammates. */\n  initialInvites?: string[]\n  className?: string\n}\n\nconst steps = [\n  { id: 1, title: 'Workspace' },\n  { id: 2, title: 'Team' },\n  { id: 3, title: 'Preferences' },\n  { id: 4, title: 'Done' },\n]\n\nconst defaultPreferences: Preference[] = [\n  {\n    id: 'digests',\n    label: 'Email digests',\n    description: 'A daily summary of workspace activity.',\n    enabled: true,\n  },\n  {\n    id: 'updates',\n    label: 'Product updates',\n    description: 'Occasional notes about new features and improvements.',\n    enabled: false,\n  },\n  {\n    id: 'reports',\n    label: 'Weekly reports',\n    description: 'Usage analytics delivered every Monday morning.',\n    enabled: true,\n  },\n]\n\nexport function OnboardingWizard({\n  initialStep = 1,\n  initialWorkspaceName = 'Acme Inc',\n  initialInvites = [],\n  className,\n}: OnboardingWizardProps) {\n  const [step, setStep] = React.useState(initialStep)\n  const [workspaceName, setWorkspaceName] = React.useState(initialWorkspaceName)\n  const [invites, setInvites] = React.useState<string[]>(initialInvites)\n  const [inviteDraft, setInviteDraft] = React.useState('')\n  const [inviteInvalid, setInviteInvalid] = React.useState(false)\n  const [preferences, setPreferences] = React.useState<Preference[]>(defaultPreferences)\n\n  const slug =\n    workspaceName\n      .trim()\n      .toLowerCase()\n      .replace(/[^a-z0-9]+/g, '-')\n      .replace(/^-+|-+$/g, '') || 'your-workspace'\n\n  function addInvite() {\n    const email = inviteDraft.trim()\n    if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email) || invites.includes(email)) {\n      setInviteInvalid(true)\n      return\n    }\n    setInviteInvalid(false)\n    setInvites((prev) => [...prev, email])\n    setInviteDraft('')\n  }\n\n  function removeInvite(email: string) {\n    setInvites((prev) => prev.filter((e) => e !== email))\n  }\n\n  function onStepperInput(value: number) {\n    // Free backward navigation; forward goes through the footer button only.\n    if (value < step && step !== 4) setStep(value)\n  }\n\n  function goNext() {\n    if (step < 4) setStep(step + 1)\n  }\n\n  function reset() {\n    setStep(1)\n    setWorkspaceName('')\n    setInvites([])\n    setInviteDraft('')\n  }\n\n  return (\n    <SectionCard\n      data-slot=\"onboarding-wizard\"\n      title=\"Set up your workspace\"\n      description=\"Four quick steps and your team is ready to collaborate.\"\n      className={className}\n      footer={\n        <div className=\"flex w-full items-center justify-between\">\n          {step > 1 && step < 4 ? (\n            <Button variant=\"ghost\" size=\"sm\" onClick={() => setStep(step - 1)}>\n              <ChevronLeft aria-hidden=\"true\" />\n              Back\n            </Button>\n          ) : (\n            <span aria-hidden=\"true\" />\n          )}\n          <span className=\"text-muted-foreground text-xs\">Step {step} of 4</span>\n          {step < 4 ? (\n            <Button size=\"sm\" disabled={step === 1 && workspaceName.trim() === ''} onClick={goNext}>\n              {step === 3 ? 'Finish' : 'Continue'}\n              <ChevronRight aria-hidden=\"true\" />\n            </Button>\n          ) : (\n            <span aria-hidden=\"true\" />\n          )}\n        </div>\n      }\n    >\n      <Stepper steps={steps} value={step} onValueChange={onStepperInput} className=\"mb-6\" />\n\n      {step === 1 && (\n        <div className=\"space-y-4\">\n          <div className=\"space-y-2\">\n            <label htmlFor=\"onboarding-workspace-name\" className=\"text-sm font-medium\">\n              Workspace name\n            </label>\n            <Input\n              id=\"onboarding-workspace-name\"\n              value={workspaceName}\n              onChange={(e) => setWorkspaceName(e.target.value)}\n              placeholder=\"Acme Inc\"\n              autoComplete=\"off\"\n            />\n          </div>\n          <div className=\"border-border bg-muted/40 flex items-center gap-2 rounded-md border px-3 py-2\">\n            <Globe className=\"text-muted-foreground size-4 shrink-0\" aria-hidden=\"true\" />\n            <p className=\"min-w-0 truncate text-xs\">\n              <span className=\"text-muted-foreground\">uipkge.dev/</span>\n              <span className=\"text-foreground font-medium\">{slug}</span>\n            </p>\n          </div>\n        </div>\n      )}\n\n      {step === 2 && (\n        <div className=\"space-y-4\">\n          <form\n            className=\"flex gap-2\"\n            onSubmit={(e) => {\n              e.preventDefault()\n              addInvite()\n            }}\n          >\n            <Input\n              value={inviteDraft}\n              onChange={(e) => {\n                setInviteDraft(e.target.value)\n                setInviteInvalid(false)\n              }}\n              type=\"email\"\n              placeholder=\"teammate@company.com\"\n              status={inviteInvalid ? 'error' : undefined}\n              className=\"flex-1\"\n            />\n            <Button type=\"submit\" variant=\"outline\" size=\"sm\" className=\"shrink-0\">\n              <Plus aria-hidden=\"true\" />\n              Add\n            </Button>\n          </form>\n          {inviteInvalid && (\n            <p role=\"alert\" className=\"text-destructive text-xs\">\n              Enter a valid email address.\n            </p>\n          )}\n          {invites.length > 0 ? (\n            <div className=\"flex flex-wrap gap-2\">\n              {invites.map((email) => (\n                <Badge key={email} variant=\"secondary\" className=\"gap-1 py-1 pr-1 pl-2.5\">\n                  {email}\n                  <button\n                    type=\"button\"\n                    aria-label={`Remove ${email}`}\n                    className=\"hover:bg-foreground/10 focus-visible:ring-ring min-h-6 rounded-full p-0.5 transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n                    onClick={() => removeInvite(email)}\n                  >\n                    <X className=\"size-3\" aria-hidden=\"true\" />\n                  </button>\n                </Badge>\n              ))}\n            </div>\n          ) : (\n            <p className=\"text-muted-foreground text-xs\">No teammates invited yet.</p>\n          )}\n          <button\n            type=\"button\"\n            className=\"text-muted-foreground hover:text-foreground focus-visible:ring-ring min-h-6 text-xs underline-offset-4 transition-colors hover:underline focus-visible:ring-2 focus-visible:outline-none\"\n            onClick={goNext}\n          >\n            Skip for now\n          </button>\n        </div>\n      )}\n\n      {step === 3 && (\n        <div className=\"divide-y rounded-lg border\">\n          {preferences.map((pref) => (\n            <div key={pref.id} className=\"flex items-center justify-between gap-4 p-4\">\n              <div className=\"min-w-0\">\n                <p className=\"text-sm font-medium\">{pref.label}</p>\n                <p className=\"text-muted-foreground mt-0.5 text-xs\">{pref.description}</p>\n              </div>\n              <Switch\n                aria-label={pref.label}\n                checked={pref.enabled}\n                onCheckedChange={(checked) =>\n                  setPreferences((prev) => prev.map((p) => (p.id === pref.id ? { ...p, enabled: checked } : p)))\n                }\n              />\n            </div>\n          ))}\n        </div>\n      )}\n\n      {step === 4 && (\n        <div className=\"space-y-4 py-6 text-center\">\n          <div className=\"border-success/30 bg-success/10 text-success mx-auto flex size-16 items-center justify-center rounded-full border shadow-xs\">\n            <Check className=\"size-8\" aria-hidden=\"true\" />\n          </div>\n          <div>\n            <p className=\"text-lg font-semibold\">You're all set</p>\n            <p className=\"text-muted-foreground mx-auto mt-1 max-w-sm text-sm\">\n              {invites.length > 0\n                ? `${workspaceName || 'Your workspace'} is ready and ${invites.length} invitation${invites.length === 1 ? '' : 's'} sent.`\n                : `${workspaceName || 'Your workspace'} is ready — invite teammates anytime from settings.`}\n            </p>\n          </div>\n          <Button variant=\"outline\" size=\"sm\" onClick={reset}>\n            Set up another workspace\n          </Button>\n        </div>\n      )}\n    </SectionCard>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/OnboardingWizard.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/section-card.json",
    "https://uipkge.dev/r/react/stepper.json",
    "https://uipkge.dev/r/react/switch.json"
  ],
  "description": "Multi-step workspace setup flow in a SectionCard: a four-step Stepper (Workspace → Team → Preferences → Done) with check icons on completed steps, a workspace-name input with live URL slug preview, teammate invites as removable email chips with a skip link, preference Switch rows, and a success panel with a glowing check circle. Footer carries Back/Continue actions plus a Step X of 4 counter. Data is stubbed inline — wire your API of choice.",
  "categories": [
    "auth",
    "app",
    "onboarding"
  ]
}