@@ -225,35 +225,28 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
225225 setInputValue,
226226 } )
227227
228- // Handle modifier key detection for mention clicks
229- const handleGlobalKeyDown = useCallback (
230- ( e : KeyboardEvent ) => {
228+ // Add global event listeners for modifier key detection
229+ useEffect ( ( ) => {
230+ const handleGlobalKeyDown = ( e : KeyboardEvent ) => {
231231 if ( ( isMac && e . metaKey ) || ( ! isMac && e . ctrlKey ) ) {
232232 setIsModifierPressed ( true )
233233 }
234- } ,
235- [ isMac ] ,
236- )
234+ }
237235
238- const handleGlobalKeyUp = useCallback (
239- ( e : KeyboardEvent ) => {
236+ const handleGlobalKeyUp = ( e : KeyboardEvent ) => {
240237 if ( ( isMac && ! e . metaKey ) || ( ! isMac && ! e . ctrlKey ) ) {
241238 setIsModifierPressed ( false )
242239 }
243- } ,
244- [ isMac ] ,
245- )
240+ }
246241
247- // Add global event listeners for modifier key detection
248- useEffect ( ( ) => {
249242 document . addEventListener ( "keydown" , handleGlobalKeyDown )
250243 document . addEventListener ( "keyup" , handleGlobalKeyUp )
251244
252245 return ( ) => {
253246 document . removeEventListener ( "keydown" , handleGlobalKeyDown )
254247 document . removeEventListener ( "keyup" , handleGlobalKeyUp )
255248 }
256- } , [ handleGlobalKeyDown , handleGlobalKeyUp ] )
249+ } , [ isMac ] )
257250
258251 // Handle clicks on mentions in the highlight layer
259252 const handleMentionClick = useCallback (
@@ -273,6 +266,27 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
273266 [ isModifierPressed ] ,
274267 )
275268
269+ // Handle keyboard events on mentions for accessibility
270+ const handleMentionKeyDown = useCallback (
271+ ( e : KeyboardEvent ) => {
272+ if ( ! isModifierPressed ) return
273+
274+ const target = e . target as HTMLElement
275+ if ( target . tagName === "MARK" && target . classList . contains ( "mention-context-textarea-highlight" ) ) {
276+ if ( e . key === "Enter" || e . key === " " ) {
277+ e . preventDefault ( )
278+ const mentionText = target . textContent
279+ if ( mentionText ) {
280+ // Remove @ symbol if present and send to VSCode
281+ const cleanText = mentionText . startsWith ( "@" ) ? mentionText . slice ( 1 ) : mentionText
282+ vscode . postMessage ( { type : "openMention" , text : cleanText } )
283+ }
284+ }
285+ }
286+ } ,
287+ [ isModifierPressed ] ,
288+ )
289+
276290 // Fetch git commits when Git is selected or when typing a hash.
277291 useEffect ( ( ) => {
278292 if ( selectedType === ContextMenuOptionType . Git || / ^ [ a - f 0 - 9 ] + $ / i. test ( searchQuery ) ) {
@@ -771,14 +785,18 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
771785
772786 // Determine the class to use based on modifier key state
773787 const mentionClass = `mention-context-textarea-highlight${ isModifierPressed ? " clickable" : "" } `
788+ const tabIndex = isModifierPressed ? 0 : - 1
789+ const ariaLabel = isModifierPressed
790+ ? `${ isMac ? "Cmd" : "Ctrl" } + Click or Enter to open`
791+ : `Hold ${ isMac ? "Cmd" : "Ctrl" } + Click to open`
774792
775793 // Process the text to highlight mentions and valid commands
776794 let processedText = text
777795 . replace ( / \n $ / , "\n\n" )
778796 . replace ( / [ < > & ] / g, ( c ) => ( { "<" : "<" , ">" : ">" , "&" : "&" } ) [ c ] || c )
779797 . replace (
780798 mentionRegexGlobal ,
781- `<mark class="${ mentionClass } " title ="${ isModifierPressed ? ` ${ isMac ? "Cmd" : "Ctrl" } + Click to open` : `Hold ${ isMac ? "Cmd" : "Ctrl" } + Click to open` } ">$&</mark>` ,
799+ `<mark class="${ mentionClass } " tabindex ="${ tabIndex } " role="button" aria-label=" ${ ariaLabel } " title=" ${ ariaLabel } ">$&</mark>` ,
782800 )
783801
784802 // Custom replacement for commands - only highlight valid ones
@@ -791,10 +809,10 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
791809
792810 if ( startsWithSpace ) {
793811 // Keep the space but only highlight the command part
794- return ` <mark class="${ mentionClass } " title ="${ isModifierPressed ? ` ${ isMac ? "Cmd" : "Ctrl" } + Click to open` : `Hold ${ isMac ? "Cmd" : "Ctrl" } + Click to open` } ">${ commandPart } </mark>`
812+ return ` <mark class="${ mentionClass } " tabindex ="${ tabIndex } " role="button" aria-label=" ${ ariaLabel } " title=" ${ ariaLabel } ">${ commandPart } </mark>`
795813 } else {
796814 // Highlight the entire command (starts at beginning of line)
797- return `<mark class="${ mentionClass } " title ="${ isModifierPressed ? ` ${ isMac ? "Cmd" : "Ctrl" } + Click to open` : `Hold ${ isMac ? "Cmd" : "Ctrl" } + Click to open` } ">${ commandPart } </mark>`
815+ return `<mark class="${ mentionClass } " tabindex ="${ tabIndex } " role="button" aria-label=" ${ ariaLabel } " title=" ${ ariaLabel } ">${ commandPart } </mark>`
798816 }
799817 }
800818 return match // Return unhighlighted if command is not valid
@@ -810,16 +828,18 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
810828 updateHighlights ( )
811829 } , [ inputValue , updateHighlights ] )
812830
813- // Add click event listener to highlight layer for mention clicks
831+ // Add click and keyboard event listeners to highlight layer for mention interactions
814832 useEffect ( ( ) => {
815833 const highlightLayer = highlightLayerRef . current
816834 if ( highlightLayer ) {
817835 highlightLayer . addEventListener ( "click" , handleMentionClick )
836+ highlightLayer . addEventListener ( "keydown" , handleMentionKeyDown )
818837 return ( ) => {
819838 highlightLayer . removeEventListener ( "click" , handleMentionClick )
839+ highlightLayer . removeEventListener ( "keydown" , handleMentionKeyDown )
820840 }
821841 }
822- } , [ handleMentionClick ] )
842+ } , [ handleMentionClick , handleMentionKeyDown ] )
823843
824844 const updateCursorPosition = useCallback ( ( ) => {
825845 if ( textAreaRef . current ) {
0 commit comments