"use client" import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" import { cn } from "cn" import { Button } from "@/components/ui/button" import { CheckIcon, CopyIcon } from "lucide-react" const codeBlockVariants = cva( "group/code-block relative flex w-full min-w-0 flex-col overflow-hidden rounded-2xl text-sm has-[>[data-slot=code-block-content]:focus-visible]:ring-3 has-[>[data-slot=code-block-content]:focus-visible]:ring-ring/30 data-[size=sm]:rounded-xl data-[size=sm]:text-xs", { variants: { variant: { default: "bg-muted text-foreground ring-1 ring-foreground/5 dark:ring-foreground/10", destructive: "bg-destructive/5 text-destructive ring-1 ring-destructive/15 dark:bg-destructive/10 dark:ring-destructive/20", }, }, defaultVariants: { variant: "default", }, } ) function CodeBlock({ className, variant = "default", size = "default", ...props }: React.ComponentProps<"div"> & VariantProps & { size?: "default" | "sm" }) { return (
) } function CodeBlockHeader({ className, ...props }: React.ComponentProps<"div">) { return (
[data-slot=code-block-title]]:min-w-0", className )} {...props} /> ) } function CodeBlockTitle({ className, ...props }: React.ComponentProps<"div">) { return (
) } function CodeBlockActions({ className, ...props }: React.ComponentProps<"div">) { return (
&]:absolute [[data-slot=code-block]>&]:end-4 [[data-slot=code-block]>&]:top-4 [[data-slot=code-block]>&]:z-10 [[data-slot=code-block]>&]:m-0 [[data-slot=code-block]>&]:opacity-0 [[data-slot=code-block]>&]:transition-opacity [[data-slot=code-block]>&]:group-focus-within/code-block:opacity-100 [[data-slot=code-block]>&]:group-hover/code-block:opacity-100 group-data-[size=sm]/code-block:[[data-slot=code-block]>&]:end-2 group-data-[size=sm]/code-block:[[data-slot=code-block]>&]:top-2 [[data-slot=code-block]>&]:pointer-coarse:opacity-100 [[data-slot=code-block]>&]:*:[button]:bg-background [[data-slot=code-block]>&]:*:[button]:ring-1 [[data-slot=code-block]>&]:*:[button]:ring-foreground/10", className )} {...props} /> ) } function CodeBlockCopyButton({ value, variant = "ghost", size = "icon-xs", className, onClick, ...props }: React.ComponentProps & { value: string }) { const [copied, setCopied] = React.useState(false) React.useEffect(() => { if (!copied) { return } const timeout = setTimeout(() => setCopied(false), 2000) return () => clearTimeout(timeout) }, [copied]) return ( <> {copied ? "Copied" : ""} ) } function CodeBlockContent({ className, children, style, wrap = false, lineNumbers = false, startLine = 1, ...props }: React.ComponentProps<"pre"> & { wrap?: boolean lineNumbers?: boolean startLine?: number }) { return (
      
        {lineNumbers && typeof children === "string"
          ? children
              .replace(/\n$/, "")
              .split("\n")
              .map((line, index) => (
                {line}
              ))
          : children}
      
    
) } const codeBlockLineVariants = cva( "relative -mx-5 block min-h-lh px-5 group-data-[size=sm]/code-block:-mx-3 group-data-[size=sm]/code-block:px-3 before:min-w-6 before:text-end before:text-muted-foreground after:absolute after:start-1 after:top-0 after:text-muted-foreground after:select-none in-data-numbered:col-span-2 in-data-numbered:grid in-data-numbered:grid-cols-subgrid in-data-numbered:gap-x-3 in-data-numbered:[counter-increment:line] in-data-numbered:before:content-[counter(line)] in-data-numbered:before:select-none in-data-numbered:supports-[content:counter(line)_/_'']:before:content-[counter(line)_/_'']", { variants: { variant: { default: "", added: "bg-foreground/5 after:content-['+']", removed: "bg-destructive/10 after:text-destructive after:content-['−']", highlighted: "bg-foreground/5", }, }, defaultVariants: { variant: "default", }, } ) function CodeBlockLine({ className, variant = "default", children, ...props }: React.ComponentProps<"span"> & VariantProps) { // An empty line holds a newline so copying a selection keeps blank lines. const empty = children === undefined || children === null || children === "" || (Array.isArray(children) && children.length === 0) return ( {empty ? "\n" : children} ) } function CodeBlockFooter({ className, ...props }: React.ComponentProps<"div">) { return (
) } export { CodeBlock, CodeBlockHeader, CodeBlockTitle, CodeBlockActions, CodeBlockCopyButton, CodeBlockContent, CodeBlockLine, CodeBlockFooter, }