Skip to content

Commit

Permalink
feat: 🎸 make useCopyToClipboard hook interface more idiomatic
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Apr 7, 2019
1 parent cf84703 commit 0a6d773
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 76 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -73,6 +73,7 @@
- [**Side-effects**](./docs/Side-effects.md)
- [`useAsync`](./docs/useAsync.md) — resolves an `async` function.
- [`useAsyncRetry`](./docs/useAsyncRetry.md) — `useAsync` with `retry()` method.
- [`useCopyToClipboard`](./docs/useCopyToClipboard.md) — copies text to clipboard.
- [`useDebounce`](./docs/useDebounce.md) — debounces a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usedebounce--demo)
- [`useFavicon`](./docs/useFavicon.md) — sets favicon of the page.
- [`useLocalStorage`](./docs/useLocalStorage.md) — manages a value in `localStorage`.
Expand Down
57 changes: 19 additions & 38 deletions docs/useCopyToClipboard.md
@@ -1,54 +1,35 @@
# `useCopyToClipboard`

copy text to a users clipboard.
Copy text to a user's clipboard.

## Usage

### basic usage:

```jsx
import {useCopyToClipboard} from 'react-use';

const myComp = (props) => {
const [success, copyToClipboard] = useCopyToClipboard();
const myText = 'text to be copied';
return (
<span onClick={ () => copyToClipboard(myText) }>{myText}</span>
)
}
```
## Usage

### with timeout:
Basic usage

```jsx
import {useCopyToClipboard} from 'react-use';
const Demo = () => {
const [text, setText] = React.useState('');
const [copied, copyToClipboard] = useCopyToClipboard(text);

const myComp = (props) => {
const [success, copyToClipboard] = useCopyToClipboard(2000);
const myText = 'text to be copied';
return (
<div>
<span onClick={ () => copyToClipboard(myText) }>{myText}</span>
{ success && <span>copied to clipboard</span>}
<input value={text} onChange={e => setText(e.target.value)} />
<button type="button" onClick={copyToClipboard}>copy text</button>
<div>Copied: {copied ? 'Yes' : 'No'}</div>
</div>
)
)
}
```

### with custom polyfill:
## Reference

```jsx
import {useCopyToClipboard} from 'react-use';
import * as clipboard from "clipboard-polyfill"

const myComp = (props) => {
const [success, copyToClipboard] = useCopyToClipboard(undefined, clipboard.writeText);
const myText = 'text to be copied';
return (
<div>
<span onClick={ () => copyToClipboard(myText) }>{myText}</span>
{ success && <span>copied to clipboard</span>}
</div>
)
}
```js
const [copied, copyToClipboard] = useCopyToClipboard(text);
const [copied, copyToClipboard] = useCopyToClipboard(text, copyFunction);
```

, where

- `copyFunction` &mdash; function that receives a single string argument, which
it copies to user's clipboard.
13 changes: 7 additions & 6 deletions src/__stories__/useCopyToClipboard.story.tsx
Expand Up @@ -4,20 +4,21 @@ import ShowDocs from './util/ShowDocs';
import {useCopyToClipboard} from '..';

const Demo = () => {
const [success, copyToClipboard] = useCopyToClipboard(2000);
const textToCopy = "text to be copied"
const [text, setText] = React.useState('');
const [copied, copyToClipboard] = useCopyToClipboard(text);

return (
<div>
<span style={{margin: 10}}>{textToCopy}</span>
<button type="button" onClick={ () => copyToClipboard(textToCopy)}>copy text</button>
{ success && <span> text copied!</span>}
<input value={text} onChange={e => setText(e.target.value)} />
<button type="button" onClick={copyToClipboard}>copy text</button>
<div>Copied: {copied ? 'Yes' : 'No'}</div>
<div style={{margin: 10}}>
<input type="text" placeholder="now paste it in here"/>
</div>
</div>
)
}

storiesOf('UI|useCopyToClipboard', module)
storiesOf('Side-effects|useCopyToClipboard', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useCopyToClipboard.md')} />)
.add('Demo', () => <Demo/>)
50 changes: 18 additions & 32 deletions src/useCopyToClipboard.ts
@@ -1,41 +1,27 @@
import {useState, useEffect} from 'react';
import * as clipboard from "clipboard-polyfill"
import useUpdateEffect from './useUpdateEffect';
import {useState, useCallback} from 'react';

const copyDefault = (text) => {
console.log('run');
const element = document.createElement('textarea'); // create textarea HTML element
element.value = text; // add the text to be copied to the element
document.body.appendChild(element); // add element to DOM
element.select(); // select the text
document.execCommand('copy'); // execute copy command
document.body.removeChild(element); // remove element from DOM
const element = document.createElement('textarea');
element.value = text;
document.body.appendChild(element);
element.select();
document.execCommand('copy');
document.body.removeChild(element);
};

const useCopyToClipboard = (text: string = '', copy = copyDefault): [boolean, () => void] => {
const [copied, setCopied] = useState(false);
const copyToClipboard = useCallback(() => {
copy(text);
setCopied(true);
}, [text]);

const useCopyToClipboard = (timeout = undefined, copy = copyDefault) => {
useUpdateEffect(() => {
setCopied(false);
}, [text]);

const [success, setSuccess] = useState(false);

const copyToClipboard = (text) => {

if (typeof text == "string" || typeof text == "number" ) {
copy(text);
setSuccess(true);
}
else {
setSuccess(false);
console.error(`Cannot copy typeof ${typeof text} to clipboard, must be a valid string or number.`);
}
}

useEffect( () => {
// if timeout given, set success to false
if (timeout) {
if (success) setTimeout( () => setSuccess(false), timeout);
}
}, [success])

return [success, copyToClipboard];
return [copied, copyToClipboard];
}

export default useCopyToClipboard;

0 comments on commit 0a6d773

Please sign in to comment.