import { Transition } from "@headlessui/react"; import { ClipboardDocumentIcon, CheckIcon } from "@heroicons/react/24/outline"; import clsx from "clsx"; import { useMemo, useCallback, type HTMLAttributes } from "react"; import { useEffect, useState } from "react"; import type { OffsetOrPosition } from "shiki"; import style from "./style.module.css"; import type { SupportedLanguage } from "./supported-language"; import { useHighlightedCode } from "./use-highlighted-code"; import { getLogger } from "../../browser-logger"; import { Button } from "../Button"; export * from "./supported-language"; type CodeProps = { language?: SupportedLanguage | undefined; children: string; dimRange?: readonly [OffsetOrPosition, OffsetOrPosition] | undefined; }; export const Code = ({ language, children, dimRange }: CodeProps) => { const chompedCode = useMemo(() => chomp(children), [children]); return (
{chompedCode} {chompedCode}
); }; const chomp = (text: string) => { const splitText = text.split("\n"); const firstNonemptyLine = splitText.findIndex((line) => line.trim() !== ""); const lastNonemptyLine = splitText.findLastIndex( (line) => line.trim() !== "", ); return splitText.slice(firstNonemptyLine, lastNonemptyLine + 1).join("\n"); }; type CopyButtonProps = Omit, "children"> & { children: string; }; const CopyButton = ({ children, className, ...props }: CopyButtonProps) => { const [isCopied, setIsCopied] = useState(false); const copy = useCallback(() => { navigator.clipboard .writeText(children) .then(() => { setIsCopied(true); }) .catch((error: unknown) => { /* TODO do something here? */ getLogger().error(error); }); }, [children]); useEffect(() => { setIsCopied(false); }, [children]); useEffect(() => { if (isCopied) { const timeout = setTimeout(() => { setIsCopied(false); }, 2000); return () => { clearTimeout(timeout); }; } else { return; } }, [isCopied]); return (
); }; type HighlightedCodeProps = Omit, "children"> & { language?: SupportedLanguage | undefined; children: string; dimRange?: readonly [OffsetOrPosition, OffsetOrPosition] | undefined; }; const HighlightedCode = ({ language, children, dimRange, className, ...props }: HighlightedCodeProps) => { const highlightedCode = useHighlightedCode(language, children, dimRange); return (
{children.split("\n").map((line, i) => (
{line}
))}
), })} /> ); };