1- import { useState } from "react" ;
1+ import { useEffect , useRef , useState } from "react" ;
22import { Button , DropdownMenu } from "@cloudflare/kumo" ;
33import {
44 CopySimpleIcon ,
@@ -15,8 +15,22 @@ interface CopyPageButtonProps {
1515 align ?: "start" | "center" | "end" ;
1616}
1717
18+ const COPIED_FEEDBACK_MS = 2000 ;
19+
1820export function CopyPageButton ( { align = "end" } : CopyPageButtonProps ) {
1921 const [ copied , setCopied ] = useState ( false ) ;
22+ const resetTimeoutRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
23+ const copyAttemptRef = useRef ( 0 ) ;
24+
25+ useEffect ( ( ) => {
26+ return ( ) => {
27+ copyAttemptRef . current += 1 ;
28+ if ( resetTimeoutRef . current !== null ) {
29+ clearTimeout ( resetTimeoutRef . current ) ;
30+ resetTimeoutRef . current = null ;
31+ }
32+ } ;
33+ } , [ ] ) ;
2034
2135 const getMarkdownUrl = ( ) => {
2236 const url = new URL ( window . location . href ) ;
@@ -29,23 +43,37 @@ export function CopyPageButton({ align = "end" }: CopyPageButtonProps) {
2943 return `${ url . origin } ${ path } .md` ;
3044 } ;
3145
32- const onCopySuccess = ( ) => {
33- setCopied ( true ) ;
46+ const onCopySuccess = ( attempt : number ) => {
47+ if ( copyAttemptRef . current !== attempt ) return ;
3448
35- setTimeout ( ( ) => setCopied ( false ) , 2000 ) ; // 2 seconds
49+ setCopied ( true ) ;
50+ resetTimeoutRef . current = setTimeout ( ( ) => {
51+ if ( copyAttemptRef . current !== attempt ) return ;
52+ setCopied ( false ) ;
53+ resetTimeoutRef . current = null ;
54+ } , COPIED_FEEDBACK_MS ) ;
3655 } ;
3756
3857 const handleCopyMarkdown = async ( ) => {
39- onCopySuccess ( ) ;
58+ const attempt = ++ copyAttemptRef . current ;
59+ if ( resetTimeoutRef . current !== null ) {
60+ clearTimeout ( resetTimeoutRef . current ) ;
61+ resetTimeoutRef . current = null ;
62+ }
4063
4164 try {
4265 const markdownUrl = getMarkdownUrl ( ) ;
4366 const response = await fetch ( markdownUrl ) ;
4467 if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` ) ;
4568 const markdown = await response . text ( ) ;
69+ if ( copyAttemptRef . current !== attempt ) return ;
4670
4771 await navigator . clipboard . writeText ( markdown ) ;
72+ onCopySuccess ( attempt ) ;
4873 } catch ( error ) {
74+ if ( copyAttemptRef . current !== attempt ) return ;
75+
76+ setCopied ( false ) ;
4977 console . error ( "Failed to copy page as Markdown:" , error ) ;
5078 }
5179 } ;
0 commit comments