'use client' import { Check, Copy, WrapText, ArrowRightFromLine } from 'lucide-react' import { type MouseEvent, useCallback, useEffect, useState, useRef } from 'react' import { type ThemedToken } from 'shiki' import { type NodeHover } from 'twoslash' import { cn, copyToClipboard, Tooltip, TooltipContent, TooltipTrigger } from 'ui' import { getFontStyle } from './CodeBlock.utils' export function AnnotatedSpan({ token, annotations, }: { token: ThemedToken annotations: Array }) { const [open, setOpen] = useState(false) const [isTouchDevice, setIsTouchDevice] = useState(false) useEffect(() => { const touchDevice = !window.matchMedia('(pointer: fine)').matches setIsTouchDevice(touchDevice) }, []) const handleClick = useCallback( (evt: MouseEvent) => { if (isTouchDevice) { evt.preventDefault() evt.stopPropagation() setOpen((open) => !open) } }, [isTouchDevice] ) const onOpenChange = useCallback( (open: boolean) => { if (!isTouchDevice || !open) { setOpen(open) } }, [isTouchDevice] ) return ( {annotations.map((annotation, idx) => ( ))} ) } function Annotation({ annotation }: { annotation: NodeHover }) { const { text, docs, tags } = annotation return (
{text} {docs &&

{docs}

} {tags && (
{tags.map((tag, idx) => { return ( @{tag[0]} {tag[1]} ) })}
)}
) } export function CodeCopyButton({ className, content }: { className?: string; content: string }) { const [copied, setCopied] = useState(false) const handleCopy = async () => { copyToClipboard(content, () => { setCopied(true) setTimeout(() => setCopied(false), 1000) }) } return ( ) } export function CodeBlockControls({ content }: { content: string }) { const [isWrapped, setIsWrapped] = useState(false) const wrapperRef = useRef(null) const toggleWrap = useCallback(() => { setIsWrapped((prev) => { const newValue = !prev // Find the parent code block and toggle the wrap data attribute const codeBlock = wrapperRef.current?.closest('.shiki') if (codeBlock) { if (newValue) { codeBlock.setAttribute('data-wrapped', 'true') } else { codeBlock.removeAttribute('data-wrapped') } } return newValue }) }, []) return (
{isWrapped ? 'Disable word wrap' : 'Enable word wrap'}
) }