{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "accordion",
  "type": "registry:component",
  "title": "Accordion",
  "description": "Collapsible content sections supporting single or multiple open items.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/accordion/accordion.tsx",
      "content": "\"use client\";\n\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useMemo,\n  useState,\n} from \"react\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\n\n// Context for accordion state\ntype AccordionContextValue = {\n  openItems: Set<string>;\n  toggleItem: (value: string) => void;\n  type: \"multiple\" | \"single\";\n};\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null);\n\nfunction useAccordionContext(): AccordionContextValue {\n  const context = useContext(AccordionContext);\n  if (!context) {\n    throw new Error(\"AccordionItem must be used within an Accordion\");\n  }\n  return context;\n}\n\nexport type AccordionProps = {\n  children: ReactNode;\n  className?: string;\n  defaultValue?: string | string[];\n  type?: \"multiple\" | \"single\";\n};\n\nfunction Accordion({\n  children,\n  className,\n  defaultValue,\n  type = \"single\",\n}: AccordionProps): React.ReactNode {\n  const [openItems, setOpenItems] = useState<Set<string>>(() => {\n    if (!defaultValue) return new Set();\n    if (Array.isArray(defaultValue)) return new Set(defaultValue);\n    return new Set([defaultValue]);\n  });\n\n  const toggleItem = useCallback(\n    (value: string) => {\n      setOpenItems((previous) => {\n        const newSet = new Set(previous);\n        if (newSet.has(value)) {\n          newSet.delete(value);\n        } else {\n          if (type === \"single\") {\n            newSet.clear();\n          }\n          newSet.add(value);\n        }\n        return newSet;\n      });\n    },\n    [type],\n  );\n\n  const contextValue = useMemo(\n    () => ({ openItems, toggleItem, type }),\n    [openItems, toggleItem, type],\n  );\n\n  return (\n    <AccordionContext.Provider value={contextValue}>\n      <div\n        className={cn(\n          \"my-6 divide-y divide-border rounded-lg border\",\n          className,\n        )}\n      >\n        {children}\n      </div>\n    </AccordionContext.Provider>\n  );\n}\n\nexport type AccordionItemProps = {\n  children: ReactNode;\n  className?: string;\n  value: string;\n};\n\nfunction AccordionItem({\n  children,\n  className,\n  value,\n}: AccordionItemProps): React.ReactNode {\n  return (\n    <div\n      className={cn(\n        \"first:rounded-t-lg last:rounded-b-lg overflow-hidden\",\n        className,\n      )}\n      data-value={value}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport type AccordionTriggerProps = {\n  children: ReactNode;\n  className?: string;\n  icon?: ReactNode;\n  value: string;\n};\n\nfunction AccordionTrigger({\n  children,\n  className,\n  icon,\n  value,\n}: AccordionTriggerProps): React.ReactNode {\n  const { openItems, toggleItem } = useAccordionContext();\n  const isOpen = openItems.has(value);\n\n  return (\n    <button\n      aria-expanded={isOpen}\n      className={cn(\n        \"w-full flex items-center justify-between p-4 text-left font-medium transition-colors\",\n        \"hover:bg-muted/50\",\n        isOpen && \"bg-muted/30\",\n        className,\n      )}\n      onClick={() => {\n        toggleItem(value);\n      }}\n      type=\"button\"\n    >\n      <span className=\"text-sm\">{children}</span>\n      {icon ? (\n        <span\n          className={cn(\n            \"size-4 flex-shrink-0 transition-transform duration-200\",\n            isOpen && \"rotate-180\",\n          )}\n        >\n          {icon}\n        </span>\n      ) : (\n        <svg\n          className={cn(\n            \"size-4 flex-shrink-0 transition-transform duration-200\",\n            isOpen && \"rotate-180\",\n          )}\n          fill=\"none\"\n          stroke=\"currentColor\"\n          viewBox=\"0 0 24 24\"\n        >\n          <path\n            d=\"m6 9 6 6 6-6\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth={2}\n          />\n        </svg>\n      )}\n    </button>\n  );\n}\n\nexport type AccordionContentProps = {\n  children: ReactNode;\n  className?: string;\n  value: string;\n};\n\nfunction AccordionContent({\n  children,\n  className,\n  value,\n}: AccordionContentProps): React.ReactNode {\n  const { openItems } = useAccordionContext();\n  const isOpen = openItems.has(value);\n\n  return (\n    <div\n      className={cn(\n        \"overflow-hidden transition-all duration-200\",\n        isOpen ? \"max-h-[1000px] opacity-100\" : \"max-h-0 opacity-0\",\n      )}\n    >\n      <div\n        className={cn(\n          \"p-4 pt-0 text-sm text-muted-foreground [&>p]:mb-2 [&>pre]:my-2\",\n          className,\n        )}\n      >\n        {children}\n      </div>\n    </div>\n  );\n}\n\n// Attach sub-components\nAccordion.Item = AccordionItem;\nAccordion.Trigger = AccordionTrigger;\nAccordion.Content = AccordionContent;\n\nexport { Accordion, AccordionContent, AccordionItem, AccordionTrigger };\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
