mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 16:23:06 +10:00
feat: add safari clipboard copy support
This commit is contained in:
54
packages/lib/client-only/hooks/use-copy-share-link.ts
Normal file
54
packages/lib/client-only/hooks/use-copy-share-link.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { TCreateOrGetShareLinkMutationSchema } from '@documenso/trpc/server/share-link-router/schema';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { useCopyToClipboard } from './use-copy-to-clipboard';
|
||||
|
||||
export function useCopyShareLink() {
|
||||
const { toast } = useToast();
|
||||
|
||||
const [, copyToClipboard] = useCopyToClipboard();
|
||||
|
||||
const { mutateAsync: createOrGetShareLink, isLoading: isCreatingShareLink } =
|
||||
trpc.shareLink.createOrGetShareLink.useMutation();
|
||||
|
||||
/**
|
||||
* Copy a share link to the user's clipboard.
|
||||
*
|
||||
* Will create or get a share link if one is not provided.
|
||||
*
|
||||
* @param payload Either the share link itself or the input to create a new share link.
|
||||
*/
|
||||
const copyShareLink = async (payload: TCreateOrGetShareLinkMutationSchema | string) => {
|
||||
const valueToCopy =
|
||||
typeof payload === 'string'
|
||||
? payload
|
||||
: createOrGetShareLink(payload).then(
|
||||
(result) => `${window.location.origin}/share/${result.slug}`,
|
||||
);
|
||||
|
||||
try {
|
||||
const isCopySuccess = await copyToClipboard(valueToCopy);
|
||||
if (!isCopySuccess) {
|
||||
throw new Error('Copy to clipboard failed');
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Copied to clipboard',
|
||||
description: 'The sharing link has been copied to your clipboard.',
|
||||
});
|
||||
} catch {
|
||||
toast({
|
||||
variant: 'destructive',
|
||||
title: 'Something went wrong',
|
||||
description: 'The sharing link could not be created at this time. Please try again.',
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isCopyingShareLink: isCreatingShareLink,
|
||||
copyShareLink,
|
||||
};
|
||||
}
|
||||
55
packages/lib/client-only/hooks/use-copy-to-clipboard.ts
Normal file
55
packages/lib/client-only/hooks/use-copy-to-clipboard.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
export type CopiedValue = string | null;
|
||||
export type CopyFn = (_text: CopyValue, _blobType?: string) => Promise<boolean>;
|
||||
|
||||
type CopyValue = Promise<string> | string;
|
||||
|
||||
export function useCopyToClipboard(): [CopiedValue, CopyFn] {
|
||||
const [copiedText, setCopiedText] = useState<CopiedValue>(null);
|
||||
|
||||
const copy: CopyFn = async (text, blobType = 'text/plain') => {
|
||||
if (!navigator?.clipboard) {
|
||||
console.warn('Clipboard not supported');
|
||||
return false;
|
||||
}
|
||||
|
||||
const isClipboardApiSupported = Boolean(typeof ClipboardItem && navigator.clipboard.write);
|
||||
|
||||
// Try to save to clipboard then save it in the state if worked
|
||||
try {
|
||||
isClipboardApiSupported
|
||||
? await handleClipboardApiCopy(text, blobType)
|
||||
: await handleWriteTextCopy(text);
|
||||
|
||||
setCopiedText(await text);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn('Copy failed', error);
|
||||
setCopiedText(null);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle copying values to the clipboard using the ClipboardItem API.
|
||||
*
|
||||
* Allows us to copy async values for Safari. Does not work in FireFox.
|
||||
*
|
||||
* https://caniuse.com/mdn-api_clipboarditem
|
||||
*/
|
||||
const handleClipboardApiCopy = async (value: CopyValue, blobType = 'text/plain') => {
|
||||
await navigator.clipboard.write([new ClipboardItem({ [blobType]: value })]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle copying values to the clipboard using `writeText`.
|
||||
*
|
||||
* Will not work in Safari for async values.
|
||||
*/
|
||||
const handleWriteTextCopy = async (value: CopyValue) => {
|
||||
await navigator.clipboard.writeText(await value);
|
||||
};
|
||||
|
||||
return [copiedText, copy];
|
||||
}
|
||||
Reference in New Issue
Block a user