This repository was archived by the owner on Aug 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathuseClipboard.ts
117 lines (89 loc) · 2.78 KB
/
useClipboard.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { useState, useCallback } from 'react';
interface UseClipboardState {
clipboardState: string;
setClipboard: (value: string) => Promise<void>;
readClipboard: () => Promise<void>;
}
const NOT_ALLOWED_ERROR = new Error('Not Allowed');
const createInput = (): HTMLInputElement => {
const i = document.createElement('input');
i.setAttribute('size', '0');
i.style.setProperty('border-width', '0');
i.style.setProperty('bottom', '0');
i.style.setProperty('margin-left', '0');
i.style.setProperty('margin-top', '0');
i.style.setProperty('outline-width', '0');
i.style.setProperty('padding-bottom', '0');
i.style.setProperty('padding-left', '0');
i.style.setProperty('padding-right', '0');
i.style.setProperty('padding-top', '0');
i.style.setProperty('right', '0');
i.style.setProperty('box-sizing', 'border-box');
i.style.setProperty('margin-bottom', '-1px');
i.style.setProperty('margin-right', '-1px');
i.style.setProperty('width', '1px');
i.style.setProperty('height', '1px');
i.style.setProperty('max-width', '1px');
i.style.setProperty('max-height', '1px');
i.style.setProperty('min-width', '1px');
i.style.setProperty('min-height', '1px');
i.style.setProperty('outline-color', 'transparent');
i.style.setProperty('position', 'absolute');
i.style.setProperty('user-select', 'auto');
document.body.appendChild(i);
return i;
};
const removeInput = (i: HTMLInputElement): void => {
document.body.removeChild(i);
};
const read = (): Promise<string> => new Promise((resolve, reject): void => {
const i = createInput();
i.focus();
const success = document.execCommand('paste');
if (!success) {
removeInput(i);
reject(NOT_ALLOWED_ERROR);
}
const { value } = i;
removeInput(i);
resolve(value);
});
const write = (text: string): Promise<void> => new Promise((resolve, reject): void => {
const i = createInput();
i.setAttribute('value', text);
i.select();
const success = document.execCommand('copy');
removeInput(i);
if (!success) {
reject(NOT_ALLOWED_ERROR);
}
resolve();
});
/**
* Hook that read and write to the user's clipboard.
*/
export const useClipboard = (): UseClipboardState => {
const [clipboardState, setClipboardState] = useState('');
const setClipboard = useCallback(async (value: string) => {
if (navigator.clipboard) {
await navigator.clipboard.writeText(value);
} else {
await write(value);
}
setClipboardState(value);
}, []);
const readClipboard = useCallback(async () => {
let clipboard: string;
if (navigator.clipboard) {
clipboard = await navigator.clipboard.readText();
} else {
clipboard = await read();
}
setClipboardState(clipboard);
}, []);
return {
clipboardState,
setClipboard,
readClipboard,
};
};