{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["lucide-react","motion"],"description":"Categorized FAQ section with tab navigation","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { ChevronDown } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\n\nexport interface FaqCategorizedProps {\n  categories?: Array<{\n    name: string;\n    faqs: Array<{\n      question: string;\n      answer: string;\n    }>;\n  }>;\n  description?: string;\n  title?: string;\n}\n\nconst defaultCategories = [\n  {\n    faqs: [\n      {\n        answer:\n          \"Setting up SmoothUI is straightforward. Install the package using npm or pnpm, then import the components you need. Our CLI tool can also help scaffold components directly into your project with the right dependencies.\",\n        question: \"How do I set up SmoothUI in my project?\",\n      },\n      {\n        answer:\n          \"SmoothUI requires React 18 or later, Next.js 13+, and Node.js 18+. You'll also need Tailwind CSS configured in your project. All modern browsers are supported.\",\n        question: \"What are the minimum requirements?\",\n      },\n      {\n        answer:\n          \"Use our CLI command `npx shadcn@latest add @smoothui/component-name` to add any component. This will install the component with all its dependencies and place it in your components directory.\",\n        question: \"How do I add my first component?\",\n      },\n    ],\n    name: \"Getting Started\",\n  },\n  {\n    faqs: [\n      {\n        answer:\n          \"Yes, SmoothUI is completely free and open source under the MIT license. You can use it in personal and commercial projects without any cost or attribution requirements.\",\n        question: \"Is SmoothUI free to use?\",\n      },\n      {\n        answer:\n          \"Since SmoothUI is free, there are no purchases to refund. For any premium services or support packages we may offer in the future, our refund policy will be clearly stated.\",\n        question: \"Do you offer refunds?\",\n      },\n      {\n        answer:\n          \"Currently, all components are free. If we introduce premium features, we'll support major credit cards, PayPal, and other popular payment methods through our secure payment processor.\",\n        question: \"What payment methods do you accept?\",\n      },\n    ],\n    name: \"Billing\",\n  },\n  {\n    faqs: [\n      {\n        answer:\n          \"SmoothUI supports all modern browsers including Chrome, Firefox, Safari, and Edge. We test across the latest versions and one version back for each browser to ensure compatibility.\",\n        question: \"Which browsers are supported?\",\n      },\n      {\n        answer:\n          \"Components are optimized for performance with tree-shaking support, minimal bundle size, and hardware-accelerated animations. We only animate transform and opacity properties to ensure 60fps animations.\",\n        question: \"How does SmoothUI affect performance?\",\n      },\n      {\n        answer:\n          \"Absolutely! SmoothUI is built with TypeScript and provides full type definitions for all components. You get autocomplete, type checking, and inline documentation in supported editors.\",\n        question: \"Is TypeScript supported?\",\n      },\n      {\n        answer:\n          \"Yes, all components use Tailwind CSS and CSS variables for styling. You can override styles using className props, customize the design tokens, or modify the component source directly.\",\n        question: \"Can I customize component styles?\",\n      },\n    ],\n    name: \"Technical\",\n  },\n];\n\nexport function FaqCategorized({\n  title = \"Frequently Asked Questions\",\n  description = \"Find answers organized by topic\",\n  categories = defaultCategories,\n}: FaqCategorizedProps) {\n  const [activeCategory, setActiveCategory] = useState(0);\n  const [openIndex, setOpenIndex] = useState<number | null>(null);\n  const shouldReduceMotion = useReducedMotion();\n\n  const springTransition = shouldReduceMotion\n    ? { duration: 0 }\n    : { bounce: 0.05, duration: 0.25, type: \"spring\" as const };\n\n  const contentTransition = shouldReduceMotion\n    ? { duration: 0 }\n    : { bounce: 0, duration: 0.25, type: \"spring\" as const };\n\n  const handleCategoryChange = (index: number) => {\n    setActiveCategory(index);\n    setOpenIndex(null);\n  };\n\n  const toggleAccordion = (index: number) => {\n    setOpenIndex(openIndex === index ? null : index);\n  };\n\n  return (\n    <section className=\"py-20\">\n      <div className=\"mx-auto max-w-4xl px-6\">\n        <motion.div\n          animate={shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }}\n          className=\"mb-12 text-center\"\n          initial={shouldReduceMotion ? { opacity: 1 } : { opacity: 0, y: 20 }}\n          transition={springTransition}\n        >\n          <h2 className=\"mb-4 font-bold text-3xl text-foreground lg:text-4xl\">\n            {title}\n          </h2>\n          <p className=\"mx-auto max-w-2xl text-foreground/70 text-lg\">\n            {description}\n          </p>\n        </motion.div>\n\n        <motion.div\n          animate={shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }}\n          className=\"mb-8\"\n          initial={shouldReduceMotion ? { opacity: 1 } : { opacity: 0, y: 20 }}\n          transition={{\n            ...springTransition,\n            delay: shouldReduceMotion ? 0 : 0.1,\n          }}\n        >\n          <div\n            className=\"flex flex-wrap justify-center gap-2 border-border border-b\"\n            role=\"tablist\"\n          >\n            {categories.map((category, index) => (\n              <button\n                aria-selected={activeCategory === index}\n                className={`relative px-4 py-3 font-medium text-sm transition-colors ${\n                  activeCategory === index\n                    ? \"text-brand\"\n                    : \"text-foreground/60 hover:text-foreground\"\n                }`}\n                key={category.name}\n                onClick={() => handleCategoryChange(index)}\n                role=\"tab\"\n                type=\"button\"\n              >\n                {category.name}\n                {activeCategory === index && (\n                  <motion.div\n                    className=\"absolute right-0 bottom-0 left-0 h-0.5 bg-brand\"\n                    layoutId=\"categoryIndicator\"\n                    transition={springTransition}\n                  />\n                )}\n              </button>\n            ))}\n          </div>\n        </motion.div>\n\n        <AnimatePresence mode=\"wait\">\n          <motion.div\n            animate={shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }}\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0, transition: { duration: 0 } }\n                : { opacity: 0, y: -10 }\n            }\n            initial={\n              shouldReduceMotion ? { opacity: 1 } : { opacity: 0, y: 10 }\n            }\n            key={activeCategory}\n            transition={springTransition}\n          >\n            <div className=\"space-y-4\">\n              {categories[activeCategory].faqs.map((faq, index) => {\n                const isOpen = openIndex === index;\n\n                return (\n                  <motion.div\n                    animate={\n                      shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }\n                    }\n                    className=\"overflow-hidden rounded-xl border border-border bg-background transition-colors hover:border-brand\"\n                    initial={\n                      shouldReduceMotion\n                        ? { opacity: 1 }\n                        : { opacity: 0, y: 20 }\n                    }\n                    key={faq.question}\n                    transition={{\n                      ...springTransition,\n                      delay: shouldReduceMotion ? 0 : index * 0.05,\n                    }}\n                  >\n                    <button\n                      aria-expanded={isOpen}\n                      className=\"flex w-full cursor-pointer items-center justify-between p-5 text-left transition-colors hover:bg-background/50\"\n                      onClick={() => toggleAccordion(index)}\n                      type=\"button\"\n                    >\n                      <h3 className=\"pr-4 font-medium text-foreground\">\n                        {faq.question}\n                      </h3>\n                      <motion.div\n                        animate={{ rotate: isOpen ? 180 : 0 }}\n                        className=\"flex-shrink-0\"\n                        transition={springTransition}\n                      >\n                        <ChevronDown\n                          aria-hidden=\"true\"\n                          className=\"h-5 w-5 text-foreground/60\"\n                        />\n                      </motion.div>\n                    </button>\n\n                    <AnimatePresence>\n                      {isOpen && (\n                        <motion.div\n                          animate={\n                            shouldReduceMotion\n                              ? { height: \"auto\", opacity: 1 }\n                              : { height: \"auto\", opacity: 1 }\n                          }\n                          className=\"overflow-hidden\"\n                          exit={\n                            shouldReduceMotion\n                              ? {\n                                  height: 0,\n                                  opacity: 0,\n                                  transition: { duration: 0 },\n                                }\n                              : { height: 0, opacity: 0 }\n                          }\n                          initial={\n                            shouldReduceMotion\n                              ? { height: \"auto\", opacity: 1 }\n                              : { height: 0, opacity: 0 }\n                          }\n                          transition={contentTransition}\n                        >\n                          <div className=\"px-5 pb-5\">\n                            <p className=\"text-foreground/70 leading-relaxed\">\n                              {faq.answer}\n                            </p>\n                          </div>\n                        </motion.div>\n                      )}\n                    </AnimatePresence>\n                  </motion.div>\n                );\n              })}\n            </div>\n          </motion.div>\n        </AnimatePresence>\n      </div>\n    </section>\n  );\n}\n\nexport default FaqCategorized;\n","path":"index.tsx","target":"components/smoothui/faq-4/index.tsx","type":"registry:block"}],"name":"faq-4","registryDependencies":["https://smoothui.dev/r/tokens.json"],"title":"Faq 4","type":"registry:block"}