Message Actions
spectrumui/message-actionsFreeBlock
Per-message controls — copy, regenerate, and thumb feedback.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/message-actions.jsonSource
1'use client';23import { useEffect, useRef, useState } from 'react';4import { Check, Copy, GitBranch, RefreshCw, ThumbsDown, ThumbsUp } from 'lucide-react';5import { cn } from '@/lib/utils';6import type { MessageFeedback } from './types';78export type MessageActionsVariant = 'Ghost' | 'Pill';910export interface MessageActionsProps {11 content?: string;12 feedback?: MessageFeedback | null;13 onCopy?: (content: string) => void;14 onRegenerate?: () => void;15 onFeedback?: (feedback: MessageFeedback | null) => void;16 onBranch?: () => void;17 variant?: MessageActionsVariant;18 className?: string;19}2021export function MessageActions({22 content = '',23 feedback: feedbackProp,24 onCopy,25 onRegenerate,26 onFeedback,27 onBranch,28 variant = 'Ghost',29 className,30}: MessageActionsProps) {31 const [copied, setCopied] = useState(false);32 const [spinning, setSpinning] = useState(false);33 const [feedbackState, setFeedbackState] = useState<MessageFeedback | null>(null);34 const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);35 useEffect(() => () => clearTimeout(timer.current), []);3637 const feedback = feedbackProp !== undefined ? feedbackProp : feedbackState;3839 async function copy() {40 try {41 await navigator.clipboard.writeText(content);42 } catch {}43 onCopy?.(content);44 setCopied(true);45 clearTimeout(timer.current);46 timer.current = setTimeout(() => setCopied(false), 1600);47 }4849 function regenerate() {50 setSpinning(true);51 setTimeout(() => setSpinning(false), 500);52 onRegenerate?.();53 }5455 function rate(next: MessageFeedback) {56 const value = feedback === next ? null : next;57 setFeedbackState(value);58 onFeedback?.(value);59 }6061 return (62 <div63 role="toolbar"64 aria-label="Message actions"65 className={cn(66 'flex w-fit items-center gap-0.5 text-neutral-400 dark:text-neutral-500',67 'opacity-100 transition-opacity duration-150 [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover/message:opacity-100 [@media(hover:hover)]:focus-within:opacity-100',68 variant === 'Pill' &&69 'rounded-full border border-black/[0.07] bg-white p-0.5 shadow-xs dark:border-white/[0.08] dark:bg-neutral-900',70 className,71 )}72 >73 <ActionButton label={copied ? 'Copied' : 'Copy message'} onClick={copy}>74 <span className="relative grid size-3.5 place-items-center">75 <Copy76 className={cn(77// … truncated
What it pulls in
npm packages
Files it writes
More from spectrumui
All 182 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Agent Planagent-plan | spectrumui | Blocks | Free | 1 dep | |
| Agent Stepsagent-steps | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Approval Cardapproval-card | spectrumui | Blocks | Free | 1 dep | |
| Chat Empty Statechat-empty-state | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Citation Sourcescitation-sources | spectrumui | Blocks | Free | no deps · 2 files | |
| Code Blockcode-block | spectrumui | Blocks | Free | 1 dep | |
| Conversation Listconversation-list | spectrumui | Blocks | Free | 1 dep | |
| Diff Viewdiff-view | spectrumui | Blocks | Free | 1 dep |
