Conversation
trovecn/conversationFreeComponent
A quiet conversation surface with authored hierarchy and contextual message actions.
Install it
npx shadcn@latest add https://trovecn.dev/r/conversation.jsonSource
1"use client";23import { useState, type ReactNode } from "react";4import { CheckIcon, CopyIcon, PencilIcon, RotateCcwIcon } from "lucide-react";5import { AnimatePresence, motion, useReducedMotion } from "motion/react";67import { Button } from "@/components/ui/button";8import { spring } from "@/lib/springs";9import { cn } from "@/lib/utils";1011export type ConversationMessageRole = "user" | "assistant";1213export interface ConversationMessage {14 id: string;15 role: ConversationMessageRole;16 /** Consumer-rendered text, markdown, or other inline response content. */17 content: ReactNode;18 /** Rendered below a user message; assistant messages intentionally omit it. */19 timestamp?: ReactNode;20}2122export interface ConversationProps {23 messages: readonly ConversationMessage[];24 onCopy?: (message: ConversationMessage) => void;25 onEdit?: (message: ConversationMessage) => void;26 onRegenerate?: (message: ConversationMessage) => void;27 emptyState?: ReactNode;28 className?: string;29}3031/**32 * A quiet conversation reading surface. It establishes authored hierarchy and33 * contextual actions, leaving transport, markdown, and product state outside.34 */35function Conversation({36 messages,37 onCopy,38 onEdit,39 onRegenerate,40 emptyState,41 className,42}: ConversationProps) {43 const reduceMotion = useReducedMotion();44 const [copiedMessageId, setCopiedMessageId] = useState<string>();4546 async function handleCopy(message: ConversationMessage) {47 let copied = false;4849 if (typeof message.content === "string" && navigator.clipboard) {50 try {51 await navigator.clipboard.writeText(message.content);52 copied = true;53 } catch {54 // A consumer callback can provide a fallback for restricted clipboard contexts.55 }56 }5758 onCopy?.(message);59 if (!copied && !onCopy) return;6061 setCopiedMessageId(message.id);62 window.setTimeout(() => setCopiedMessageId(undefined), 1_600);63 }6465 if (messages.length === 0) {66 return emptyState ? (67 <div data-slot="conversation" className={className}>68 {emptyState}69 </div>70 ) : null;71 }7273 return (74 <section data-slot="conversation" aria-label="Conversation" className={cn("w-full", className)}>75 <div className="space-y-2">76 <AnimatePresence initial={false}>77 {messages.map((message) => (78 <motion.article79 key={message.id}80 data-slot="conversation-message"81 data-role={message.role}82// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from trovecn
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | trovecn | Components | Free | 3 deps | |
| Agent Activityagent-activity | trovecn | Components | Free | 2 deps | |
| Approval Requestapproval-request | trovecn | Components | Free | 2 deps | |
| Buttonbutton | trovecn | Components | Free | 2 deps | |
| Checkboxcheckbox | trovecn | Components | Free | 2 deps | |
| Checkbox Groupcheckbox-group | trovecn | Components | Free | 2 deps | |
| Comboboxcombobox | trovecn | Components | Free | 3 deps | |
| Comparison Slidercomparison-slider | trovecn | Components | Free | 1 dep |
