tpmjs/packages/ui/src/CodeBlock/CodeBlock.tsx
Ajax Davis 990ba6f050 fix: correct Biome formatting and restore non-null assertions in tests
- Remove root biome.json (conflicted with packages/config/biome.json)
- Format all files with correct config (spaces, not tabs)
- Restore non-null assertions (ref!) in test files where refs are guaranteed
- Biome's optional chaining conversion broke TypeScript inference in tests

Fixes type-check and format-check CI failures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 19:04:34 +10:00

89 lines
1.9 KiB
TypeScript

import { cn } from "@tpmjs/utils/cn";
import { forwardRef, useState } from "react";
import { Icon } from "../Icon/Icon";
import type { CodeBlockProps } from "./types";
import {
codeBlockCodeVariants,
codeBlockContainerVariants,
codeBlockCopyButtonVariants,
} from "./variants";
/**
* CodeBlock component
*
* Displays formatted code with optional copy functionality.
* Includes syntax-highlighted display and copy-to-clipboard button.
* Built with React and JSX.
*
* @example
* ```typescript
* import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
*
* function MyComponent() {
* return (
* <CodeBlock
* code="npm install @tpmjs/registry"
* language="bash"
* size="md"
* showCopy={true}
* />
* );
* }
* ```
*/
export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
(
{
className,
code,
language = "text",
size = "md",
showCopy = true,
...props
},
ref,
) => {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
// Silently fail if clipboard API is not available
console.error("Failed to copy code:", err);
}
};
return (
<div
ref={ref}
className={cn(codeBlockContainerVariants(), className)}
{...props}
>
<code
className={codeBlockCodeVariants({
size,
})}
data-language={language}
>
{code}
</code>
{showCopy && (
<button
type="button"
className={codeBlockCopyButtonVariants()}
onClick={handleCopy}
aria-label={copied ? "Copied!" : "Copy code"}
data-testid="copy-button"
>
<Icon icon={copied ? "check" : "copy"} size="sm" />
</button>
)}
</div>
);
},
);
CodeBlock.displayName = "CodeBlock";