import { forwardRef, useState } from 'react' import CodeBlock from '../CodeBlock' import { CodeBlockVariant, DiffLineType } from '../types' import { codeBlockAccessibilityReport } from './CodeBlockAccessibilityReport' import { generateAccessibilityReport, downloadReport, getMimeType, getFileExtension, type ReportFormat, } from '../../shared/accessibility/reportGenerator' import { Download as DownloadIcon } from 'lucide-react' import { Button, ButtonType, ButtonSize } from '../../Button' export type CodeBlockAccessibilityProps = { className?: string } const CodeBlockAccessibility = forwardRef< HTMLDivElement, CodeBlockAccessibilityProps >(({ className }, ref) => { const [selectedFormat, setSelectedFormat] = useState('markdown') const [includeTestResults, setIncludeTestResults] = useState(true) const [includeRecommendations, setIncludeRecommendations] = useState(true) const [reportHtmlContent, setReportHtmlContent] = useState( null ) const [showFullReport, setShowFullReport] = useState(false) const handleDownload = () => { try { const content = generateAccessibilityReport( codeBlockAccessibilityReport, { format: selectedFormat, includeTestResults, includeRecommendations, } ) const filename = `codeblock-accessibility-report-${codeBlockAccessibilityReport.reportDate}.${getFileExtension(selectedFormat)}` const mimeType = getMimeType(selectedFormat) downloadReport(content, filename, mimeType) } catch (error) { console.error('Error generating report:', error) alert('Failed to generate report. Please try again.') } } const handleViewReport = () => { try { const htmlContent = generateAccessibilityReport( codeBlockAccessibilityReport, { format: 'html', includeTestResults, includeRecommendations, } ) setReportHtmlContent(htmlContent) setShowFullReport(true) } catch (error) { console.error('Error generating report:', error) alert('Failed to generate report. Please try again.') } } const report = codeBlockAccessibilityReport const compliantCount = report.criteria.filter( (c) => c.status === 'compliant' ).length const nonCompliantCount = report.criteria.filter( (c) => c.status === 'non-compliant' ).length const unsureCount = report.criteria.filter( (c) => c.status === 'unsure' ).length const totalApplicable = report.criteria.filter( (c) => c.status !== 'not-applicable' ).length const complianceRate = totalApplicable > 0 ? Math.round((compliantCount / totalApplicable) * 100) : 0 return (

CodeBlock Component Accessibility

WCAG {report.wcagVersion} • {report.conformanceLevel} • {report.reportDate}
Evaluates: WCAG 2.0, 2.1, 2.2

Download Report

{compliantCount}
Compliant ✅
Verified & tested
{nonCompliantCount}
Non-Compliant ❌
Issues found
{unsureCount}
Unsure ⚠️
Needs verification
{complianceRate}%
Compliance Rate
Based on verified items
{unsureCount > 0 && (
⚠️

Manual Verification Required

{unsureCount} criterion/criteria marked as "unsure" require manual verification. These items need testing with contrast checkers, screen readers, or depend on application context.

)}

Summary

{report.summary}

Quick Stats

Total Criteria: {report.criteria.length}
Level A: { report.criteria.filter( (c) => c.level === 'A' ).length }
Level AA: { report.criteria.filter( (c) => c.level === 'AA' ).length }
Level AAA: { report.criteria.filter( (c) => c.level === 'AAA' ).length }
{showFullReport && reportHtmlContent && (

Full Accessibility Report

)}

WCAG Criteria Breakdown

{report.criteria.map((criterion) => (
{criterion.id}:{' '} {criterion.title} Level {criterion.level} {criterion.status === 'compliant' ? '✅ Compliant' : criterion.status === 'non-compliant' ? '❌ Non-Compliant' : criterion.status === 'unsure' ? '⚠️ Unsure' : 'N/A'}

{criterion.description}

Implementation:

{criterion.implementation}

{criterion.testResults && (
Test Results:

{criterion.testResults}

)} {criterion.notes && (
Notes:

{criterion.notes}

)}
))}

Strengths

    {report.strengths.map((strength, index) => (
  • {strength}
  • ))}
{report.recommendations.length > 0 && (

Recommendations

    {report.recommendations.map( (recommendation, index) => (
  • {recommendation}
  • ) )}
)}

Component Examples

Basic CodeBlock

Basic code block with line numbers, header, and copy button. All interactive elements are keyboard accessible.

CodeBlock without Line Numbers

Code block without line numbers. Line number gutters are hidden from screen readers with aria-hidden="true".

CodeBlock without Header

Code block without header. The main region has aria-label describing the code block.

Diff View

Diff view showing removed, added, and unchanged lines. Each side has proper role="group" with aria-label.

Multiple Languages

TypeScript

Python

Code blocks support syntax highlighting for various programming languages. All variants maintain accessibility standards.

Keyboard Navigation

Copy Button:
  • Tab: Navigate to copy button
  • Enter/Space: Copy code to clipboard
  • Tab: Move focus away from code block
Code Content:
  • Tab: Focus code content for scrolling and selection
  • Arrow Keys: Navigate through code content
  • Mouse: Select and copy code text
) }) CodeBlockAccessibility.displayName = 'CodeBlockAccessibility' export default CodeBlockAccessibility