{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["lucide-react","motion"],"description":"Searchable FAQ section with filter animations","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { ChevronDown, Search } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useMemo, useState } from \"react\";\n\nexport interface FaqSearchableProps {\n  description?: string;\n  faqs?: Array<{\n    question: string;\n    answer: string;\n  }>;\n  noResultsText?: string;\n  searchPlaceholder?: string;\n  title?: string;\n}\n\nconst defaultFaqs = [\n  {\n    answer:\n      \"Getting started is easy! Simply install the package via npm or pnpm, import the components you need, and start building. We provide comprehensive documentation and examples to help you get up and running quickly.\",\n    question: \"How do I get started with SmoothUI?\",\n  },\n  {\n    answer:\n      \"Yes! SmoothUI is completely free and open source. You can use it in both personal and commercial projects without any restrictions. We believe in making beautiful UI components accessible to everyone.\",\n    question: \"Is SmoothUI free to use?\",\n  },\n  {\n    answer:\n      \"SmoothUI requires React 18 or later and works with Next.js 13+. You'll also need Node.js 18+ and a modern browser that supports CSS animations and transforms.\",\n    question: \"What are the system requirements?\",\n  },\n  {\n    answer:\n      \"Absolutely! All animations are fully customizable. You can modify timing, easing, and effects using Motion (Framer Motion) props. We also respect the prefers-reduced-motion setting for accessibility.\",\n    question: \"Can I customize the animations?\",\n  },\n  {\n    answer:\n      \"You can report bugs by opening an issue on our GitHub repository. Please include a detailed description, steps to reproduce, and your environment details. We actively monitor and respond to issues.\",\n    question: \"How do I report bugs or issues?\",\n  },\n  {\n    answer:\n      \"Yes, we offer enterprise support packages that include priority bug fixes, dedicated support channels, custom component development, and SLA guarantees. Contact us for more information.\",\n    question: \"Is there enterprise support available?\",\n  },\n];\n\nexport function FaqSearchable({\n  title = \"Frequently Asked Questions\",\n  description = \"Search through our FAQ to find answers to your questions\",\n  searchPlaceholder = \"Search questions...\",\n  noResultsText = \"No matching questions found. Try a different search term.\",\n  faqs = defaultFaqs,\n}: FaqSearchableProps) {\n  const [searchQuery, setSearchQuery] = useState(\"\");\n  const [openIndex, setOpenIndex] = useState<number | null>(null);\n  const shouldReduceMotion = useReducedMotion();\n\n  const filteredFaqs = useMemo(() => {\n    if (!searchQuery.trim()) {\n      return faqs;\n    }\n    const query = searchQuery.toLowerCase();\n    return faqs.filter(\n      (faq) =>\n        faq.question.toLowerCase().includes(query) ||\n        faq.answer.toLowerCase().includes(query)\n    );\n  }, [faqs, searchQuery]);\n\n  const toggleAccordion = (index: number) => {\n    setOpenIndex(openIndex === index ? null : index);\n  };\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  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=\"relative mb-8\"\n          initial={shouldReduceMotion ? { opacity: 1 } : { opacity: 0, y: 20 }}\n          transition={{\n            ...springTransition,\n            delay: shouldReduceMotion ? 0 : 0.1,\n          }}\n        >\n          <Search className=\"absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 text-foreground/40\" />\n          <input\n            aria-label=\"Search frequently asked questions\"\n            className=\"w-full rounded-xl border border-border bg-background py-4 pr-4 pl-12 text-foreground transition-colors placeholder:text-foreground/40 focus:border-brand focus:outline-none focus:ring-2 focus:ring-brand/20\"\n            onChange={(e) => {\n              setSearchQuery(e.target.value);\n              setOpenIndex(null);\n            }}\n            placeholder={searchPlaceholder}\n            type=\"text\"\n            value={searchQuery}\n          />\n        </motion.div>\n\n        <div className=\"space-y-4\">\n          <AnimatePresence mode=\"popLayout\">\n            {filteredFaqs.length === 0 ? (\n              <motion.div\n                animate={\n                  shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1 }\n                }\n                className=\"rounded-xl border border-border bg-background/50 py-12 text-center\"\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0, transition: { duration: 0 } }\n                    : { opacity: 0, scale: 0.95 }\n                }\n                initial={\n                  shouldReduceMotion\n                    ? { opacity: 1 }\n                    : { opacity: 0, scale: 0.95 }\n                }\n                key=\"no-results\"\n                transition={springTransition}\n              >\n                <p className=\"text-foreground/60\">{noResultsText}</p>\n              </motion.div>\n            ) : (\n              filteredFaqs.map((faq, index) => {\n                const originalIndex = faqs.indexOf(faq);\n                const isOpen = openIndex === originalIndex;\n\n                return (\n                  <motion.div\n                    animate={\n                      shouldReduceMotion\n                        ? { opacity: 1 }\n                        : { opacity: 1, scale: 1, y: 0 }\n                    }\n                    className=\"group overflow-hidden rounded-xl border border-border bg-background transition-colors hover:border-brand\"\n                    exit={\n                      shouldReduceMotion\n                        ? { opacity: 0, transition: { duration: 0 } }\n                        : { opacity: 0, scale: 0.95, y: -10 }\n                    }\n                    initial={\n                      shouldReduceMotion\n                        ? { opacity: 1 }\n                        : { opacity: 0, scale: 0.95, y: 20 }\n                    }\n                    key={faq.question}\n                    layout={!shouldReduceMotion}\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(originalIndex)}\n                      type=\"button\"\n                    >\n                      <h3 className=\"pr-4 font-medium text-foreground\">\n                        {faq.question}\n                      </h3>\n                      <motion.div\n                        animate={{\n                          rotate: isOpen ? 180 : 0,\n                        }}\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            )}\n          </AnimatePresence>\n        </div>\n      </div>\n    </section>\n  );\n}\n\nexport default FaqSearchable;\n","path":"index.tsx","target":"components/smoothui/faq-3/index.tsx","type":"registry:block"}],"name":"faq-3","registryDependencies":["https://smoothui.dev/r/tokens.json"],"title":"Faq 3","type":"registry:block"}