{
  "name": "subitem-navbar-subitem-navbar",
  "type": "registry:block",
  "tier": "free",
  "dependencies": [
    "motion",
    "@hugeicons/react",
    "@hugeicons/core-free-icons",
    "react-use-measure"
  ],
  "registryDependencies": [
    "https://www.craftui.space/r/craftui-base.json"
  ],
  "files": [
    {
      "path": "components/craftui/blocks/subitem-navbar/subitem-navbar.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\nimport { motion, AnimatePresence, useReducedMotion } from \"motion/react\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport {\n  Mail01Icon,\n  LockPasswordIcon,\n  EyeIcon,\n  ViewOffIcon,\n} from \"@hugeicons/core-free-icons\";\nimport useMeasure from \"react-use-measure\";\n\ntype HugeIcon = React.ComponentProps<typeof HugeiconsIcon>[\"icon\"];\n\nexport type SubItem = {\n  label: string;\n  icon: HugeIcon;\n};\n\nexport type NavItemWithSubs = {\n  label: string;\n  icon: HugeIcon;\n  subs: SubItem[];\n};\n\nexport type NavItemWithPanel = {\n  label: string;\n  icon: HugeIcon;\n  panel: React.ReactNode;\n};\n\nexport type NavItem = NavItemWithSubs | NavItemWithPanel;\n\nfunction hasPanel(item: NavItem): item is NavItemWithPanel {\n  return \"panel\" in item;\n}\n\nconst EASE_OUT = [0.22, 1, 0.36, 1] as const;\n\nexport function LoginPanel() {\n  const prefersReducedMotion = useReducedMotion();\n  const [email, setEmail] = React.useState(\"\");\n  const [password, setPassword] = React.useState(\"\");\n  const [showPassword, setShowPassword] = React.useState(false);\n\n  return (\n    <div className=\"flex flex-col gap-2.5 px-3 pt-3 pb-3\">\n      <div\n        className=\"flex min-h-[44px] items-center gap-2.5 rounded-lg px-3.5 py-2.5 transition-[box-shadow] duration-150 focus-within:shadow-[0_0_0_1px_rgba(255,255,255,0.18)]\"\n        style={{ background: \"rgba(255,255,255,0.06)\" }}\n      >\n        <HugeiconsIcon icon={Mail01Icon} size={14} color=\"rgba(255,255,255,0.7)\" strokeWidth={1.5} />\n        <input\n          type=\"email\"\n          placeholder=\"Email\"\n          value={email}\n          onChange={(e) => setEmail(e.target.value)}\n          className=\"flex-1 bg-transparent text-[12px] text-white antialiased outline-none placeholder:text-white/30\"\n        />\n      </div>\n\n      <div\n        className=\"flex min-h-[44px] items-center gap-2.5 rounded-lg px-3.5 py-2.5 transition-[box-shadow] duration-150 focus-within:shadow-[0_0_0_1px_rgba(255,255,255,0.18)]\"\n        style={{ background: \"rgba(255,255,255,0.06)\" }}\n      >\n        <HugeiconsIcon icon={LockPasswordIcon} size={14} color=\"rgba(255,255,255,0.7)\" strokeWidth={1.5} />\n        <input\n          type={showPassword ? \"text\" : \"password\"}\n          placeholder=\"Password\"\n          value={password}\n          onChange={(e) => setPassword(e.target.value)}\n          className=\"flex-1 bg-transparent text-[12px] text-white antialiased outline-none placeholder:text-white/30\"\n        />\n        <motion.button\n          onClick={() => setShowPassword((p) => !p)}\n          className=\"relative flex h-8 w-8 cursor-pointer items-center justify-center select-none\"\n          whileTap={{ scale: 0.96 }}\n        >\n          <AnimatePresence initial={false} mode=\"popLayout\">\n            <motion.span\n              key={showPassword ? \"hide\" : \"show\"}\n              initial={{ opacity: 0, scale: 0.25, filter: \"blur(2px)\" }}\n              animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n              exit={{ opacity: 0, scale: 0.25, filter: \"blur(2px)\" }}\n              transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.2, ease: \"easeInOut\" }}\n              className=\"flex items-center justify-center\"\n            >\n              <HugeiconsIcon\n                icon={showPassword ? ViewOffIcon : EyeIcon}\n                size={14}\n                color=\"rgba(255,255,255,0.7)\"\n                strokeWidth={1.5}\n              />\n            </motion.span>\n          </AnimatePresence>\n        </motion.button>\n      </div>\n\n      <motion.button\n        whileTap={{ scale: 0.96 }}\n        className=\"w-full cursor-pointer rounded-lg py-3 text-[12px] font-semibold text-black antialiased transition-[opacity] duration-150 select-none hover:opacity-90\"\n        style={{ background: \"rgba(255,255,255,0.92)\" }}\n      >\n        Sign in\n      </motion.button>\n\n      <motion.button\n        whileTap={{ scale: 0.96 }}\n        className=\"w-full cursor-pointer py-1 text-center text-[11px] text-white/30 antialiased transition-[color] duration-150 select-none hover:text-white/50\"\n      >\n        Forgot password?\n      </motion.button>\n    </div>\n  );\n}\n\nexport default function BottomNavbar({ items }: { items: NavItem[] }) {\n  const prefersReducedMotion = useReducedMotion();\n  const [activeTab, setActiveTab] = React.useState<string | null>(null);\n  const [activeSub, setActiveSub] = React.useState<string>(\"\");\n  const [subRef, { height: subHeight }] = useMeasure();\n\n  const handleTabClick = (label: string) => {\n    if (activeTab === label) {\n      setActiveTab(null);\n    } else {\n      setActiveTab(label);\n      const item = items.find((i) => i.label === label);\n      if (item && !hasPanel(item) && item.subs.length > 0) {\n        setActiveSub(item.subs[0].label);\n      }\n    }\n  };\n\n  const currentItem = items.find((i) => i.label === activeTab);\n\n  return (\n    <div className=\"pointer-events-none absolute inset-0\">\n      <AnimatePresence initial={false}>\n        {activeTab && (\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            transition={{ duration: 0.25, ease: \"easeOut\" }}\n            onClick={() => setActiveTab(null)}\n            className=\"pointer-events-auto absolute inset-0 z-10\"\n            style={{\n              backdropFilter: \"blur(20px)\",\n              WebkitBackdropFilter: \"blur(20px)\",\n              background: \"rgba(200,200,210,0.3)\",\n            }}\n          />\n        )}\n      </AnimatePresence>\n\n      <motion.div\n        layout\n        transition={{ type: \"spring\", duration: 0.45, bounce: 0.15 }}\n        style={{\n          borderRadius: 17,\n          boxShadow: \"0 0 0 1px rgba(255,255,255,0.06), 0 24px 48px rgba(0,0,0,0.6)\",\n        }}\n        className=\"pointer-events-auto absolute right-4 bottom-5 left-4 z-20 overflow-hidden bg-[#0e0e0e]\"\n      >\n        <motion.div\n          animate={{ height: activeTab ? subHeight : 0 }}\n          transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.3, ease: EASE_OUT }}\n          style={{ overflow: \"hidden\" }}\n        >\n          <div ref={subRef}>\n            <AnimatePresence initial={false} mode=\"popLayout\">\n              {currentItem && !hasPanel(currentItem) && (\n                <motion.div\n                  key={currentItem.label}\n                  initial={{ opacity: 0, filter: \"blur(4px)\", y: 8 }}\n                  animate={{ opacity: 1, filter: \"blur(0px)\", y: 0 }}\n                  exit={{\n                    opacity: 0,\n                    filter: \"blur(2px)\",\n                    transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.12, ease: EASE_OUT },\n                  }}\n                  transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.2, ease: EASE_OUT }}\n                  className=\"px-3 pt-3 pb-3\"\n                >\n                  <div className=\"flex flex-wrap gap-2\">\n                    {currentItem.subs.map((sub) => {\n                      const isSubActive = activeSub === sub.label;\n                      return (\n                        <motion.button\n                          key={sub.label}\n                          whileTap={{ scale: 0.96 }}\n                          onClick={() => setActiveSub(sub.label)}\n                          className=\"flex min-h-[34px] cursor-pointer items-center gap-1.5 rounded-full px-3 py-2 antialiased transition-[background-color,color] duration-150 select-none\"\n                          style={{\n                            background: isSubActive ? \"rgba(255,255,255,0.14)\" : \"rgba(255,255,255,0.05)\",\n                            color: isSubActive ? \"rgba(255,255,255,1)\" : \"rgba(255,255,255,0.7)\",\n                          }}\n                        >\n                          <HugeiconsIcon icon={sub.icon} size={11} color=\"currentColor\" strokeWidth={isSubActive ? 2 : 1.5} />\n                          <span className=\"text-[11px]\" style={{ fontWeight: isSubActive ? 600 : 400 }}>\n                            {sub.label}\n                          </span>\n                        </motion.button>\n                      );\n                    })}\n                  </div>\n                </motion.div>\n              )}\n\n              {currentItem && hasPanel(currentItem) && (\n                <motion.div\n                  key={currentItem.label}\n                  initial={{ opacity: 0, filter: \"blur(2px)\", y: 8 }}\n                  animate={{ opacity: 1, filter: \"blur(0px)\", y: 0 }}\n                  exit={{\n                    opacity: 0,\n                    filter: \"blur(2px)\",\n                    transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.1, ease: EASE_OUT },\n                  }}\n                  transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.4, ease: EASE_OUT }}\n                >\n                  {currentItem.panel}\n                </motion.div>\n              )}\n            </AnimatePresence>\n            <div className=\"mx-4 h-px bg-white/[0.07]\" />\n          </div>\n        </motion.div>\n\n        <div className=\"flex h-14 items-center\">\n          {items.map((item) => {\n            const isActive = activeTab === item.label;\n            return (\n              <motion.button\n                key={item.label}\n                onClick={() => handleTabClick(item.label)}\n                whileTap={{ scale: 0.96 }}\n                className=\"relative flex flex-1 cursor-pointer flex-col items-center justify-center gap-1 py-2 select-none\"\n              >\n                <span\n                  className=\"relative transition-[color] duration-150\"\n                  style={{ color: isActive ? \"white\" : \"rgba(255,255,255,0.7)\" }}\n                >\n                  <HugeiconsIcon icon={item.icon} size={17} color=\"currentColor\" strokeWidth={isActive ? 2 : 1.5} />\n                </span>\n                <span\n                  className=\"relative text-[10px] antialiased transition-[color,font-weight] duration-150\"\n                  style={{ fontWeight: isActive ? 600 : 400, color: isActive ? \"white\" : \"rgba(255,255,255,0.7)\" }}\n                >\n                  {item.label}\n                </span>\n              </motion.button>\n            );\n          })}\n        </div>\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "~/components/craftui/blocks/subitem-navbar/subitem-navbar.tsx"
    }
  ],
  "meta": {
    "displayName": "SubItem Navbar - SubItem Navbar",
    "description": "Tabs expand a panel above the bar via a spring-driven height animation. Panels are either a chip filter list (subs) or any React node (panel). LoginPanel is a named export for use as a panel slot.",
    "category": "navbar",
    "tags": [
      "navbar",
      "navigation",
      "bottom",
      "pill",
      "submenu",
      "filter",
      "animation",
      "morphing"
    ],
    "animationType": "click"
  }
}