fix: copy clipboard fix
This commit is contained in:
@@ -103,29 +103,56 @@ export function useCopyFeedback() {
|
||||
|
||||
const copy = useCallback(async (text: string) => {
|
||||
let success = false;
|
||||
const finalText = await shortenHighlightUrlsIn(text);
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(finalText);
|
||||
success = true;
|
||||
} catch {
|
||||
// Fallback for iOS Safari and older browsers
|
||||
const ta = document.createElement("textarea");
|
||||
ta.value = finalText;
|
||||
ta.style.position = "fixed";
|
||||
ta.style.top = "0";
|
||||
ta.style.left = "0";
|
||||
ta.style.opacity = "0";
|
||||
document.body.appendChild(ta);
|
||||
ta.focus();
|
||||
ta.select();
|
||||
// Why we don't just `await shortenHighlightUrlsIn(text)` first: the URL
|
||||
// shortening is a network round-trip, and awaiting it consumes the
|
||||
// transient user activation that navigator.clipboard needs. The write
|
||||
// would then silently fail on the *first* click and only succeed on the
|
||||
// second (when the short link is cached and the shorten resolves
|
||||
// synchronously). Instead we hand the clipboard a *Promise* of the text
|
||||
// via ClipboardItem — the browser keeps the gesture alive while the
|
||||
// async work finishes, so a single click copies the shortened URL.
|
||||
if (typeof ClipboardItem !== "undefined" && navigator.clipboard?.write) {
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
const item = new ClipboardItem({
|
||||
"text/plain": shortenHighlightUrlsIn(text).then(
|
||||
(s) => new Blob([s], { type: "text/plain" }),
|
||||
),
|
||||
});
|
||||
await navigator.clipboard.write([item]);
|
||||
success = true;
|
||||
} catch {
|
||||
// silent fail
|
||||
// ClipboardItem-with-promise unsupported or rejected — fall through.
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
// Legacy path: now that ClipboardItem failed, await the text and try
|
||||
// the synchronous fallbacks. (May still need a second click on very old
|
||||
// browsers, but those lack ClipboardItem entirely.)
|
||||
const finalText = await shortenHighlightUrlsIn(text);
|
||||
try {
|
||||
await navigator.clipboard.writeText(finalText);
|
||||
success = true;
|
||||
} catch {
|
||||
// Fallback for older browsers without the async clipboard API.
|
||||
const ta = document.createElement("textarea");
|
||||
ta.value = finalText;
|
||||
ta.style.position = "fixed";
|
||||
ta.style.top = "0";
|
||||
ta.style.left = "0";
|
||||
ta.style.opacity = "0";
|
||||
document.body.appendChild(ta);
|
||||
ta.focus();
|
||||
ta.select();
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
success = true;
|
||||
} catch {
|
||||
// silent fail
|
||||
}
|
||||
document.body.removeChild(ta);
|
||||
}
|
||||
document.body.removeChild(ta);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
|
||||
Reference in New Issue
Block a user