"use client"; import { CodeBlock, type CodeBlockProps, Pre, } from "@/components/ui/code-block"; import type { HighlightOptions, HighlightOptionsCommon, HighlightOptionsThemes, } from "fumadocs-core/highlight"; import { useShiki } from "fumadocs-core/highlight/client"; import { cn } from "@/lib/utils"; import { type ComponentProps, createContext, type FC, Suspense, use, } from "react"; export interface DynamicCodeblockProps { lang: string; code: string; /** * Extra props for the underlying `` component. * * Ignored if you defined your own `pre` component in `options.components`. */ codeblock?: CodeBlockProps; /** * Wrap in React `` and provide a fallback. * * @defaultValue true */ wrapInSuspense?: boolean; /** * Allow to copy code with copy button * * @defaultValue true */ allowCopy?: boolean; options?: Omit & HighlightOptionsThemes; } const PropsContext = createContext(undefined); function DefaultPre(props: ComponentProps<"pre">) { const extraProps = use(PropsContext); return (
{props.children}
); } export function DynamicCodeBlock({ lang, code, codeblock, options, wrapInSuspense = true, allowCopy = true, }: DynamicCodeblockProps) { const shikiOptions = { lang, ...options, components: { pre: DefaultPre, ...options?.components, }, } satisfies HighlightOptions; let children = ; if (wrapInSuspense) children = ( } > {children} ); return ( {children} ); } function Placeholder({ code, components = {}, }: { code: string; components: HighlightOptions["components"]; }) { const { pre: Pre = "pre", code: Code = "code" } = components as Record< string, FC >; return (
			
				{code.split("\n").map((line, i) => (
					
						{line}
					
				))}
			
		
); } function Internal({ code, options, }: { code: string; options: HighlightOptions; }) { return useShiki(code, options); }