Skip to content

Commit bc6d4d8

Browse files
committed
[WIP] useClipboard hook
1 parent dc251d6 commit bc6d4d8

2 files changed

Lines changed: 100 additions & 1 deletion

File tree

packages/react-tools/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
- [x] useInterval
6767
- [x] useTextSelection
6868
- [x] useDocumentVisibility
69-
- [ ] useCoptyToClipboard
69+
- [-] useClipboard
7070
- [ ] useColorScheme
7171
- [ ] useTitle (change document.title but also document.head.title nodeElement)
7272
- [ ] useFetch
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { RefObject, useCallback, useRef } from "react";
2+
import { useSyncExternalStore } from ".";
3+
4+
const askPermission = (type: "clipboard-read" | "clipboard-write") => {
5+
return navigator.permissions.query({
6+
name: type as PermissionName
7+
})
8+
.then(permission => {
9+
if (permission.state === "denied") {
10+
throw Error(`Permission to ${type.includes("read") ? "copy to" : "paste from"} Clipboard denied.`);
11+
}
12+
})
13+
.catch(err => {
14+
throw err
15+
});
16+
}
17+
export const useClipboard = ({ useValue, target }: { useValue: boolean, target?: RefObject<HTMLElement>|HTMLElement }) => {
18+
const copy = useRef((blob: Blob | Blob[]) => (
19+
askPermission("clipboard-write")
20+
.then(() => navigator.clipboard.write(
21+
Array.isArray(blob)
22+
? blob.map(el => new ClipboardItem({ [el.type]: el }))
23+
: [new ClipboardItem({ [blob.type]: blob })]
24+
))
25+
.then(() => {
26+
const element = target
27+
? (target as RefObject<HTMLElement>).current
28+
? (target as RefObject<HTMLElement>).current
29+
: target as HTMLElement
30+
: document;
31+
element!.dispatchEvent(new ClipboardEvent("copy", {
32+
clipboardData: new DataTransfer()
33+
}))
34+
})
35+
.catch(err => {
36+
throw err;
37+
})
38+
));
39+
40+
const copyText = useRef((text: string) => (
41+
askPermission("clipboard-write")
42+
.then(() => navigator.clipboard.writeText(text))
43+
.catch(err => {
44+
throw err;
45+
})
46+
));
47+
48+
const paste = useRef(() => (
49+
askPermission("clipboard-read")
50+
.then(() => navigator.clipboard.read())
51+
.then(items => {
52+
const promises = [];
53+
for (const item of items) {
54+
for (let i = 0, size = item.types.length; i < size; i++) {
55+
promises.push(item.getType(item.types[i]));
56+
}
57+
}
58+
return Promise.all(promises);
59+
})
60+
.catch(err => {
61+
throw err;
62+
})
63+
));
64+
65+
const pasteText = useRef(() => (
66+
askPermission("clipboard-read")
67+
.then(() => navigator.clipboard.readText())
68+
.catch(err => {
69+
throw err;
70+
})
71+
));
72+
73+
const value = useSyncExternalStore(
74+
useCallback(notif => {
75+
76+
}, []),
77+
useCallback(async () => (
78+
askPermission("clipboard-read")
79+
.then(()=>pasteText.current)
80+
), [])
81+
);
82+
83+
if (useValue) {
84+
return [
85+
value,
86+
copyText.current,
87+
pasteText.current,
88+
copy.current,
89+
paste.current
90+
]
91+
}
92+
93+
return [
94+
copyText.current,
95+
pasteText.current,
96+
copy.current,
97+
paste.current
98+
]
99+
}

0 commit comments

Comments
 (0)