11'use client' ;
22
3- import { Fragment , useEffect , useRef , useState } from 'react' ;
3+ import { Fragment , useCallback , useEffect , useRef , useState } from 'react' ;
44import { createPortal } from 'react-dom' ;
55import { Clipboard } from 'react-feather' ;
66import Link from 'next/link' ;
@@ -24,7 +24,15 @@ export function CopyMarkdownButton({pathname}: CopyMarkdownButtonProps) {
2424 const dropdownRef = useRef < HTMLDivElement > ( null ) ;
2525 const { emit} = usePlausibleEvent ( ) ;
2626
27-
27+ const fetchMarkdownContent = useCallback ( async ( ) : Promise < string > => {
28+ // This doesn't work on local development since we need the generated markdown
29+ // files, and we need to be aware of the origin since we have two different origins.
30+ const response = await fetch ( `${ window . location . origin } /${ pathname } .md` ) ;
31+ if ( ! response . ok ) {
32+ throw new Error ( `Failed to fetch markdown content: ${ response . status } ` ) ;
33+ }
34+ return await response . text ( ) ;
35+ } , [ pathname ] ) ;
2836
2937 const copyMarkdownToClipboard = async ( ) => {
3038 setIsLoading ( true ) ;
@@ -36,18 +44,10 @@ export function CopyMarkdownButton({pathname}: CopyMarkdownButtonProps) {
3644
3745 try {
3846 let content : string ;
39-
40- // Use pre-fetched content if available (for mobile)
4147 if ( prefetchedContent ) {
4248 content = prefetchedContent ;
4349 } else {
44- // This doesn't work on local development since we need the generated markdown
45- // files, and we need to be aware of the origin since we have two different origins.
46- const response = await fetch ( `${ window . location . origin } /${ pathname } .md` ) ;
47- if ( ! response . ok ) {
48- throw new Error ( `Failed to fetch markdown content: ${ response . status } ` ) ;
49- }
50- content = await response . text ( ) ;
50+ content = await fetchMarkdownContent ( ) ;
5151 }
5252
5353 await navigator . clipboard . writeText ( content ) ;
@@ -94,21 +94,20 @@ export function CopyMarkdownButton({pathname}: CopyMarkdownButtonProps) {
9494 } , [ ] ) ;
9595
9696 // Pre-fetch markdown content to avoid losing user gesture context
97+ // On iOS we can't async fetch on tap because the user gesture is lost by the time we try to update the clipboard.
9798 useEffect ( ( ) => {
9899 if ( ! prefetchedContent ) {
99100 const prefetchContent = async ( ) => {
100101 try {
101- const response = await fetch ( `${ window . location . origin } /${ pathname } .md` ) ;
102- if ( response . ok ) {
103- setPrefetchedContent ( await response . text ( ) ) ;
104- }
102+ const content = await fetchMarkdownContent ( ) ;
103+ setPrefetchedContent ( content ) ;
105104 } catch ( err ) {
106105 // Silently fail - we'll fall back to regular fetch on click
107106 }
108107 } ;
109108 prefetchContent ( ) ;
110109 }
111- } , [ pathname , prefetchedContent ] ) ;
110+ } , [ pathname , prefetchedContent , fetchMarkdownContent ] ) ;
112111
113112 const getDropdownPosition = ( ) => {
114113 if ( ! buttonRef . current ) return { top : 0 , left : 0 } ;
0 commit comments