import * as React from "react"; import { Check, CheckCheck } from "lucide-react"; import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; import { cn } from "@/lib/cn"; export interface ChatBubbleProps { /** Message text (string or ReactNode for rich content). */ children: React.ReactNode; /** incoming: bubble on the left, outgoing: bubble on the right. */ variant: "incoming" | "outgoing"; /** Avatar (for incoming). */ avatarUrl?: string; /** Fallback text avatar (usually initials). */ avatarFallback?: string; /** Message time. */ timestamp?: React.ReactNode; /** Read status (for outgoing). */ read?: boolean; /** Hide avatar and timestamp (for consecutive messages from * the same sender). */ grouped?: boolean; /** Additional class. */ className?: string; } /** * ChatBubble - chat message bubble in the style of WhatsApp / Telegram. * * - Variant incoming (left, muted) and outgoing (right, brand). * - Avatar (incoming) + timestamp + read receipt (outgoing). * - grouped=true hides avatar and timestamp for consecutive * messages from the same sender. * - Solid tone (NOT gradient). * * Example: * * Hello, how are you? * * Good! */ export function ChatBubble({ children, variant, avatarUrl, avatarFallback, timestamp, read, grouped = false, className, }: ChatBubbleProps) { const isOutgoing = variant === "outgoing"; const showAvatar = !isOutgoing && !grouped; const showTimestamp = !grouped; return (
{showAvatar ? ( {avatarUrl ? ( ) : null} {(avatarFallback ?? "?").slice(0, 2).toUpperCase()} ) : (
)}
{children}
{showTimestamp ? (
{isOutgoing ? ( read ? ( ) : ( ) ) : null}
) : null}
); }