@@ -4,7 +4,7 @@ import { VscVscode } from "react-icons/vsc"
44import Link from "next/link"
55import { motion } from "framer-motion"
66import { Copy , Check } from "lucide-react"
7- import { useState } from "react"
7+ import { useState , useEffect , useRef } from "react"
88
99interface InstallSectionProps {
1010 downloads : string | null
@@ -14,11 +14,22 @@ export function InstallSection({ downloads }: InstallSectionProps) {
1414 const [ copied , setCopied ] = useState ( false )
1515 const installCmd = "code --install-extension RooVeterinaryInc.roo-cline"
1616
17+ const timeoutRef = useRef < ReturnType < typeof setTimeout > | null > ( null )
18+
19+ useEffect ( ( ) => {
20+ return ( ) => {
21+ if ( timeoutRef . current ) {
22+ clearTimeout ( timeoutRef . current )
23+ }
24+ }
25+ } , [ ] )
26+
1727 const handleCopy = async ( ) => {
1828 try {
1929 await navigator . clipboard . writeText ( installCmd )
2030 setCopied ( true )
21- setTimeout ( ( ) => setCopied ( false ) , 1000 )
31+ const id = setTimeout ( ( ) => setCopied ( false ) , 1000 )
32+ timeoutRef . current = id
2233 } catch ( _e ) {
2334 // Fallback for environments without Clipboard API support
2435 const textarea = document . createElement ( "textarea" )
@@ -28,7 +39,8 @@ export function InstallSection({ downloads }: InstallSectionProps) {
2839 try {
2940 document . execCommand ( "copy" )
3041 setCopied ( true )
31- setTimeout ( ( ) => setCopied ( false ) , 1000 )
42+ const id = setTimeout ( ( ) => setCopied ( false ) , 1000 )
43+ timeoutRef . current = id
3244 } finally {
3345 document . body . removeChild ( textarea )
3446 }
@@ -123,7 +135,9 @@ export function InstallSection({ downloads }: InstallSectionProps) {
123135 ) : (
124136 < Copy className = "h-4 w-4" />
125137 ) }
126- < span className = "sr-only" > { copied ? "Copied" : "Copy" } </ span >
138+ < span className = "sr-only" aria-live = "polite" role = "status" >
139+ { copied ? "Copied" : "Copy" }
140+ </ span >
127141 </ button >
128142 </ div >
129143 </ div >
0 commit comments