{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "native-hover-card-shadcnui", "type": "registry:component", "title": "Native Hover Card", "description": "Avatar card that expands on hover to reveal profile information with smooth animations.", "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/native/native-hover-card-shadcnui.tsx", "content": "\"use client\";\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, MotionConfig } from \"framer-motion\";\nimport { type ReactNode, useState } from \"react\";\n\nexport interface NativeHoverCardProps {\n /**\n * Image source URL\n */\n imageSrc: string;\n /**\n * Alt text for the image\n */\n imageAlt?: string;\n /**\n * Display name\n */\n name: string;\n /**\n * Username or handle\n */\n username?: string;\n /**\n * Description or bio text\n */\n description?: string;\n /**\n * Button text\n * Default: \"View Profile\"\n */\n buttonText?: string;\n /**\n * Button click handler\n */\n onButtonClick?: () => void;\n /**\n * Custom button component\n */\n buttonContent?: ReactNode;\n /**\n * Size of the image when collapsed\n * Default: \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n /**\n * Additional class names for the container\n */\n className?: string;\n /**\n * Card variant style\n */\n variant?: \"default\" | \"glass\" | \"bordered\";\n}\n\nconst imageSizeVariants = {\n sm: \"w-16 h-16\",\n md: \"w-24 h-24\",\n lg: \"w-32 h-32\",\n xl: \"w-40 h-40\",\n};\n\nconst cardWidthVariants = {\n sm: \"w-56\",\n md: \"w-72\",\n lg: \"w-80\",\n xl: \"w-96\",\n};\n\nconst getInitials = (name: string) => {\n return name\n .split(\" \")\n .filter(Boolean)\n .map((n) => n[0])\n .join(\"\")\n .toUpperCase()\n .slice(0, 2);\n};\n\nexport function NativeHoverCard({\n imageSrc,\n imageAlt,\n name,\n username,\n description,\n buttonText = \"View Profile\",\n onButtonClick,\n buttonContent,\n size = \"md\",\n className,\n variant = \"default\",\n}: NativeHoverCardProps) {\n const [isOpen, setIsOpen] = useState(false);\n\n const getVariantStyles = () => {\n switch (variant) {\n case \"glass\":\n return \"bg-background/80 backdrop-blur-md border border-border/50\";\n case \"bordered\":\n return \"bg-card border-2 border-primary/20\";\n default:\n return \"bg-card border border-border\";\n }\n };\n\n // Avatar component - renders a fresh instance to ensure updates/animations work\n const avatarElement = (\n \n \n {getInitials(name)}\n \n );\n\n return (\n \n setIsOpen(true)}\n onMouseLeave={() => setIsOpen(false)}\n onFocus={() => setIsOpen(true)}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {\n setIsOpen(false);\n }\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setIsOpen(false);\n }}\n >\n {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n setIsOpen((open) => !open);\n }\n }}\n className={cn(\n \"relative rounded-full overflow-hidden cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n imageSizeVariants[size]\n )}\n layout\n animate={{\n padding: isOpen ? \"8px\" : \"0px\",\n }}\n transition={{\n type: \"spring\",\n stiffness: 300,\n damping: 30,\n }}\n >\n {avatarElement}\n \n\n {/* Expanded Card Content */}\n \n {isOpen && (\n \n {/* Background with gradient overlay on image */}\n
\n \n {avatarElement}\n
\n\n {/* Content Section */}\n \n {/* Name */}\n
\n \n {name}\n \n\n {/* Username */}\n {username && (\n \n @{username}\n \n )}\n
\n\n {/* Description */}\n {description && (\n \n {description}\n \n )}\n\n {/* Button */}\n \n {buttonContent ? (\n buttonContent\n ) : (\n \n {buttonText}\n \n )}\n \n \n \n \n )}\n
\n \n
\n );\n}\n", "type": "registry:component", "target": "components/uitripled/native-hover-card-shadcnui.tsx" } ] }