fix: copy clipboard fix
This commit is contained in:
@@ -103,29 +103,56 @@ export function useCopyFeedback() {
|
|||||||
|
|
||||||
const copy = useCallback(async (text: string) => {
|
const copy = useCallback(async (text: string) => {
|
||||||
let success = false;
|
let success = false;
|
||||||
const finalText = await shortenHighlightUrlsIn(text);
|
|
||||||
|
|
||||||
try {
|
// Why we don't just `await shortenHighlightUrlsIn(text)` first: the URL
|
||||||
await navigator.clipboard.writeText(finalText);
|
// shortening is a network round-trip, and awaiting it consumes the
|
||||||
success = true;
|
// transient user activation that navigator.clipboard needs. The write
|
||||||
} catch {
|
// would then silently fail on the *first* click and only succeed on the
|
||||||
// Fallback for iOS Safari and older browsers
|
// second (when the short link is cached and the shorten resolves
|
||||||
const ta = document.createElement("textarea");
|
// synchronously). Instead we hand the clipboard a *Promise* of the text
|
||||||
ta.value = finalText;
|
// via ClipboardItem — the browser keeps the gesture alive while the
|
||||||
ta.style.position = "fixed";
|
// async work finishes, so a single click copies the shortened URL.
|
||||||
ta.style.top = "0";
|
if (typeof ClipboardItem !== "undefined" && navigator.clipboard?.write) {
|
||||||
ta.style.left = "0";
|
|
||||||
ta.style.opacity = "0";
|
|
||||||
document.body.appendChild(ta);
|
|
||||||
ta.focus();
|
|
||||||
ta.select();
|
|
||||||
try {
|
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;
|
success = true;
|
||||||
} catch {
|
} 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) {
|
if (success) {
|
||||||
|
|||||||
Reference in New Issue
Block a user