@@ -12,6 +12,21 @@ import useCopyClipboard from '@/rest/components/useClipboard'
1212import { EventType } from '@/events/types'
1313import { sendEvent } from '@/events/components/events'
1414
15+ // Create a unique identifier by sampling characters distributed across content
16+ function getBlockId ( text : string , targetLength : number = 8 ) {
17+ const alphanumeric = text . replace ( / [ ^ a - z A - Z 0 - 9 ] + / g, '' ) . toLowerCase ( )
18+ if ( ! alphanumeric || alphanumeric . length <= targetLength ) {
19+ return Math . random ( ) . toString ( 36 ) . substring ( 2 , 10 )
20+ }
21+ const step = alphanumeric . length / targetLength
22+ let result = ''
23+ for ( let i = 0 ; i < targetLength ; i ++ ) {
24+ const index = Math . floor ( i * step )
25+ result += alphanumeric [ index ]
26+ }
27+ return result
28+ }
29+
1530export type MarkdownContentPropsT = {
1631 children : string
1732 className ?: string
@@ -35,6 +50,7 @@ export const UnrenderedMarkdownContent = ({
3550 ...restProps
3651} : MarkdownContentPropsT ) => {
3752 const { t } = useTranslation ( 'search' )
53+
3854 // Overrides for ReactMarkdown components
3955 const components = { } as Components
4056 if ( codeBlocksCopyable ) {
@@ -50,19 +66,32 @@ export const UnrenderedMarkdownContent = ({
5066 text = text . replace ( / \n $ / , '' )
5167 }
5268
69+ // Extract language from className for better accessibility
70+ const language = props . className ?. startsWith ( 'language-' )
71+ ? props . className . replace ( 'language-' , '' )
72+ : ''
73+
5374 const [ isCopied , copyToClipboard ] = useCopyClipboard ( text , {
5475 successDuration : 2000 ,
5576 } )
5677
78+ // Create more descriptive aria-label
79+ const getAriaLabel = ( ) => {
80+ if ( isCopied ) {
81+ return t ( 'search.ai.response.copied_code' )
82+ }
83+ return t ( 'search.ai.response.copy_code_lang' )
84+ . replace ( '{language}' , language ? `${ language } ` : '' )
85+ . replace ( '{block}' , getBlockId ( text ) )
86+ }
87+
5788 return (
5889 < div style = { { position : 'relative' } } >
5990 < IconButton
6091 size = "small"
6192 icon = { isCopied ? CheckIcon : CopyIcon }
6293 className = "btn-octicon"
63- aria-label = {
64- isCopied ? t ( 'search.ai.response.copied_code' ) : t ( 'search.ai.response.copy_code' )
65- }
94+ aria-label = { getAriaLabel ( ) }
6695 onClick = { async ( ) => {
6796 await copyToClipboard ( )
6897 announce ( t ( 'search.ai.response.copied_code' ) )
0 commit comments