AI Message
hextaui/ai-messageFreeComponent
Display AI messages with markdown support and code highlighting.
Live preview
live · rendered by the registry
Rendered by HextaUI on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://hextaui.com/r/ai-message.jsonSource
1"use client";23import { Copy, Edit, MoreVertical, RotateCcw } from "lucide-react";4import { useTheme } from "next-themes";5import React, {6 startTransition,7 useCallback,8 useEffect,9 useId,10 useMemo,11 useRef,12 useState,13} from "react";14import ReactMarkdown from "react-markdown";15import remarkGfm from "remark-gfm";16import { type BundledLanguage, codeToHtml } from "shiki";17import { cn } from "@/lib/utils";18import { Button } from "@/registry/new-york/ui/button";19import {20 DropdownMenu,21 DropdownMenuContent,22 DropdownMenuItem,23 DropdownMenuSeparator,24 DropdownMenuShortcut,25 DropdownMenuTrigger,26} from "@/registry/new-york/ui/dropdown-menu";2728const STREAMING_CONFIG = {29 CHAR_DELAY: 20,30 BATCH_SIZE: 3,31} as const;3233const COPY_FEEDBACK_DURATION = 2000;3435interface AIMessageProps {36 content: string;37 isStreaming?: boolean;38 onRegenerate?: () => void;39 onEdit?: () => void;40 className?: string;41 skipCodeHighlighting?: boolean;42}4344function useStreamingText(fullText: string, isStreaming: boolean): string {45 const [displayedText, setDisplayedText] = useState(() =>46 isStreaming ? "" : fullText47 );48 const timeoutRef = useRef<NodeJS.Timeout | null>(null);4950 useEffect(() => {51 let initialTimeoutId: NodeJS.Timeout | null = null;5253 if (!isStreaming) {54 initialTimeoutId = setTimeout(() => {55 setDisplayedText(fullText);56 }, 0);57 return () => {58 if (initialTimeoutId) {59 clearTimeout(initialTimeoutId);60 }61 };62 }6364 if (typeof window !== "undefined") {65 const prefersReducedMotion = window.matchMedia(66 "(prefers-reduced-motion: reduce)"67 ).matches;6869 if (prefersReducedMotion) {70 initialTimeoutId = setTimeout(() => {71 setDisplayedText(fullText);72 }, 0);73 return () => {74 if (initialTimeoutId) {75 clearTimeout(initialTimeoutId);76 }77 };78 }79 }8081 initialTimeoutId = setTimeout(() => {82 setDisplayedText("");83 }, 0);84 let currentIndex = 0;8586 const streamNext = () => {87 if (currentIndex >= fullText.length) {88 return;89 }9091 const nextIndex = Math.min(92 currentIndex + STREAMING_CONFIG.BATCH_SIZE,93 fullText.length94 );95 setDisplayedText(fullText.slice(0, nextIndex));96 currentIndex = nextIndex;9798 timeoutRef.current = setTimeout(streamNext, STREAMING_CONFIG.CHAR_DELAY);99 };100101 streamNext();102103 return () => {104 if (initialTimeoutId) {105// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from HextaUI
All 139 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | HextaUI | Components | Free | 1 dep | |
| AI Chat Historyai-chat-history | HextaUI | Components | Free | no deps | |
| AI Citationsai-citations | HextaUI | Components | Free | no deps | |
| AI Conversationai-conversation | HextaUI | Components | Free | no deps | |
| AI Error Handlerai-error-handler | HextaUI | Components | Free | no deps | |
| AI File Uploadai-file-upload | HextaUI | Components | Free | no deps | |
| AI Model Selectorai-model-selector | HextaUI | Components | Free | no deps | |
| AI Prompt Inputai-prompt-input | HextaUI | Components | Free | no deps |
