Skip to content

Commit

Permalink
feat: 🎸 improve useCopyToClipboard() hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Apr 7, 2019
1 parent 0a6d773 commit f185044
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
4 changes: 2 additions & 2 deletions docs/useCopyToClipboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ const Demo = () => {

```js
const [copied, copyToClipboard] = useCopyToClipboard(text);
const [copied, copyToClipboard] = useCopyToClipboard(text, copyFunction);
const [copied, copyToClipboard] = useCopyToClipboard(text, writeText);
```

, where

- `copyFunction` — function that receives a single string argument, which
- `writeText` — function that receives a single string argument, which
it copies to user's clipboard.
48 changes: 39 additions & 9 deletions src/useCopyToClipboard.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,54 @@
import useUpdateEffect from './useUpdateEffect';
import {useState, useCallback} from 'react';
import useRefMounted from './useRefMounted';
import {useState, useCallback, useRef} from 'react';

const copyDefault = (text) => {
export type WriteText = (text: string) => Promise<void>; // https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText
export type UseCopyToClipboard = (text?: string, writeText?: WriteText) => [boolean, () => void];

const writeTextDefault = async (text) => {
const element = document.createElement('textarea');
element.value = text;
document.body.appendChild(element);
element.select();
document.execCommand('copy');
document.body.removeChild(element);
try {
element.select();
document.execCommand('copy');
} finally {
document.body.removeChild(element);
}
};

const useCopyToClipboard = (text: string = '', copy = copyDefault): [boolean, () => void] => {
const useCopyToClipboard: UseCopyToClipboard = (text = '', writeText = writeTextDefault) => {
if (process.env.NODE_ENV !== 'production') {
if (typeof text !== 'string') {
console.warn('useCopyToClipboard hook expects first argument to be string.');
}
}

const mounted = useRefMounted();
const latestText = useRef(text);
const [copied, setCopied] = useState(false);
const copyToClipboard = useCallback(() => {
copy(text);
setCopied(true);
const copyToClipboard = useCallback(async () => {
if (latestText.current !== text) {
if (process.env.NODE_ENV !== 'production') {
console.warn('Trying to copy stale text.');
}
return;
}

try {
await writeText(text);
if (!mounted.current) return;
setCopied(true);
} catch (error) {
if (!mounted.current) return;
console.error(error);
setCopied(false);
}
}, [text]);

useUpdateEffect(() => {
setCopied(false);
latestText.current = text;
}, [text]);

return [copied, copyToClipboard];
Expand Down

0 comments on commit f185044

Please sign in to comment.