{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "native-profile-notch-shadcnui",
  "type": "registry:component",
  "title": "Native Profile Notch",
  "description": "A dynamic expanding notch component for displaying user profiles with smooth spring animations.",
  "dependencies": [
    "framer-motion",
    "react"
  ],
  "files": [
    {
      "path": "@uitripled/react-shadcn/src/components/native/native-profile-notch-shadcnui.tsx",
      "content": "\"use client\";\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, MotionConfig } from \"framer-motion\";\nimport { ChevronRight, X } from \"lucide-react\";\nimport { useEffect, useId, useRef, useState } from \"react\";\n\nexport interface NativeProfileNotchProps {\n  /**\n   * Url of the user image\n   */\n  imageSrc: string;\n  /**\n   * Name of the user\n   */\n  name: string;\n  /**\n   * Handle or role of the user\n   */\n  username: string;\n  /**\n   * Custom content to show in expanded state\n   */\n  children?: React.ReactNode;\n  /**\n   * Size of the notch\n   * @default \"md\"\n   */\n  size?: \"sm\" | \"md\" | \"lg\";\n  /**\n   * Class name for the container\n   */\n  className?: string;\n  /**\n   * Variant of the notch.\n   * \"default\": expands and pushes content.\n   * \"overlay\": expands over content (absolute positioning).\n   * @default \"default\"\n   */\n  variant?: \"default\" | \"overlay\";\n}\n\nexport function NativeProfileNotch({\n  imageSrc,\n  name,\n  username,\n  children,\n  size = \"md\",\n  className,\n  variant = \"default\",\n}: NativeProfileNotchProps) {\n  const [isOpen, setIsOpen] = useState(false);\n  const uid = useId();\n  const notchRef = useRef<HTMLDivElement>(null);\n  const closeButtonRef = useRef<HTMLButtonElement>(null);\n  const wasOpen = useRef(false);\n\n  // Move focus into the panel on open, back to the notch on close.\n  useEffect(() => {\n    if (isOpen) {\n      wasOpen.current = true;\n      closeButtonRef.current?.focus();\n    } else if (wasOpen.current) {\n      notchRef.current?.focus();\n    }\n  }, [isOpen]);\n\n  return (\n    <div\n      className={cn(\n        variant === \"overlay\"\n          ? \"relative flex items-center justify-center w-[160px] h-[60px]\"\n          : \"flex items-start justify-center\",\n        className\n      )}\n    >\n      <MotionConfig reducedMotion=\"user\">\n        <motion.div\n          ref={notchRef}\n          layout\n          role={!isOpen ? \"button\" : undefined}\n          tabIndex={!isOpen ? 0 : -1}\n          aria-expanded={isOpen}\n          aria-label={!isOpen ? `Open ${name}'s profile` : undefined}\n          className={cn(\n            \"bg-background text-foreground overflow-hidden z-50 border border-accent/60\",\n            \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n            isOpen ? \"rounded-3xl\" : \"rounded-full cursor-pointer\",\n            variant === \"overlay\" ? \"absolute top-0 left-0\" : \"relative\"\n          )}\n          initial={false}\n          animate={{\n            width: isOpen ? 320 : 160,\n            height: isOpen ? 380 : 60,\n            borderRadius: isOpen ? 32 : 32,\n          }}\n          transition={{\n            width: {\n              delay: isOpen ? 0 : 0.25,\n              type: \"spring\",\n              stiffness: 260,\n              damping: 30,\n            },\n            height: {\n              delay: isOpen ? 0.15 : 0,\n              type: \"spring\",\n              stiffness: 260,\n              damping: 30,\n            },\n            borderRadius: {\n              delay: isOpen ? 0 : 0.25,\n              type: \"spring\",\n              stiffness: 260,\n              damping: 30,\n            },\n            layout: { duration: 0.35, ease: \"easeInOut\" },\n          }}\n          onClick={() => !isOpen && setIsOpen(true)}\n          onKeyDown={(e) => {\n            if (!isOpen && (e.key === \"Enter\" || e.key === \" \")) {\n              e.preventDefault();\n              setIsOpen(true);\n            }\n            if (isOpen && e.key === \"Escape\") {\n              setIsOpen(false);\n            }\n          }}\n        >\n          <AnimatePresence mode=\"wait\">\n            {!isOpen ? (\n              <motion.div\n                key=\"collapsed\"\n                className=\"absolute inset-0 flex items-center justify-center w-full h-full\"\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n                transition={{ duration: 0.2 }}\n              >\n                <div className=\"flex items-center gap-3 px-4 w-full\">\n                  <Avatar className=\"w-8 h-8 flex-shrink-0\">\n                    <AvatarImage\n                      src={imageSrc}\n                      alt=\"\"\n                      className=\"object-cover\"\n                    />\n                    <AvatarFallback className=\"bg-muted text-[10px] text-foreground\">\n                      {name.slice(0, 2).toUpperCase()}\n                    </AvatarFallback>\n                  </Avatar>\n                  <div className=\"flex flex-col overflow-hidden\">\n                    <span className=\"text-sm font-medium text-foreground truncate\">\n                      {name}\n                    </span>\n                    <span className=\"text-[10px] text-muted-foreground truncate\">\n                      @{username}\n                    </span>\n                  </div>\n                  <ChevronRight\n                    aria-hidden=\"true\"\n                    className=\"w-4 h-4 text-muted-foreground ml-auto\"\n                  />\n                </div>\n              </motion.div>\n            ) : (\n              <motion.div\n                key=\"expanded\"\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n                transition={{ duration: 0.2 }}\n                className=\"flex flex-col h-full relative p-6 cursor-default\"\n              >\n                {/* Close Button */}\n                <button\n                  ref={closeButtonRef}\n                  type=\"button\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setIsOpen(false);\n                  }}\n                  className=\"absolute top-4 right-4 p-1 rounded-full bg-muted/50 hover:bg-muted transition-colors z-10 outline-none focus-visible:ring-2 focus-visible:ring-ring after:absolute after:-inset-2\"\n                  aria-label=\"Close profile\"\n                >\n                  <X aria-hidden=\"true\" className=\"w-4 h-4 text-muted-foreground\" />\n                </button>\n\n                {/* Scrollable Content */}\n                <div className=\"flex flex-col items-center w-full h-full overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:'none'] [scrollbar-width:'none']\">\n                  {/* Profile Header */}\n                  <div className=\"flex flex-col items-center mt-4 flex-shrink-0\">\n                    <motion.div\n                      layoutId={`${uid}-avatar`}\n                      className=\"w-24 h-24 rounded-full overflow-hidden border-4 border-muted/20 shadow-lg mb-4\"\n                    >\n                      <img\n                        src={imageSrc}\n                        alt=\"\"\n                        className=\"w-full h-full object-cover\"\n                      />\n                    </motion.div>\n\n                    <motion.p\n                      layoutId={`${uid}-name`}\n                      className=\"text-xl font-bold text-foreground text-center\"\n                    >\n                      {name}\n                    </motion.p>\n\n                    <motion.p\n                      layoutId={`${uid}-username`}\n                      className=\"text-muted-foreground text-sm font-medium text-center\"\n                    >\n                      @{username}\n                    </motion.p>\n                  </div>\n\n                  {/* Custom Content */}\n                  <motion.div\n                    initial={{ opacity: 0, y: 10 }}\n                    animate={{ opacity: 1, y: 0 }}\n                    transition={{ delay: 0.2 }}\n                    className=\"mt-6 w-full flex-1\"\n                  >\n                    {children}\n                  </motion.div>\n\n                  {/* Bottom Action */}\n                  <motion.div\n                    initial={{ opacity: 0, y: 10 }}\n                    animate={{ opacity: 1, y: 0 }}\n                    transition={{ delay: 0.3 }}\n                    className=\"mt-4 w-full pt-4 sticky bottom-0 bg-gradient-to-t from-background via-background to-transparent p-1\"\n                  >\n                    <button\n                      type=\"button\"\n                      className=\"w-full py-3 rounded-xl bg-primary text-primary-foreground font-semibold text-sm hover:bg-primary/90 transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n                      onClick={(e) => {\n                        e.stopPropagation();\n                      }}\n                    >\n                      View Full Profile\n                    </button>\n                  </motion.div>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </motion.div>\n      </MotionConfig>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/native-profile-notch-shadcnui.tsx"
    }
  ]
}