{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "CardNav-TS-TW",
	"title": "CardNav",
	"description": "Expandable navigation bar with card panels revealing nested links.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "CardNav/CardNav.tsx",
			"content": "import React, { useLayoutEffect, useRef, useState } from 'react';\nimport { gsap } from 'gsap';\n// use your own icon import if react-icons is not available\nimport { GoArrowUpRight } from 'react-icons/go';\n\ntype CardNavLink = {\n  label: string;\n  href: string;\n  ariaLabel: string;\n};\n\nexport type CardNavItem = {\n  label: string;\n  bgColor: string;\n  textColor: string;\n  links: CardNavLink[];\n};\n\nexport interface CardNavProps {\n  logo: string;\n  logoAlt?: string;\n  items: CardNavItem[];\n  className?: string;\n  ease?: string;\n  baseColor?: string;\n  menuColor?: string;\n  buttonBgColor?: string;\n  buttonTextColor?: string;\n}\n\nconst CardNav: React.FC<CardNavProps> = ({\n  logo,\n  logoAlt = 'Logo',\n  items,\n  className = '',\n  ease = 'power3.out',\n  baseColor = '#fff',\n  menuColor,\n  buttonBgColor,\n  buttonTextColor\n}) => {\n  const [isHamburgerOpen, setIsHamburgerOpen] = useState(false);\n  const [isExpanded, setIsExpanded] = useState(false);\n  const navRef = useRef<HTMLDivElement | null>(null);\n  const cardsRef = useRef<HTMLDivElement[]>([]);\n  const tlRef = useRef<gsap.core.Timeline | null>(null);\n\n  const calculateHeight = () => {\n    const navEl = navRef.current;\n    if (!navEl) return 260;\n\n    const isMobile = window.matchMedia('(max-width: 768px)').matches;\n    if (isMobile) {\n      const contentEl = navEl.querySelector('.card-nav-content') as HTMLElement;\n      if (contentEl) {\n        const wasVisible = contentEl.style.visibility;\n        const wasPointerEvents = contentEl.style.pointerEvents;\n        const wasPosition = contentEl.style.position;\n        const wasHeight = contentEl.style.height;\n\n        contentEl.style.visibility = 'visible';\n        contentEl.style.pointerEvents = 'auto';\n        contentEl.style.position = 'static';\n        contentEl.style.height = 'auto';\n\n        contentEl.offsetHeight;\n\n        const topBar = 60;\n        const padding = 16;\n        const contentHeight = contentEl.scrollHeight;\n\n        contentEl.style.visibility = wasVisible;\n        contentEl.style.pointerEvents = wasPointerEvents;\n        contentEl.style.position = wasPosition;\n        contentEl.style.height = wasHeight;\n\n        return topBar + contentHeight + padding;\n      }\n    }\n    return 260;\n  };\n\n  const createTimeline = () => {\n    const navEl = navRef.current;\n    if (!navEl) return null;\n\n    gsap.set(navEl, { height: 60, overflow: 'hidden' });\n    gsap.set(cardsRef.current, { y: 50, opacity: 0 });\n\n    const tl = gsap.timeline({ paused: true });\n\n    tl.to(navEl, {\n      height: calculateHeight,\n      duration: 0.4,\n      ease\n    });\n\n    tl.to(cardsRef.current, { y: 0, opacity: 1, duration: 0.4, ease, stagger: 0.08 }, '-=0.1');\n\n    return tl;\n  };\n\n  useLayoutEffect(() => {\n    const tl = createTimeline();\n    tlRef.current = tl;\n\n    return () => {\n      tl?.kill();\n      tlRef.current = null;\n    };\n  }, [ease, items]);\n\n  useLayoutEffect(() => {\n    const handleResize = () => {\n      if (!tlRef.current) return;\n\n      if (isExpanded) {\n        const newHeight = calculateHeight();\n        gsap.set(navRef.current, { height: newHeight });\n\n        tlRef.current.kill();\n        const newTl = createTimeline();\n        if (newTl) {\n          newTl.progress(1);\n          tlRef.current = newTl;\n        }\n      } else {\n        tlRef.current.kill();\n        const newTl = createTimeline();\n        if (newTl) {\n          tlRef.current = newTl;\n        }\n      }\n    };\n\n    window.addEventListener('resize', handleResize);\n    return () => window.removeEventListener('resize', handleResize);\n  }, [isExpanded]);\n\n  const toggleMenu = () => {\n    const tl = tlRef.current;\n    if (!tl) return;\n    if (!isExpanded) {\n      setIsHamburgerOpen(true);\n      setIsExpanded(true);\n      tl.play(0);\n    } else {\n      setIsHamburgerOpen(false);\n      tl.eventCallback('onReverseComplete', () => setIsExpanded(false));\n      tl.reverse();\n    }\n  };\n\n  const setCardRef = (i: number) => (el: HTMLDivElement | null) => {\n    if (el) cardsRef.current[i] = el;\n  };\n\n  return (\n    <div\n      className={`card-nav-container absolute left-1/2 -translate-x-1/2 w-[90%] max-w-[800px] z-[99] top-[1.2em] md:top-[2em] ${className}`}\n    >\n      <nav\n        ref={navRef}\n        className={`card-nav ${isExpanded ? 'open' : ''} block h-[60px] p-0 rounded-xl shadow-md relative overflow-hidden will-change-[height]`}\n        style={{ backgroundColor: baseColor }}\n      >\n        <div className=\"card-nav-top absolute inset-x-0 top-0 h-[60px] flex items-center justify-between p-2 pl-[1.1rem] z-[2]\">\n          <div\n            className={`hamburger-menu ${isHamburgerOpen ? 'open' : ''} group h-full flex flex-col items-center justify-center cursor-pointer gap-[6px] order-2 md:order-none`}\n            onClick={toggleMenu}\n            onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {\n              if (e.key === 'Enter' || e.key === ' ') {\n                e.preventDefault();\n                toggleMenu();\n              }\n            }}\n            role=\"button\"\n            aria-label={isExpanded ? 'Close menu' : 'Open menu'}\n            aria-expanded={isExpanded}\n            tabIndex={0}\n            style={{ color: menuColor || '#000' }}\n          >\n            <div\n              className={`hamburger-line w-[30px] h-[2px] bg-current transition-[transform,opacity,margin] duration-300 ease-linear [transform-origin:50%_50%] ${\n                isHamburgerOpen ? 'translate-y-[4px] rotate-45' : ''\n              } group-hover:opacity-75`}\n            />\n            <div\n              className={`hamburger-line w-[30px] h-[2px] bg-current transition-[transform,opacity,margin] duration-300 ease-linear [transform-origin:50%_50%] ${\n                isHamburgerOpen ? '-translate-y-[4px] -rotate-45' : ''\n              } group-hover:opacity-75`}\n            />\n          </div>\n\n          <div className=\"logo-container flex items-center md:absolute md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 order-1 md:order-none\">\n            <img src={logo} alt={logoAlt} className=\"logo h-[28px]\" />\n          </div>\n\n          <button\n            type=\"button\"\n            className=\"card-nav-cta-button hidden md:inline-flex border-0 rounded-[calc(0.75rem-0.2rem)] px-4 items-center h-full font-medium cursor-pointer transition-colors duration-300\"\n            style={{ backgroundColor: buttonBgColor, color: buttonTextColor }}\n          >\n            Get Started\n          </button>\n        </div>\n\n        <div\n          className={`card-nav-content absolute left-0 right-0 top-[60px] bottom-0 p-2 flex flex-col items-stretch gap-2 justify-start z-[1] ${\n            isExpanded ? 'visible pointer-events-auto' : 'invisible pointer-events-none'\n          } md:flex-row md:items-end md:gap-[12px]`}\n          aria-hidden={!isExpanded}\n        >\n          {(items || []).slice(0, 3).map((item, idx) => (\n            <div\n              key={`${item.label}-${idx}`}\n              className=\"nav-card select-none relative flex flex-col gap-2 p-[12px_16px] rounded-[calc(0.75rem-0.2rem)] min-w-0 flex-[1_1_auto] h-auto min-h-[60px] md:h-full md:min-h-0 md:flex-[1_1_0%]\"\n              ref={setCardRef(idx)}\n              style={{ backgroundColor: item.bgColor, color: item.textColor }}\n            >\n              <div className=\"nav-card-label font-normal tracking-[-0.5px] text-[18px] md:text-[22px]\">\n                {item.label}\n              </div>\n              <div className=\"nav-card-links mt-auto flex flex-col gap-[2px]\">\n                {item.links?.map((lnk, i) => (\n                  <a\n                    key={`${lnk.label}-${i}`}\n                    className=\"nav-card-link inline-flex items-center gap-[6px] no-underline cursor-pointer transition-opacity duration-300 hover:opacity-75 text-[15px] md:text-[16px]\"\n                    href={lnk.href}\n                    aria-label={lnk.ariaLabel}\n                  >\n                    <GoArrowUpRight className=\"nav-card-link-icon shrink-0\" aria-hidden=\"true\" />\n                    {lnk.label}\n                  </a>\n                ))}\n              </div>\n            </div>\n          ))}\n        </div>\n      </nav>\n    </div>\n  );\n};\n\nexport default CardNav;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"gsap@^3.13.0",
		"react-icons@^5.5.0"
	]
}