"use client"; import "@assistant-ui/react-markdown/styles/dot.css"; import { type CodeHeaderProps, MarkdownTextPrimitive, unstable_memoizeMarkdownComponents as memoizeMarkdownComponents, useIsMarkdownCodeBlock, } from "@assistant-ui/react-markdown"; import remarkGfm from "remark-gfm"; import { type FC, memo, useMemo, useRef } from "react"; import type { TextMessagePartProps } from "@assistant-ui/react"; import { CheckIcon, CopyIcon } from "lucide-react"; import { TooltipIconButton } from './tooltip-icon-button'; import { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard'; import { cn } from '../../lib/utils'; type MarkdownTextProps = Partial & { components?: Parameters[0]; }; const useShallowStable = | undefined>( value: T, ): T => { const ref = useRef(value); if (value !== ref.current) { const prev = ref.current; const stable = value !== undefined && prev !== undefined && Object.keys(prev).length === Object.keys(value).length && Object.keys(value).every((key) => prev[key] === value[key]); if (!stable) ref.current = value; } return ref.current; }; const MarkdownTextImpl: FC = ({ components }) => { const stableComponents = useShallowStable(components); const markdownComponents = useMemo(() => { if (!stableComponents) return defaultComponents; return { ...defaultComponents, ...memoizeMarkdownComponents(stableComponents), }; }, [stableComponents]); return ( ); }; export const MarkdownText = memo(MarkdownTextImpl); const CodeHeader: FC = ({ language, code }) => { const { isCopied, copyToClipboard } = useCopyToClipboard(); const onCopy = () => { if (!code || isCopied) return; copyToClipboard(code); }; return (
{language} {!isCopied && ( )} {isCopied && ( )}
); }; const defaultComponents = memoizeMarkdownComponents({ h1: ({ className, ...props }) => (

), h2: ({ className, ...props }) => (

), h3: ({ className, ...props }) => (

), h4: ({ className, ...props }) => (

), h5: ({ className, ...props }) => (

), h6: ({ className, ...props }) => (
), p: ({ className, ...props }) => (

), a: ({ className, ...props }) => ( ), blockquote: ({ className, ...props }) => (

), ul: ({ className, ...props }) => (
    li]:mt-1", className, )} {...props} /> ), ol: ({ className, ...props }) => (
      li]:mt-1", className, )} {...props} /> ), hr: ({ className, ...props }) => (
      ), table: ({ className, ...props }) => ( ), th: ({ className, ...props }) => ( td:first-child]:rounded-es-lg [&:last-child>td:last-child]:rounded-ee-lg", className, )} {...props} /> ), li: ({ className, ...props }) => (
    1. ), strong: ({ className, ...props }) => ( ), sup: ({ className, ...props }) => ( a]:text-xs [&>a]:no-underline", className)} {...props} /> ), pre: ({ className, ...props }) => (
        ),
        code: function Code({ className, ...props }) {
          const isCodeBlock = useIsMarkdownCodeBlock();
          return (
            
          );
        },
        CodeHeader,
      });
      
    2. ), td: ({ className, ...props }) => ( ), tr: ({ className, ...props }) => (