|
1 | | -import { |
2 | | - useCallback, |
3 | | - useEffect, |
4 | | - useEffectEvent, |
5 | | - useRef, |
6 | | - useState, |
7 | | -} from "react"; |
| 1 | +import { useCallback, useEffect, useRef, useState } from "react"; |
8 | 2 | import { toast } from "sonner"; |
9 | 3 |
|
10 | 4 | const CLIPBOARD_TIMEOUT_MS = 1_000; |
@@ -44,55 +38,50 @@ export type UseClipboardResult = Readonly<{ |
44 | 38 | export const useClipboard = ( |
45 | 39 | input: UseClipboardInput = {}, |
46 | 40 | ): UseClipboardResult => { |
47 | | - const { |
48 | | - onError = (msg: string) => toast.error(msg), |
49 | | - clearErrorOnSuccess = true, |
50 | | - } = input; |
| 41 | + const { onError = toast.error, clearErrorOnSuccess = true } = input; |
51 | 42 |
|
52 | 43 | const [showCopiedSuccess, setShowCopiedSuccess] = useState(false); |
53 | 44 | const [error, setError] = useState<Error>(); |
54 | 45 | const timeoutIdRef = useRef<number | undefined>(undefined); |
55 | 46 |
|
56 | 47 | useEffect(() => { |
57 | | - const clearTimeoutOnUnmount = () => { |
58 | | - window.clearTimeout(timeoutIdRef.current); |
59 | | - }; |
60 | | - return clearTimeoutOnUnmount; |
| 48 | + return () => window.clearTimeout(timeoutIdRef.current); |
61 | 49 | }, []); |
62 | 50 |
|
63 | | - const onErrorEvent = useEffectEvent(() => onError(COPY_FAILED_MESSAGE)); |
64 | | - const handleSuccessfulCopy = useEffectEvent(() => { |
65 | | - setShowCopiedSuccess(true); |
66 | | - if (clearErrorOnSuccess) { |
67 | | - setError(undefined); |
68 | | - } |
69 | | - |
70 | | - timeoutIdRef.current = window.setTimeout(() => { |
71 | | - setShowCopiedSuccess(false); |
72 | | - }, CLIPBOARD_TIMEOUT_MS); |
73 | | - }); |
74 | | - |
75 | | - const copyToClipboard = useCallback(async (textToCopy: string) => { |
76 | | - try { |
77 | | - await window.navigator.clipboard.writeText(textToCopy); |
78 | | - handleSuccessfulCopy(); |
79 | | - } catch (err) { |
80 | | - const fallbackCopySuccessful = simulateClipboardWrite(textToCopy); |
81 | | - if (fallbackCopySuccessful) { |
82 | | - handleSuccessfulCopy(); |
83 | | - return; |
| 51 | + const copyToClipboard = useCallback( |
| 52 | + async (textToCopy: string) => { |
| 53 | + const markSuccess = () => { |
| 54 | + setShowCopiedSuccess(true); |
| 55 | + if (clearErrorOnSuccess) { |
| 56 | + setError(undefined); |
| 57 | + } |
| 58 | + timeoutIdRef.current = window.setTimeout(() => { |
| 59 | + setShowCopiedSuccess(false); |
| 60 | + }, CLIPBOARD_TIMEOUT_MS); |
| 61 | + }; |
| 62 | + |
| 63 | + try { |
| 64 | + await window.navigator.clipboard.writeText(textToCopy); |
| 65 | + markSuccess(); |
| 66 | + } catch (err) { |
| 67 | + const fallbackCopySuccessful = simulateClipboardWrite(textToCopy); |
| 68 | + if (fallbackCopySuccessful) { |
| 69 | + markSuccess(); |
| 70 | + return; |
| 71 | + } |
| 72 | + |
| 73 | + const wrappedErr = new Error(COPY_FAILED_MESSAGE); |
| 74 | + if (err instanceof Error) { |
| 75 | + wrappedErr.stack = err.stack; |
| 76 | + } |
| 77 | + |
| 78 | + console.error(wrappedErr); |
| 79 | + setError(wrappedErr); |
| 80 | + onError(COPY_FAILED_MESSAGE); |
84 | 81 | } |
85 | | - |
86 | | - const wrappedErr = new Error(COPY_FAILED_MESSAGE); |
87 | | - if (err instanceof Error) { |
88 | | - wrappedErr.stack = err.stack; |
89 | | - } |
90 | | - |
91 | | - console.error(wrappedErr); |
92 | | - setError(wrappedErr); |
93 | | - onErrorEvent(); |
94 | | - } |
95 | | - }, []); |
| 82 | + }, |
| 83 | + [onError, clearErrorOnSuccess], |
| 84 | + ); |
96 | 85 |
|
97 | 86 | return { showCopiedSuccess, error, copyToClipboard }; |
98 | 87 | }; |
|
0 commit comments